From 01055d2cfd5e579b02f3dbbf0f89a5d7958d6ab4 Mon Sep 17 00:00:00 2001 From: reindexer-bot <@> Date: Thu, 15 Aug 2024 22:33:41 +0000 Subject: [PATCH] [upd] Update changelog --- .clang-format | 8 +- changelog.md | 16 + clang-tidy/.clang-tidy | 31 - clang-tidy/.clang-tidy-ignore | 10 - clang-tidy/run-clang-tidy-18.py | 429 -- cpp_src/CMakeLists.txt | 10 +- cpp_src/client/coroqueryresults.cc | 46 +- cpp_src/client/coroqueryresults.h | 2 +- cpp_src/client/cororeindexer.cc | 8 +- cpp_src/client/cororeindexer.h | 70 +- cpp_src/client/cororpcclient.cc | 32 +- cpp_src/client/cororpcclient.h | 100 +- cpp_src/client/corotransaction.cc | 16 +- cpp_src/client/internalrdxcontext.h | 4 +- cpp_src/client/item.cc | 18 +- cpp_src/client/item.h | 22 +- cpp_src/client/itemimpl.cc | 18 +- cpp_src/client/itemimpl.h | 28 +- cpp_src/client/queryresults.cc | 50 +- cpp_src/client/reindexer.cc | 8 +- cpp_src/client/reindexer.h | 72 +- cpp_src/client/resultserializer.cc | 4 +- cpp_src/client/rpcclient.cc | 91 +- cpp_src/client/rpcclient.h | 108 +- cpp_src/client/rpcclientmock.cc | 47 +- cpp_src/client/rpcclientmock.h | 32 +- cpp_src/client/synccoroqueryresults.cc | 2 +- cpp_src/client/synccororeindexer.cc | 8 +- cpp_src/client/synccororeindexer.h | 64 +- cpp_src/client/synccororeindexerimpl.cc | 179 +- cpp_src/client/synccororeindexerimpl.h | 100 +- cpp_src/client/transaction.cc | 23 +- .../cmake/modules/RxPrepareInstallFiles.cmake | 2 +- .../cmd/reindexer_server/contrib/Dockerfile | 20 +- .../reindexer_server/contrib/Dockerfile.deb | 12 +- cpp_src/cmd/reindexer_server/main.cc | 2 +- .../test/test_storage_compatibility.sh | 195 + .../cmd/reindexer_tool/commandsexecutor.cc | 145 +- cpp_src/cmd/reindexer_tool/commandsexecutor.h | 2 +- .../cmd/reindexer_tool/commandsprocessor.cc | 26 +- .../cmd/reindexer_tool/commandsprocessor.h | 8 +- cpp_src/cmd/reindexer_tool/iotools.h | 16 +- cpp_src/cmd/reindexer_tool/reindexer_tool.cc | 10 +- .../cmd/reindexer_tool/tableviewscroller.cc | 12 +- cpp_src/core/activity_context.cc | 28 +- cpp_src/core/activity_context.h | 4 +- cpp_src/core/cbinding/reindexer_c.cc | 32 +- cpp_src/core/cbinding/reindexer_c.h | 10 +- cpp_src/core/cbinding/reindexer_ctypes.h | 6 +- cpp_src/core/cbinding/resultserializer.cc | 40 +- cpp_src/core/cjson/baseencoder.cc | 40 +- cpp_src/core/cjson/baseencoder.h | 34 +- cpp_src/core/cjson/cjsonbuilder.cc | 51 +- cpp_src/core/cjson/cjsonbuilder.h | 78 +- cpp_src/core/cjson/cjsondecoder.cc | 28 +- cpp_src/core/cjson/cjsondecoder.h | 72 +- cpp_src/core/cjson/cjsonmodifier.cc | 80 +- cpp_src/core/cjson/cjsonmodifier.h | 42 +- cpp_src/core/cjson/cjsontools.cc | 213 +- cpp_src/core/cjson/cjsontools.h | 43 +- cpp_src/core/cjson/csvbuilder.cc | 34 +- cpp_src/core/cjson/csvbuilder.h | 70 +- cpp_src/core/cjson/ctag.h | 6 +- cpp_src/core/cjson/defaultvaluecoder.cc | 50 +- cpp_src/core/cjson/defaultvaluecoder.h | 20 +- cpp_src/core/cjson/fieldextractor.h | 64 +- cpp_src/core/cjson/jschemachecker.cc | 43 +- cpp_src/core/cjson/jschemachecker.h | 2 +- cpp_src/core/cjson/jsonbuilder.cc | 20 +- cpp_src/core/cjson/jsonbuilder.h | 72 +- cpp_src/core/cjson/jsondecoder.cc | 39 +- cpp_src/core/cjson/jsondecoder.h | 18 +- cpp_src/core/cjson/msgpackbuilder.cc | 32 +- cpp_src/core/cjson/msgpackbuilder.h | 104 +- cpp_src/core/cjson/msgpackdecoder.cc | 18 +- cpp_src/core/cjson/protobufbuilder.h | 8 +- cpp_src/core/cjson/protobufschemabuilder.cc | 32 +- cpp_src/core/cjson/tagslengths.cc | 8 +- cpp_src/core/cjson/tagsmatcher.h | 12 +- cpp_src/core/cjson/tagsmatcherimpl.h | 66 +- cpp_src/core/cjson/tagspath.h | 82 +- cpp_src/core/cjson/tagspathcache.h | 16 +- cpp_src/core/cjson/uuid_recoders.h | 28 +- cpp_src/core/dbconfig.cc | 84 +- cpp_src/core/dbconfig.h | 31 +- cpp_src/core/expressiontree.h | 98 +- cpp_src/core/formatters/jsonstring_fmt.h | 16 + cpp_src/core/formatters/key_string_fmt.h | 24 + cpp_src/core/formatters/lsn_fmt.h | 19 + cpp_src/core/formatters/uuid_fmt.h | 24 + cpp_src/core/ft/areaholder.h | 44 +- cpp_src/core/ft/bm25.h | 4 +- cpp_src/core/ft/config/baseftconfig.cc | 48 +- cpp_src/core/ft/config/ftfastconfig.cc | 4 +- cpp_src/core/ft/config/ftfuzzyconfig.cc | 10 +- cpp_src/core/ft/filters/synonyms.cc | 8 +- cpp_src/core/ft/filters/translit.cc | 16 +- cpp_src/core/ft/filters/translit.h | 4 +- cpp_src/core/ft/ft_fast/dataholder.cc | 8 +- cpp_src/core/ft/ft_fast/dataholder.h | 4 +- cpp_src/core/ft/ft_fast/dataprocessor.cc | 80 +- cpp_src/core/ft/ft_fast/selecter.cc | 103 +- cpp_src/core/ft/ft_fuzzy/advacedpackedvec.h | 2 +- cpp_src/core/ft/ft_fuzzy/baseseacher.cc | 38 +- cpp_src/core/ft/ft_fuzzy/baseseacher.h | 19 +- .../ft_fuzzy/dataholder/basebuildedholder.cc | 6 +- .../ft_fuzzy/dataholder/basebuildedholder.h | 20 +- .../core/ft/ft_fuzzy/dataholder/smardeque.cc | 24 +- .../core/ft/ft_fuzzy/dumper/fulltextdumper.cc | 24 +- cpp_src/core/ft/ft_fuzzy/merger/basemerger.cc | 13 +- cpp_src/core/ft/ft_fuzzy/merger/basemerger.h | 26 +- .../core/ft/ft_fuzzy/prefilter/prefilter.cc | 8 +- cpp_src/core/ft/ft_fuzzy/searchengine.h | 10 +- cpp_src/core/ft/ftdsl.cc | 41 +- cpp_src/core/ft/ftdsl.h | 18 +- cpp_src/core/ft/idrelset.cc | 8 +- cpp_src/core/ft/idrelset.h | 16 +- cpp_src/core/ft/stemmer.h | 16 +- cpp_src/core/ft/stopwords/stop.h | 4 +- cpp_src/core/ft/stopwords/stop_en.cc | 26 +- cpp_src/core/ft/stopwords/stop_ru.cc | 2 +- cpp_src/core/ft/typos.cc | 8 +- cpp_src/core/ft/typos.h | 12 +- cpp_src/core/idset.cc | 8 +- cpp_src/core/idset.h | 34 +- cpp_src/core/idsetcache.h | 26 +- cpp_src/core/index/index.cc | 4 +- cpp_src/core/index/indexordered.cc | 58 +- cpp_src/core/index/indexordered.h | 14 +- cpp_src/core/index/indexstore.cc | 48 +- cpp_src/core/index/indexstore.h | 32 +- cpp_src/core/index/indextext/fastindextext.cc | 102 +- cpp_src/core/index/indextext/fastindextext.h | 4 +- cpp_src/core/index/indextext/fieldsgetter.h | 20 +- .../core/index/indextext/fuzzyindextext.cc | 8 +- cpp_src/core/index/indextext/indextext.cc | 40 +- cpp_src/core/index/indextext/indextext.h | 4 +- cpp_src/core/index/indexunordered.cc | 130 +- cpp_src/core/index/indexunordered.h | 42 +- cpp_src/core/index/keyentry.h | 12 +- cpp_src/core/index/payload_map.h | 168 +- cpp_src/core/index/rtree/greenesplitter.h | 16 +- cpp_src/core/index/rtree/indexrtree.cc | 36 +- cpp_src/core/index/rtree/indexrtree.h | 14 +- cpp_src/core/index/rtree/linearsplitter.h | 8 +- cpp_src/core/index/rtree/quadraticsplitter.h | 4 +- cpp_src/core/index/rtree/rstarsplitter.h | 20 +- cpp_src/core/index/rtree/rtree.h | 104 +- cpp_src/core/index/rtree/splitter.h | 16 +- cpp_src/core/index/string_map.h | 4 +- cpp_src/core/index/ttlindex.cc | 10 +- cpp_src/core/index/ttlindex.h | 10 +- cpp_src/core/index/updatetracker.h | 34 +- cpp_src/core/index/uuid_index.cc | 6 +- cpp_src/core/indexdef.cc | 44 +- cpp_src/core/indexdef.h | 8 +- cpp_src/core/indexopts.cc | 16 +- cpp_src/core/item.cc | 55 +- cpp_src/core/item.h | 50 +- cpp_src/core/itemimpl.cc | 74 +- cpp_src/core/itemimpl.h | 64 +- cpp_src/core/itemmodifier.cc | 146 +- cpp_src/core/itemmodifier.h | 42 +- cpp_src/core/joincache.h | 16 +- cpp_src/core/keyvalue/key_string.h | 42 +- cpp_src/core/keyvalue/p_string.cc | 8 +- cpp_src/core/keyvalue/p_string.h | 82 +- cpp_src/core/keyvalue/relaxed_variant_hash.h | 30 +- cpp_src/core/keyvalue/uuid.h | 5 +- cpp_src/core/keyvalue/variant.cc | 135 +- cpp_src/core/keyvalue/variant.h | 148 +- cpp_src/core/lrucache.cc | 21 +- cpp_src/core/lrucache.h | 30 +- cpp_src/core/lsn.h | 27 +- cpp_src/core/namespace/asyncstorage.cc | 8 +- cpp_src/core/namespace/asyncstorage.h | 6 +- cpp_src/core/namespace/bgnamespacedeleter.h | 2 +- cpp_src/core/namespace/itemsloader.cc | 45 +- cpp_src/core/namespace/namespace.h | 142 +- cpp_src/core/namespace/namespaceimpl.cc | 317 +- cpp_src/core/namespace/namespaceimpl.h | 291 +- cpp_src/core/namespace/namespacestat.cc | 89 +- cpp_src/core/namespace/namespacestat.h | 24 +- cpp_src/core/namespacedef.cc | 12 +- cpp_src/core/namespacedef.h | 20 +- cpp_src/core/nsselecter/aggregator.cc | 142 +- cpp_src/core/nsselecter/aggregator.h | 38 +- cpp_src/core/nsselecter/btreeindexiterator.h | 8 +- .../core/nsselecter/btreeindexiteratorimpl.h | 8 +- .../comparator/comparator_indexed.cc | 2 + .../comparator/comparator_indexed.h | 282 +- .../comparator/comparator_not_indexed.h | 39 +- .../comparator/equalposition_comparator.cc | 26 +- .../equalposition_comparator_impl.h | 52 +- .../nsselecter/comparator/fieldscomparator.cc | 124 +- .../nsselecter/comparator/fieldscomparator.h | 8 +- cpp_src/core/nsselecter/explaincalc.cc | 74 +- cpp_src/core/nsselecter/explaincalc.h | 40 +- cpp_src/core/nsselecter/itemcomparator.cc | 106 +- cpp_src/core/nsselecter/itemcomparator.h | 28 +- cpp_src/core/nsselecter/joinedselector.cc | 148 +- cpp_src/core/nsselecter/joinedselector.h | 94 +- cpp_src/core/nsselecter/nsselecter.cc | 487 +- cpp_src/core/nsselecter/nsselecter.h | 100 +- cpp_src/core/nsselecter/querypreprocessor.cc | 568 ++- cpp_src/core/nsselecter/querypreprocessor.h | 102 +- cpp_src/core/nsselecter/selectiterator.cc | 14 +- cpp_src/core/nsselecter/selectiterator.h | 54 +- .../nsselecter/selectiteratorcontainer.cc | 278 +- .../core/nsselecter/selectiteratorcontainer.h | 72 +- cpp_src/core/nsselecter/sortexpression.cc | 156 +- cpp_src/core/nsselecter/sortingcontext.h | 56 +- cpp_src/core/nsselecter/substitutionhelpers.h | 22 +- cpp_src/core/payload/fieldsset.cc | 4 +- cpp_src/core/payload/fieldsset.h | 161 +- cpp_src/core/payload/payloadfieldtype.cc | 8 +- cpp_src/core/payload/payloadfieldtype.h | 10 +- cpp_src/core/payload/payloadfieldvalue.h | 76 +- cpp_src/core/payload/payloadiface.cc | 354 +- cpp_src/core/payload/payloadiface.h | 185 +- cpp_src/core/payload/payloadtype.cc | 98 +- cpp_src/core/payload/payloadtype.h | 24 +- cpp_src/core/payload/payloadtypeimpl.h | 22 +- cpp_src/core/payload/payloadvalue.cc | 29 +- cpp_src/core/payload/payloadvalue.h | 28 +- cpp_src/core/perfstatcounter.cc | 4 +- cpp_src/core/perfstatcounter.h | 18 +- cpp_src/core/query/dsl/dslencoder.cc | 46 +- cpp_src/core/query/dsl/dslparser.cc | 51 +- cpp_src/core/query/expressionevaluator.cc | 31 +- cpp_src/core/query/expressionevaluator.h | 6 +- cpp_src/core/query/query.cc | 160 +- cpp_src/core/query/query.h | 530 +- cpp_src/core/query/queryentry.cc | 297 +- cpp_src/core/query/queryentry.h | 298 +- cpp_src/core/query/sql/sqlencoder.cc | 164 +- cpp_src/core/query/sql/sqlencoder.h | 22 +- cpp_src/core/query/sql/sqlparser.cc | 283 +- cpp_src/core/query/sql/sqlparser.h | 50 +- cpp_src/core/query/sql/sqlsuggester.cc | 78 +- cpp_src/core/query/sql/sqlsuggester.h | 14 +- .../core/queryresults/aggregationresult.cc | 24 +- cpp_src/core/queryresults/aggregationresult.h | 50 +- cpp_src/core/queryresults/itemref.h | 20 +- cpp_src/core/queryresults/joinresults.cc | 24 +- cpp_src/core/queryresults/joinresults.h | 4 +- cpp_src/core/queryresults/queryresults.cc | 170 +- cpp_src/core/queryresults/queryresults.h | 92 +- cpp_src/core/queryresults/tableviewbuilder.cc | 60 +- cpp_src/core/querystat.cc | 12 +- cpp_src/core/querystat.h | 16 +- cpp_src/core/rdxcontext.cc | 4 +- cpp_src/core/rdxcontext.h | 12 +- cpp_src/core/reindexer.cc | 8 +- cpp_src/core/reindexer.h | 90 +- cpp_src/core/reindexer_impl/reindexerimpl.cc | 162 +- cpp_src/core/reindexer_impl/reindexerimpl.h | 136 +- cpp_src/core/reindexer_impl/rx_selector.cc | 40 +- cpp_src/core/reindexer_impl/rx_selector.h | 46 +- cpp_src/core/rollback.h | 8 +- cpp_src/core/schema.cc | 12 +- cpp_src/core/selectfunc/ctx/ftctx.cc | 34 +- cpp_src/core/selectfunc/ctx/ftctx.h | 10 +- .../core/selectfunc/functions/highlight.cc | 20 +- cpp_src/core/selectfunc/functions/highlight.h | 2 +- cpp_src/core/selectfunc/functions/snippet.cc | 46 +- cpp_src/core/selectfunc/functions/snippet.h | 18 +- .../core/selectfunc/nsselectfuncinterface.cc | 2 +- cpp_src/core/selectfunc/selectfunc.cc | 72 +- cpp_src/core/selectfunc/selectfuncparser.cc | 64 +- cpp_src/core/selectfunc/selectfuncparser.h | 10 +- cpp_src/core/selectkeyresult.h | 88 +- cpp_src/core/sortingprioritiestable.cc | 25 +- cpp_src/core/storage/leveldblogger.cc | 2 +- cpp_src/core/storage/leveldbstorage.cc | 52 +- cpp_src/core/storage/rocksdbstorage.cc | 52 +- cpp_src/core/transaction.cc | 73 +- cpp_src/core/transaction.h | 34 +- cpp_src/core/transactionimpl.cc | 31 +- cpp_src/core/transactionimpl.h | 36 +- cpp_src/core/type_consts_helpers.cc | 4 +- cpp_src/core/type_formats.h | 13 + cpp_src/coroutine/channel.h | 14 +- cpp_src/coroutine/coroutine.cc | 40 +- cpp_src/coroutine/coroutine.h | 22 +- cpp_src/debug/allocdebug.cc | 38 +- cpp_src/debug/backtrace.cc | 76 +- cpp_src/debug/backtrace.h | 12 +- cpp_src/debug/crashqueryreporter.cc | 36 +- cpp_src/debug/crashqueryreporter.h | 10 +- cpp_src/debug/resolver.cc | 51 +- cpp_src/debug/resolver.h | 16 +- cpp_src/debug/terminate_handler.cpp | 8 +- cpp_src/estl/atomic_unique_ptr.h | 8 +- cpp_src/estl/cbuf.h | 62 +- cpp_src/estl/chunk.h | 20 +- cpp_src/estl/chunk_buf.h | 9 +- cpp_src/estl/contexted_locks.h | 36 +- cpp_src/estl/cow.h | 14 +- cpp_src/estl/fast_hash_traits.h | 14 +- cpp_src/estl/flat_str_map.h | 68 +- cpp_src/estl/h_vector.h | 58 +- cpp_src/estl/intrusive_ptr.h | 134 +- cpp_src/estl/multihash_set.h | 4 +- cpp_src/estl/mutex.h | 7 +- cpp_src/estl/packed_vector.h | 8 +- cpp_src/estl/protobufparser.h | 4 +- cpp_src/estl/shared_mutex.h | 21 +- cpp_src/estl/smart_lock.h | 5 +- cpp_src/estl/span.h | 8 +- cpp_src/estl/suffix_map.h | 83 +- cpp_src/estl/tokenizer.cc | 15 +- cpp_src/estl/tokenizer.h | 16 +- cpp_src/estl/trivial_reverse_iterator.h | 8 +- cpp_src/gtests/bench/fixtures/aggregation.cc | 32 +- cpp_src/gtests/bench/fixtures/api_encdec.cc | 64 +- .../gtests/bench/fixtures/api_tv_composite.cc | 128 +- .../gtests/bench/fixtures/api_tv_simple.cc | 348 +- .../fixtures/api_tv_simple_comparators.cc | 148 +- .../bench/fixtures/api_tv_simple_sparse.cc | 92 +- .../bench/fixtures/api_tv_simple_sparse.h | 2 +- cpp_src/gtests/bench/fixtures/base_fixture.cc | 24 +- cpp_src/gtests/bench/fixtures/ft_fixture.cc | 192 +- cpp_src/gtests/bench/fixtures/ft_fixture.h | 20 +- .../gtests/bench/fixtures/ft_merge_limit.cc | 12 +- cpp_src/gtests/bench/fixtures/geometry.cc | 32 +- cpp_src/gtests/bench/fixtures/join_items.cc | 8 +- cpp_src/gtests/bench/ft_bench.cc | 8 +- cpp_src/gtests/bench/reindexer_bench.cc | 40 +- cpp_src/gtests/bench/tools/helpers.cc | 10 +- cpp_src/gtests/bench/tools/helpers.h | 16 +- cpp_src/gtests/bench/tools/reporter.h | 4 +- cpp_src/gtests/bench/tools/sequence.h | 4 +- cpp_src/gtests/tests/API/api.cc | 4 +- cpp_src/gtests/tests/API/base_tests.cc | 40 +- .../gtests/tests/fixtures/btree_idsets_api.h | 12 +- .../gtests/tests/fixtures/equalpositionapi.h | 4 +- cpp_src/gtests/tests/fixtures/ft_api.cc | 4 +- .../gtests/tests/fixtures/fuzzing/index.cc | 68 +- cpp_src/gtests/tests/fixtures/fuzzing/ns.cc | 20 +- .../tests/fixtures/fuzzing/ns_scheme.cc | 64 +- .../tests/fixtures/fuzzing/query_generator.cc | 4 +- .../fixtures/fuzzing/random_generator.cc | 24 +- .../tests/fixtures/fuzzing/random_generator.h | 12 +- cpp_src/gtests/tests/fixtures/get_pk_api.h | 24 +- .../gtests/tests/fixtures/grpcclient_api.h | 2 +- .../tests/fixtures/item_move_semantics_api.h | 8 +- .../gtests/tests/fixtures/join_selects_api.h | 22 +- cpp_src/gtests/tests/fixtures/ns_api.h | 7 +- cpp_src/gtests/tests/fixtures/queries_api.cc | 197 +- cpp_src/gtests/tests/fixtures/queries_api.h | 42 +- .../gtests/tests/fixtures/queries_verifier.h | 101 +- cpp_src/gtests/tests/fixtures/reindexer_api.h | 18 +- .../gtests/tests/fixtures/reindexertestapi.h | 32 +- .../gtests/tests/fixtures/replication_api.cc | 28 +- .../tests/fixtures/replication_load_api.h | 24 +- cpp_src/gtests/tests/fixtures/rpcclient_api.h | 2 +- .../tests/fixtures/runtime_indexes_api.h | 4 +- .../tests/fixtures/selector_plan_test.h | 8 +- .../gtests/tests/fixtures/servercontrol.cc | 11 +- .../gtests/tests/fixtures/systemhelpers.cc | 8 +- cpp_src/gtests/tests/fixtures/test_helpers.h | 8 +- cpp_src/gtests/tests/fixtures/ttl_index_api.h | 4 +- cpp_src/gtests/tests/fuzzing/fuzzing.cc | 12 +- cpp_src/gtests/tests/mocks/rpcserver_fake.cc | 22 +- cpp_src/gtests/tests/mocks/rpcserver_fake.h | 18 +- .../gtests/tests/unit/btree_idsets_tests.cc | 10 +- .../gtests/tests/unit/csv2jsonconverter.cc | 4 +- cpp_src/gtests/tests/unit/csv2jsonconverter.h | 2 +- .../gtests/tests/unit/equalposition_tests.cc | 14 +- cpp_src/gtests/tests/unit/ft/ft_generic.cc | 14 +- cpp_src/gtests/tests/unit/index_tuple_test.cc | 155 +- cpp_src/gtests/tests/unit/join_test.cc | 38 +- cpp_src/gtests/tests/unit/namespace_test.cc | 286 +- cpp_src/gtests/tests/unit/protobuf_test.cc | 4 +- cpp_src/gtests/tests/unit/queries_test.cc | 30 +- .../unit/query_aggregate_strict_mode_test.h | 10 +- .../unit/replication_master_master_test.cc | 33 +- cpp_src/gtests/tests/unit/replication_test.cc | 20 +- cpp_src/gtests/tests/unit/rpcclient_test.cc | 14 +- cpp_src/gtests/tests/unit/rtree_test.cc | 16 +- .../gtests/tests/unit/selector_plan_test.cc | 8 +- cpp_src/gtests/tests/unit/tolal_lru_cache.cc | 2 +- cpp_src/gtests/tests/unit/ttl_index_api.cc | 4 +- cpp_src/gtests/tests/unit/uuid.cc | 36 +- .../gtests/tests/unit/value_by_json_path.cc | 4 +- cpp_src/gtests/tools.h | 4 +- cpp_src/net/connectinstatscollector.h | 4 +- cpp_src/net/connection.cc | 48 +- cpp_src/net/connection.h | 14 +- cpp_src/net/cproto/args.cc | 10 +- cpp_src/net/cproto/args.h | 6 +- cpp_src/net/cproto/clientconnection.cc | 84 +- cpp_src/net/cproto/clientconnection.h | 60 +- cpp_src/net/cproto/coroclientconnection.cc | 44 +- cpp_src/net/cproto/coroclientconnection.h | 58 +- cpp_src/net/cproto/dispatcher.h | 68 +- cpp_src/net/cproto/serverconnection.cc | 44 +- cpp_src/net/cproto/serverconnection.h | 34 +- cpp_src/net/ev/ev.cc | 89 +- cpp_src/net/ev/ev.h | 136 +- cpp_src/net/http/router.cc | 59 +- cpp_src/net/http/router.h | 104 +- cpp_src/net/http/serverconnection.cc | 74 +- cpp_src/net/http/serverconnection.h | 36 +- cpp_src/net/iserverconnection.h | 8 +- cpp_src/net/listener.cc | 68 +- cpp_src/net/listener.h | 58 +- cpp_src/net/manualconnection.cc | 72 +- cpp_src/net/manualconnection.h | 49 +- cpp_src/net/socket.cc | 30 +- cpp_src/net/socket.h | 18 +- cpp_src/readme.md | 15 + cpp_src/replicator/replicator.cc | 335 +- cpp_src/replicator/replicator.h | 64 +- cpp_src/replicator/updatesobserver.cc | 58 +- cpp_src/replicator/updatesobserver.h | 32 +- cpp_src/replicator/walrecord.cc | 28 +- cpp_src/replicator/walrecord.h | 13 +- cpp_src/replicator/walselecter.cc | 32 +- cpp_src/replicator/walselecter.h | 8 +- cpp_src/replicator/waltracker.cc | 26 +- cpp_src/replicator/waltracker.h | 22 +- cpp_src/server/cbinding/server_c.cc | 4 +- cpp_src/server/config.cc | 180 +- cpp_src/server/dbmanager.cc | 61 +- cpp_src/server/dbmanager.h | 27 +- cpp_src/server/grpc/reindexerservice.cc | 48 +- cpp_src/server/httpserver.cc | 328 +- cpp_src/server/httpserver.h | 162 +- cpp_src/server/loggerwrapper.h | 68 +- cpp_src/server/pidfile.h | 20 +- cpp_src/server/pprof/gperf_profiler.cc | 18 +- cpp_src/server/pprof/gperf_profiler.h | 6 +- cpp_src/server/pprof/pprof.cc | 40 +- cpp_src/server/pprof/pprof.h | 14 +- cpp_src/server/resources_wrapper.cc | 4 +- cpp_src/server/rpcqrwatcher.h | 7 +- cpp_src/server/rpcserver.cc | 210 +- cpp_src/server/rpcserver.h | 112 +- cpp_src/server/rpcupdatespusher.cc | 6 +- cpp_src/server/rpcupdatespusher.h | 12 +- cpp_src/server/server.cc | 10 +- cpp_src/server/server.h | 1 + cpp_src/server/serverimpl.cc | 88 +- cpp_src/server/serverimpl.h | 3 +- cpp_src/server/statscollect/prometheus.h | 54 +- cpp_src/server/winservice.cc | 39 +- cpp_src/server/winservice.h | 6 +- .../tools/alloc_ext/je_malloc_extension.cc | 10 +- cpp_src/tools/alloc_ext/je_malloc_extension.h | 4 +- .../tools/alloc_ext/tc_malloc_extension.cc | 4 +- cpp_src/tools/alloc_ext/tc_malloc_extension.h | 2 +- cpp_src/tools/alloc_ext/tc_malloc_hook.cc | 4 +- cpp_src/tools/assertrx.cc | 6 +- cpp_src/tools/assertrx.h | 4 +- cpp_src/tools/customlocal.cc | 4 +- cpp_src/tools/errors.h | 30 +- cpp_src/tools/frozen_str_tools.h | 4 +- cpp_src/tools/fsops.cc | 104 +- cpp_src/tools/fsops.h | 32 +- cpp_src/tools/json2kv.cc | 6 +- cpp_src/tools/jsonstring.h | 12 +- cpp_src/tools/jsontools.cc | 34 +- cpp_src/tools/jsontools.h | 6 +- cpp_src/tools/logger.cc | 19 +- cpp_src/tools/logger.h | 50 +- cpp_src/tools/md5crypt.cc | 12 +- cpp_src/tools/md5crypt.h | 4 +- cpp_src/tools/semversion.h | 10 +- cpp_src/tools/serializer.cc | 24 +- cpp_src/tools/serializer.h | 132 +- cpp_src/tools/string_regexp_functions.cc | 56 +- cpp_src/tools/stringstools.cc | 220 +- cpp_src/tools/stringstools.h | 12 +- cpp_src/tools/tcmallocheapwathcher.cc | 10 +- cpp_src/tools/tcmallocheapwathcher.h | 16 +- cpp_src/tools/terminalutils.cc | 4 +- cpp_src/tools/varint.h | 55 +- cpp_src/vendor/fmt/args.h | 228 + cpp_src/vendor/fmt/base.h | 3077 ++++++++++++ cpp_src/vendor/fmt/chrono.h | 2432 +++++++++ cpp_src/vendor/fmt/color.h | 612 +++ cpp_src/vendor/fmt/compile.h | 529 ++ cpp_src/vendor/fmt/core.h | 5 + cpp_src/vendor/fmt/format-inl.h | 1928 +++++++ cpp_src/vendor/fmt/format.cc | 43 + cpp_src/vendor/fmt/format.h | 4449 +++++++++++++++++ cpp_src/vendor/fmt/os.cc | 403 ++ cpp_src/vendor/fmt/os.h | 439 ++ cpp_src/vendor/fmt/ostream.h | 211 + cpp_src/vendor/fmt/printf.h | 656 +++ cpp_src/vendor/fmt/ranges.h | 882 ++++ cpp_src/vendor/fmt/std.h | 699 +++ cpp_src/vendor/fmt/xchar.h | 322 ++ cpp_src/vendor/gason/gason.cc | 152 +- cpp_src/vendor/gason/gason.h | 120 +- cpp_src/vendor/msgpack/msgpackparser.h | 21 +- cpp_src/vendor/spdlog/async.h | 100 + cpp_src/vendor/spdlog/async_logger-inl.h | 86 + cpp_src/vendor/spdlog/async_logger.h | 105 +- cpp_src/vendor/spdlog/cfg/argv.h | 40 + cpp_src/vendor/spdlog/cfg/env.h | 36 + cpp_src/vendor/spdlog/cfg/helpers-inl.h | 107 + cpp_src/vendor/spdlog/cfg/helpers.h | 29 + cpp_src/vendor/spdlog/common-inl.h | 68 + cpp_src/vendor/spdlog/common.h | 451 +- .../vendor/spdlog/details/async_log_helper.h | 326 -- .../vendor/spdlog/details/async_logger_impl.h | 107 - .../vendor/spdlog/details/backtracer-inl.h | 63 + cpp_src/vendor/spdlog/details/backtracer.h | 45 + cpp_src/vendor/spdlog/details/circular_q.h | 115 + .../vendor/spdlog/details/console_globals.h | 28 + .../vendor/spdlog/details/file_helper-inl.h | 152 + cpp_src/vendor/spdlog/details/file_helper.h | 154 +- cpp_src/vendor/spdlog/details/fmt_helper.h | 141 + cpp_src/vendor/spdlog/details/log_msg-inl.h | 44 + cpp_src/vendor/spdlog/details/log_msg.h | 68 +- .../spdlog/details/log_msg_buffer-inl.h | 54 + .../vendor/spdlog/details/log_msg_buffer.h | 32 + cpp_src/vendor/spdlog/details/logger_impl.h | 373 -- .../vendor/spdlog/details/mpmc_blocking_q.h | 177 + .../vendor/spdlog/details/mpmc_bounded_q.h | 175 - cpp_src/vendor/spdlog/details/null_mutex.h | 47 +- cpp_src/vendor/spdlog/details/os-inl.h | 594 +++ cpp_src/vendor/spdlog/details/os.h | 530 +- .../spdlog/details/pattern_formatter_impl.h | 672 --- .../spdlog/details/periodic_worker-inl.h | 26 + .../vendor/spdlog/details/periodic_worker.h | 58 + cpp_src/vendor/spdlog/details/registry-inl.h | 261 + cpp_src/vendor/spdlog/details/registry.h | 264 +- cpp_src/vendor/spdlog/details/spdlog_impl.h | 265 - .../spdlog/details/synchronous_factory.h | 22 + .../spdlog/details/tcp_client-windows.h | 135 + cpp_src/vendor/spdlog/details/tcp_client.h | 127 + .../vendor/spdlog/details/thread_pool-inl.h | 142 + cpp_src/vendor/spdlog/details/thread_pool.h | 128 + .../spdlog/details/udp_client-windows.h | 98 + cpp_src/vendor/spdlog/details/udp_client.h | 81 + .../vendor/spdlog/details/windows_include.h | 11 + cpp_src/vendor/spdlog/fmt/bin_to_hex.h | 224 + cpp_src/vendor/spdlog/fmt/bundled/LICENSE.rst | 23 - cpp_src/vendor/spdlog/fmt/bundled/format.cc | 431 -- cpp_src/vendor/spdlog/fmt/bundled/format.h | 3972 --------------- cpp_src/vendor/spdlog/fmt/bundled/ostream.cc | 35 - cpp_src/vendor/spdlog/fmt/bundled/ostream.h | 117 - cpp_src/vendor/spdlog/fmt/bundled/posix.cc | 241 - cpp_src/vendor/spdlog/fmt/bundled/posix.h | 424 -- cpp_src/vendor/spdlog/fmt/bundled/printf.cc | 32 - cpp_src/vendor/spdlog/fmt/bundled/printf.h | 712 --- cpp_src/vendor/spdlog/fmt/bundled/time.h | 183 - cpp_src/vendor/spdlog/fmt/chrono.h | 23 + cpp_src/vendor/spdlog/fmt/compile.h | 23 + cpp_src/vendor/spdlog/fmt/fmt.h | 42 +- cpp_src/vendor/spdlog/fmt/ostr.h | 24 +- cpp_src/vendor/spdlog/fmt/ranges.h | 23 + cpp_src/vendor/spdlog/fmt/std.h | 24 + cpp_src/vendor/spdlog/fmt/xchar.h | 23 + cpp_src/vendor/spdlog/formatter.h | 46 +- cpp_src/vendor/spdlog/fwd.h | 18 + cpp_src/vendor/spdlog/logger-inl.h | 200 + cpp_src/vendor/spdlog/logger.h | 429 +- cpp_src/vendor/spdlog/mdc.h | 46 + cpp_src/vendor/spdlog/pattern_formatter-inl.h | 1324 +++++ cpp_src/vendor/spdlog/pattern_formatter.h | 118 + cpp_src/vendor/spdlog/sinks/android_sink.h | 164 +- .../vendor/spdlog/sinks/ansicolor_sink-inl.h | 137 + cpp_src/vendor/spdlog/sinks/ansicolor_sink.h | 198 +- cpp_src/vendor/spdlog/sinks/base_sink-inl.h | 59 + cpp_src/vendor/spdlog/sinks/base_sink.h | 72 +- .../vendor/spdlog/sinks/basic_file_sink-inl.h | 42 + cpp_src/vendor/spdlog/sinks/basic_file_sink.h | 65 + cpp_src/vendor/spdlog/sinks/callback_sink.h | 56 + cpp_src/vendor/spdlog/sinks/daily_file_sink.h | 252 + cpp_src/vendor/spdlog/sinks/dist_sink.h | 95 +- cpp_src/vendor/spdlog/sinks/dup_filter_sink.h | 92 + cpp_src/vendor/spdlog/sinks/file_sinks.h | 315 -- .../vendor/spdlog/sinks/hourly_file_sink.h | 191 + cpp_src/vendor/spdlog/sinks/kafka_sink.h | 119 + cpp_src/vendor/spdlog/sinks/mongo_sink.h | 108 + cpp_src/vendor/spdlog/sinks/msvc_sink.h | 73 +- cpp_src/vendor/spdlog/sinks/null_sink.h | 42 +- cpp_src/vendor/spdlog/sinks/ostream_sink.h | 54 +- cpp_src/vendor/spdlog/sinks/qt_sinks.h | 304 ++ .../vendor/spdlog/sinks/reopen_file_sink.h | 100 + cpp_src/vendor/spdlog/sinks/ringbuffer_sink.h | 67 + .../spdlog/sinks/rotating_file_sink-inl.h | 144 + .../vendor/spdlog/sinks/rotating_file_sink.h | 89 + cpp_src/vendor/spdlog/sinks/sink-inl.h | 22 + cpp_src/vendor/spdlog/sinks/sink.h | 50 +- .../spdlog/sinks/stdout_color_sinks-inl.h | 38 + .../vendor/spdlog/sinks/stdout_color_sinks.h | 49 + .../vendor/spdlog/sinks/stdout_sinks-inl.h | 126 + cpp_src/vendor/spdlog/sinks/stdout_sinks.h | 125 +- cpp_src/vendor/spdlog/sinks/syslog_sink.h | 135 +- cpp_src/vendor/spdlog/sinks/systemd_sink.h | 121 + cpp_src/vendor/spdlog/sinks/tcp_sink.h | 75 + cpp_src/vendor/spdlog/sinks/udp_sink.h | 69 + .../vendor/spdlog/sinks/win_eventlog_sink.h | 260 + .../vendor/spdlog/sinks/wincolor_sink-inl.h | 163 + cpp_src/vendor/spdlog/sinks/wincolor_sink.h | 155 +- cpp_src/vendor/spdlog/sinks/windebug_sink.h | 29 - cpp_src/vendor/spdlog/spdlog-inl.h | 92 + cpp_src/vendor/spdlog/spdlog.h | 426 +- cpp_src/vendor/spdlog/stopwatch.h | 67 + cpp_src/vendor/spdlog/tweakme.h | 125 +- cpp_src/vendor/spdlog/version.h | 11 + readme.md | 5 + 608 files changed, 41129 insertions(+), 19968 deletions(-) delete mode 100644 clang-tidy/.clang-tidy delete mode 100644 clang-tidy/.clang-tidy-ignore delete mode 100755 clang-tidy/run-clang-tidy-18.py create mode 100755 cpp_src/cmd/reindexer_server/test/test_storage_compatibility.sh create mode 100644 cpp_src/core/formatters/jsonstring_fmt.h create mode 100644 cpp_src/core/formatters/key_string_fmt.h create mode 100644 cpp_src/core/formatters/lsn_fmt.h create mode 100644 cpp_src/core/formatters/uuid_fmt.h create mode 100644 cpp_src/core/type_formats.h create mode 100644 cpp_src/vendor/fmt/args.h create mode 100644 cpp_src/vendor/fmt/base.h create mode 100644 cpp_src/vendor/fmt/chrono.h create mode 100644 cpp_src/vendor/fmt/color.h create mode 100644 cpp_src/vendor/fmt/compile.h create mode 100644 cpp_src/vendor/fmt/core.h create mode 100644 cpp_src/vendor/fmt/format-inl.h create mode 100644 cpp_src/vendor/fmt/format.cc create mode 100644 cpp_src/vendor/fmt/format.h create mode 100644 cpp_src/vendor/fmt/os.cc create mode 100644 cpp_src/vendor/fmt/os.h create mode 100644 cpp_src/vendor/fmt/ostream.h create mode 100644 cpp_src/vendor/fmt/printf.h create mode 100644 cpp_src/vendor/fmt/ranges.h create mode 100644 cpp_src/vendor/fmt/std.h create mode 100644 cpp_src/vendor/fmt/xchar.h create mode 100644 cpp_src/vendor/spdlog/async.h create mode 100644 cpp_src/vendor/spdlog/async_logger-inl.h create mode 100644 cpp_src/vendor/spdlog/cfg/argv.h create mode 100644 cpp_src/vendor/spdlog/cfg/env.h create mode 100644 cpp_src/vendor/spdlog/cfg/helpers-inl.h create mode 100644 cpp_src/vendor/spdlog/cfg/helpers.h create mode 100644 cpp_src/vendor/spdlog/common-inl.h delete mode 100644 cpp_src/vendor/spdlog/details/async_log_helper.h delete mode 100644 cpp_src/vendor/spdlog/details/async_logger_impl.h create mode 100644 cpp_src/vendor/spdlog/details/backtracer-inl.h create mode 100644 cpp_src/vendor/spdlog/details/backtracer.h create mode 100644 cpp_src/vendor/spdlog/details/circular_q.h create mode 100644 cpp_src/vendor/spdlog/details/console_globals.h create mode 100644 cpp_src/vendor/spdlog/details/file_helper-inl.h create mode 100644 cpp_src/vendor/spdlog/details/fmt_helper.h create mode 100644 cpp_src/vendor/spdlog/details/log_msg-inl.h create mode 100644 cpp_src/vendor/spdlog/details/log_msg_buffer-inl.h create mode 100644 cpp_src/vendor/spdlog/details/log_msg_buffer.h delete mode 100644 cpp_src/vendor/spdlog/details/logger_impl.h create mode 100644 cpp_src/vendor/spdlog/details/mpmc_blocking_q.h delete mode 100644 cpp_src/vendor/spdlog/details/mpmc_bounded_q.h create mode 100644 cpp_src/vendor/spdlog/details/os-inl.h delete mode 100644 cpp_src/vendor/spdlog/details/pattern_formatter_impl.h create mode 100644 cpp_src/vendor/spdlog/details/periodic_worker-inl.h create mode 100644 cpp_src/vendor/spdlog/details/periodic_worker.h create mode 100644 cpp_src/vendor/spdlog/details/registry-inl.h delete mode 100644 cpp_src/vendor/spdlog/details/spdlog_impl.h create mode 100644 cpp_src/vendor/spdlog/details/synchronous_factory.h create mode 100644 cpp_src/vendor/spdlog/details/tcp_client-windows.h create mode 100644 cpp_src/vendor/spdlog/details/tcp_client.h create mode 100644 cpp_src/vendor/spdlog/details/thread_pool-inl.h create mode 100644 cpp_src/vendor/spdlog/details/thread_pool.h create mode 100644 cpp_src/vendor/spdlog/details/udp_client-windows.h create mode 100644 cpp_src/vendor/spdlog/details/udp_client.h create mode 100644 cpp_src/vendor/spdlog/details/windows_include.h create mode 100644 cpp_src/vendor/spdlog/fmt/bin_to_hex.h delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/LICENSE.rst delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/format.cc delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/format.h delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/ostream.cc delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/ostream.h delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/posix.cc delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/posix.h delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/printf.cc delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/printf.h delete mode 100644 cpp_src/vendor/spdlog/fmt/bundled/time.h create mode 100644 cpp_src/vendor/spdlog/fmt/chrono.h create mode 100644 cpp_src/vendor/spdlog/fmt/compile.h create mode 100644 cpp_src/vendor/spdlog/fmt/ranges.h create mode 100644 cpp_src/vendor/spdlog/fmt/std.h create mode 100644 cpp_src/vendor/spdlog/fmt/xchar.h create mode 100644 cpp_src/vendor/spdlog/fwd.h create mode 100644 cpp_src/vendor/spdlog/logger-inl.h create mode 100644 cpp_src/vendor/spdlog/mdc.h create mode 100644 cpp_src/vendor/spdlog/pattern_formatter-inl.h create mode 100644 cpp_src/vendor/spdlog/pattern_formatter.h create mode 100644 cpp_src/vendor/spdlog/sinks/ansicolor_sink-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/base_sink-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/basic_file_sink-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/basic_file_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/callback_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/daily_file_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/dup_filter_sink.h delete mode 100644 cpp_src/vendor/spdlog/sinks/file_sinks.h create mode 100644 cpp_src/vendor/spdlog/sinks/hourly_file_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/kafka_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/mongo_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/qt_sinks.h create mode 100644 cpp_src/vendor/spdlog/sinks/reopen_file_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/ringbuffer_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/rotating_file_sink-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/rotating_file_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/sink-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/stdout_color_sinks-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/stdout_color_sinks.h create mode 100644 cpp_src/vendor/spdlog/sinks/stdout_sinks-inl.h create mode 100644 cpp_src/vendor/spdlog/sinks/systemd_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/tcp_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/udp_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/win_eventlog_sink.h create mode 100644 cpp_src/vendor/spdlog/sinks/wincolor_sink-inl.h delete mode 100644 cpp_src/vendor/spdlog/sinks/windebug_sink.h create mode 100644 cpp_src/vendor/spdlog/spdlog-inl.h create mode 100644 cpp_src/vendor/spdlog/stopwatch.h create mode 100644 cpp_src/vendor/spdlog/version.h diff --git a/.clang-format b/.clang-format index 130ce61da..e7fa4fb1f 100644 --- a/.clang-format +++ b/.clang-format @@ -99,7 +99,7 @@ CompactNamespaces: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true -DerivePointerAlignment: true +DerivePointerAlignment: false DisableFormat: false EmptyLineAfterAccessModifier: Never EmptyLineBeforeAccessModifier: LogicalBlock @@ -136,7 +136,7 @@ IndentPPDirectives: None IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false -InsertBraces: false +InsertBraces: true InsertNewlineAtEOF: false InsertTrailingCommas: None IntegerLiteralSeparator: @@ -175,12 +175,12 @@ PenaltyIndentedWhitespace: 0 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left PPIndentWidth: -1 -QualifierAlignment: Leave +QualifierAlignment: Left ReferenceAlignment: Pointer ReflowComments: true RemoveBracesLLVM: false RemoveParentheses: Leave -RemoveSemicolon: false +RemoveSemicolon: true RequiresClausePosition: OwnLine RequiresExpressionIndentation: OuterScope SeparateDefinitionBlocks: Leave diff --git a/changelog.md b/changelog.md index 679ac8167..cafb3dd2c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,19 @@ +# Version 3.28.0 (XX.08.2024) +## Core +- [fea] Updated [logging library](https://github.com/gabime/spdlog) to v1.14.1 and [formatting library](https://github.com/fmtlib/fmt) to v11.0.2 +- [fea] Optimized log level checks to avoid excessive serializtion in core logs +- [fea] Added support for [array_remove](readme.md#remove-array-elements-by-values) with scalar values in SQL +- [fea] Added support for [array_remove](readme.md#remove-array-elements-by-values) with non-integral values +- [fix] Disabled default values creation for object array indexes to avoid Go/Java connectors incompatibility +- [fix] Fixed sorted JOIN-subqueries over optimized `tree`-indexes with unordered conditions +- [fix] Fixed `LIMIT`/`OFFSET` stability for fulltext [MERGE-queries](fulltext.md#merging-queries-results) + +## Reindexer server +- [fix] Fixed [docker's](https://hub.docker.com/r/reindexer/reindexer) SEGFAULT on M1 CPU + +## Reindexer tool +- [fix] Fixed possible stucking in interactive mode on Windows + # Version 3.27.0 (09.07.2024) ## Core - [fea] Decreased heap allocations count in general selection pipeline diff --git a/clang-tidy/.clang-tidy b/clang-tidy/.clang-tidy deleted file mode 100644 index 063df74f1..000000000 --- a/clang-tidy/.clang-tidy +++ /dev/null @@ -1,31 +0,0 @@ -Checks: 'clang-diagnostic-*, - clang-analyzer-*, - performance-*, - bugprone-*, - -bugprone-exception-escape, - -bugprone-branch-clone, - -bugprone-easily-swappable-parameters, - -bugprone-macro-parentheses, - -bugprone-signed-char-misuse, - -bugprone-narrowing-conversions, - -bugprone-reserved-identifier, - -bugprone-implicit-widening-of-multiplication-result, - -bugprone-assignment-in-if-condition, - -bugprone-parent-virtual-call, - -bugprone-integer-division, - -bugprone-unhandled-self-assignment, - -bugprone-inc-dec-in-conditions, - -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, - -performance-no-int-to-ptr, - -performance-enum-size, - -performance-avoid-endl' -# clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling - too many unnecessary warning in vendored code -# performance-no-int-to-ptr - consider how to fix this -# bugprone-macro-parentheses - consider fixing -WarningsAsErrors: '*' -HeaderFilterRegex: '.*(?= 4.0.0 are given under - # the top level key 'Diagnostics' in the output yaml files - mergekey = "Diagnostics" - merged=[] - for replacefile in glob.iglob(os.path.join(tmpdir, '*.yaml')): - content = yaml.safe_load(open(replacefile, 'r')) - if not content: - continue # Skip empty files. - merged.extend(content.get(mergekey, [])) - - if merged: - # MainSourceFile: The key is required by the definition inside - # include/clang/Tooling/ReplacementsYaml.h, but the value - # is actually never used inside clang-apply-replacements, - # so we set it to '' here. - output = {'MainSourceFile': '', mergekey: merged} - with open(mergefile, 'w') as out: - yaml.safe_dump(output, out) - else: - # Empty the file: - open(mergefile, 'w').close() - - -def find_binary(arg, name, build_path): - """Get the path for a binary or exit""" - if arg: - if shutil.which(arg): - return arg - else: - raise SystemExit( - "error: passed binary '{}' was not found or is not executable" - .format(arg)) - - built_path = os.path.join(build_path, "bin", name) - binary = shutil.which(name) or shutil.which(built_path) - if binary: - return binary - else: - raise SystemExit( - "error: failed to find {} in $PATH or at {}" - .format(name, built_path)) - - -def apply_fixes(args, clang_apply_replacements_binary, tmpdir): - """Calls clang-apply-fixes on a given directory.""" - invocation = [clang_apply_replacements_binary] - invocation.append('-ignore-insert-conflict') - if args.format: - invocation.append('-format') - if args.style: - invocation.append('-style=' + args.style) - invocation.append(tmpdir) - subprocess.call(invocation) - - -def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, - failed_files): - """Takes filenames out of queue and runs clang-tidy on them.""" - while True: - name = queue.get() - invocation = get_tidy_invocation(name, clang_tidy_binary, args.checks, - tmpdir, build_path, args.header_filter, - args.allow_enabling_alpha_checkers, - args.extra_arg, args.extra_arg_before, - args.quiet, args.config_file, args.config, - args.line_filter, args.use_color, - args.plugins) - - proc = subprocess.Popen(invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - output, err = proc.communicate() - if proc.returncode != 0: - if proc.returncode < 0: - msg = "%s: terminated by signal %d\n" % (name, -proc.returncode) - err += msg.encode('utf-8') - failed_files.append(name) - with lock: - sys.stdout.write(' '.join(invocation) + '\n' + output.decode('utf-8')) - if len(err) > 0: - sys.stdout.flush() - sys.stderr.write(err.decode('utf-8')) - queue.task_done() - - -def main(): - parser = argparse.ArgumentParser(description='Runs clang-tidy over all files ' - 'in a compilation database. Requires ' - 'clang-tidy and clang-apply-replacements in ' - '$PATH or in your build directory.') - parser.add_argument('-allow-enabling-alpha-checkers', - action='store_true', help='allow alpha checkers from ' - 'clang-analyzer.') - parser.add_argument('-clang-tidy-binary', metavar='PATH', - default='clang-tidy-18', - help='path to clang-tidy binary') - parser.add_argument('-clang-apply-replacements-binary', metavar='PATH', - default='clang-apply-replacements-18', - help='path to clang-apply-replacements binary') - parser.add_argument('-checks', default=None, - help='checks filter, when not specified, use clang-tidy ' - 'default') - config_group = parser.add_mutually_exclusive_group() - config_group.add_argument('-config', default=None, - help='Specifies a configuration in YAML/JSON format: ' - ' -config="{Checks: \'*\', ' - ' CheckOptions: {x: y}}" ' - 'When the value is empty, clang-tidy will ' - 'attempt to find a file named .clang-tidy for ' - 'each source file in its parent directories.') - config_group.add_argument('-config-file', default=None, - help='Specify the path of .clang-tidy or custom config ' - 'file: e.g. -config-file=/some/path/myTidyConfigFile. ' - 'This option internally works exactly the same way as ' - '-config option after reading specified config file. ' - 'Use either -config-file or -config, not both.') - parser.add_argument('-header-filter', default=None, - help='regular expression matching the names of the ' - 'headers to output diagnostics from. Diagnostics from ' - 'the main file of each translation unit are always ' - 'displayed.') - parser.add_argument('-line-filter', default=None, - help='List of files with line ranges to filter the' - 'warnings.') - if yaml: - parser.add_argument('-export-fixes', metavar='filename', dest='export_fixes', - help='Create a yaml file to store suggested fixes in, ' - 'which can be applied with clang-apply-replacements.') - parser.add_argument('-j', type=int, default=0, - help='number of tidy instances to be run in parallel.') - parser.add_argument('files', nargs='*', default=['.*'], - help='files to be processed (regex on path)') - parser.add_argument('-fix', action='store_true', help='apply fix-its') - parser.add_argument('-format', action='store_true', help='Reformat code ' - 'after applying fixes') - parser.add_argument('-style', default='file', help='The style of reformat ' - 'code after applying fixes') - parser.add_argument('-use-color', type=strtobool, nargs='?', const=True, - help='Use colors in diagnostics, overriding clang-tidy\'s' - ' default behavior. This option overrides the \'UseColor' - '\' option in .clang-tidy file, if any.') - parser.add_argument('-p', dest='build_path', - help='Path used to read a compile command database.') - parser.add_argument('-extra-arg', dest='extra_arg', - action='append', default=[], - help='Additional argument to append to the compiler ' - 'command line.') - parser.add_argument('-extra-arg-before', dest='extra_arg_before', - action='append', default=[], - help='Additional argument to prepend to the compiler ' - 'command line.') - parser.add_argument('-ignore', default=DEFAULT_CLANG_TIDY_IGNORE, - help='File path to clang-tidy-ignore') - parser.add_argument('-quiet', action='store_true', - help='Run clang-tidy in quiet mode') - parser.add_argument('-load', dest='plugins', - action='append', default=[], - help='Load the specified plugin in clang-tidy.') - args = parser.parse_args() - - db_path = 'compile_commands.json' - - if args.build_path is not None: - build_path = args.build_path - else: - # Find our database - build_path = find_compilation_database(db_path) - - clang_tidy_binary = find_binary(args.clang_tidy_binary, "clang-tidy", - build_path) - - tmpdir = None - if args.fix or (yaml and args.export_fixes): - clang_apply_replacements_binary = find_binary( - args.clang_apply_replacements_binary, "clang-apply-replacements", - build_path) - tmpdir = tempfile.mkdtemp() - - try: - invocation = get_tidy_invocation("", clang_tidy_binary, args.checks, - None, build_path, args.header_filter, - args.allow_enabling_alpha_checkers, - args.extra_arg, args.extra_arg_before, - args.quiet, args.config_file, args.config, - args.line_filter, args.use_color, - args.plugins) - invocation.append('-list-checks') - invocation.append('-') - if args.quiet: - # Even with -quiet we still want to check if we can call clang-tidy. - with open(os.devnull, 'w') as dev_null: - subprocess.check_call(invocation, stdout=dev_null) - else: - subprocess.check_call(invocation) - except: - print("Unable to run clang-tidy.", file=sys.stderr) - sys.exit(1) - - # Load the database and extract all files. - database = json.load(open(os.path.join(build_path, db_path))) - files = set([make_absolute(entry['file'], entry['directory']) - for entry in database]) - files, excluded = filter_files(args.ignore, files) - if excluded: - print("Excluding the following files:\n" + "\n".join(excluded) + "\n") - - max_task = args.j - if max_task == 0: - max_task = multiprocessing.cpu_count() - - # Build up a big regexy filter from all command line arguments. - file_name_re = re.compile('|'.join(args.files)) - - return_code = 0 - try: - # Spin up a bunch of tidy-launching threads. - task_queue = queue.Queue(max_task) - # List of files with a non-zero return code. - failed_files = [] - lock = threading.Lock() - for _ in range(max_task): - t = threading.Thread(target=run_tidy, - args=(args, clang_tidy_binary, tmpdir, build_path, - task_queue, lock, failed_files)) - t.daemon = True - t.start() - - # Fill the queue with files. - for name in files: - if file_name_re.search(name): - task_queue.put(name) - - # Wait for all threads to be done. - task_queue.join() - if len(failed_files): - return_code = 1 - - except KeyboardInterrupt: - # This is a sad hack. Unfortunately subprocess goes - # bonkers with ctrl-c and we start forking merrily. - print('\nCtrl-C detected, goodbye.') - if tmpdir: - shutil.rmtree(tmpdir) - os.kill(0, 9) - - if yaml and args.export_fixes: - print('Writing fixes to ' + args.export_fixes + ' ...') - try: - merge_replacement_files(tmpdir, args.export_fixes) - except: - print('Error exporting fixes.\n', file=sys.stderr) - traceback.print_exc() - return_code=1 - - if args.fix: - print('Applying fixes ...') - try: - apply_fixes(args, clang_apply_replacements_binary, tmpdir) - except: - print('Error applying fixes.\n', file=sys.stderr) - traceback.print_exc() - return_code = 1 - - if tmpdir: - shutil.rmtree(tmpdir) - sys.exit(return_code) - - -if __name__ == '__main__': - main() diff --git a/cpp_src/CMakeLists.txt b/cpp_src/CMakeLists.txt index f0ae5f63d..13c9cd423 100644 --- a/cpp_src/CMakeLists.txt +++ b/cpp_src/CMakeLists.txt @@ -86,8 +86,8 @@ if(NOT MSVC AND NOT APPLE) endif() if(MSVC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd4244 -wd4267 -wd4996 -wd4717 -MP") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4244 -wd4267 -wd4996 -wd4717 -wd4800 -wd4396 -wd4503 -MP") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd4244 -wd4267 -wd4996 -wd4717 -MP -MD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd4244 -wd4267 -wd4996 -wd4717 -wd4800 -wd4396 -wd4503 -MP -MD") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -SAFESEH:NO") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -Wswitch-enum") @@ -296,7 +296,8 @@ set_source_files_properties (${REINDEXER_SOURCE_PATH}/core/storage/leveldblogger list(APPEND REINDEXER_LIBRARIES reindexer) add_library(${TARGET} STATIC ${HDRS} ${SRCS} ${VENDORS}) add_definitions(-DREINDEX_CORE_BUILD=1) - +add_definitions(-DFMT_HEADER_ONLY=1) +add_definitions(-DSPDLOG_FMT_EXTERNAL=1) # add_definitions(-DREINDEX_FT_EXTRA_DEBUG=1) @@ -567,9 +568,10 @@ endif() include_directories(${PROJECT_BINARY_DIR}) -string ( REGEX REPLACE "(.*)([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)" "\\2.\\3.\\4" REINDEXER_VERSION ${REINDEXER_VERSION_FULL}) +string ( REGEX REPLACE "v([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)" "\\1.\\2.\\3" REINDEXER_VERSION ${REINDEXER_VERSION_FULL}) string ( REGEX REPLACE ".*-([0-9]+)-(.*)" "\\1.\\2" REINDEXER_RELEASE ${REINDEXER_VERSION_FULL}) set(REINDEXER_VERSION_REDUCED ${REINDEXER_VERSION}) + if(CMAKE_MATCH_1) set(REINDEXER_VERSION ${REINDEXER_VERSION}.${REINDEXER_RELEASE}) endif() diff --git a/cpp_src/client/coroqueryresults.cc b/cpp_src/client/coroqueryresults.cc index 6e858b108..8eab07c21 100644 --- a/cpp_src/client/coroqueryresults.cc +++ b/cpp_src/client/coroqueryresults.cc @@ -12,7 +12,7 @@ using namespace reindexer::net; CoroQueryResults::CoroQueryResults(int fetchFlags) : conn_(nullptr), fetchOffset_(0), fetchFlags_(fetchFlags), fetchAmount_(0), requestTimeout_(0) {} -CoroQueryResults::CoroQueryResults(net::cproto::CoroClientConnection *conn, NsArray &&nsArray, int fetchFlags, int fetchAmount, +CoroQueryResults::CoroQueryResults(net::cproto::CoroClientConnection* conn, NsArray&& nsArray, int fetchFlags, int fetchAmount, seconds timeout) : conn_(conn), nsArray_(std::move(nsArray)), @@ -21,7 +21,7 @@ CoroQueryResults::CoroQueryResults(net::cproto::CoroClientConnection *conn, NsAr fetchAmount_(fetchAmount), requestTimeout_(timeout) {} -CoroQueryResults::CoroQueryResults(net::cproto::CoroClientConnection *conn, NsArray &&nsArray, std::string_view rawResult, RPCQrId id, +CoroQueryResults::CoroQueryResults(net::cproto::CoroClientConnection* conn, NsArray&& nsArray, std::string_view rawResult, RPCQrId id, int fetchFlags, int fetchAmount, seconds timeout) : CoroQueryResults(conn, std::move(nsArray), fetchFlags, fetchAmount, timeout) { Bind(rawResult, id); @@ -61,7 +61,7 @@ void CoroQueryResults::Bind(std::string_view rawResult, RPCQrId id) { RawResBufT::max_size(), rawResLen, fetchAmount_); } rawResult_.assign(copyStart, rawResult.end()); - } catch (const Error &err) { + } catch (const Error& err) { status_ = err; } } @@ -98,7 +98,9 @@ void CoroQueryResults::fetchNextResults() { h_vector CoroQueryResults::GetNamespaces() const { h_vector ret; ret.reserve(nsArray_.size()); - for (auto &ns : nsArray_) ret.push_back(ns->name_); + for (auto& ns : nsArray_) { + ret.push_back(ns->name_); + } return ret; } @@ -107,14 +109,14 @@ TagsMatcher CoroQueryResults::getTagsMatcher(int nsid) const { return nsArray_[n class AdditionalRank : public IAdditionalDatasource { public: AdditionalRank(double r) noexcept : rank_(r) {} - void PutAdditionalFields(JsonBuilder &builder) const override final { builder.Put("rank()", rank_); } - IEncoderDatasourceWithJoins *GetJoinsDatasource() noexcept override final { return nullptr; } + void PutAdditionalFields(JsonBuilder& builder) const override final { builder.Put("rank()", rank_); } + IEncoderDatasourceWithJoins* GetJoinsDatasource() noexcept override final { return nullptr; } private: double rank_; }; -void CoroQueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSerializer &wrser, bool withHdrLen) { +void CoroQueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSerializer& wrser, bool withHdrLen) { auto tm = qr_->getTagsMatcher(itemParams_.nsid); JsonEncoder enc(&tm); JsonBuilder builder(wrser, ObjType::TypePlain); @@ -136,7 +138,7 @@ void CoroQueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSeri } } -Error CoroQueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { +Error CoroQueryResults::Iterator::GetMsgPack(WrSerializer& wrser, bool withHdrLen) { readNext(); int type = qr_->queryParams_.flags & kResultsFormatMask; if (type == kResultsMsgPack) { @@ -151,7 +153,7 @@ Error CoroQueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLe return errOK; } -Error CoroQueryResults::Iterator::GetJSON(WrSerializer &wrser, bool withHdrLen) { +Error CoroQueryResults::Iterator::GetJSON(WrSerializer& wrser, bool withHdrLen) { readNext(); try { switch (qr_->queryParams_.flags & kResultsFormatMask) { @@ -169,13 +171,13 @@ Error CoroQueryResults::Iterator::GetJSON(WrSerializer &wrser, bool withHdrLen) default: return Error(errParseBin, "Server returned data in unknown format %d", qr_->queryParams_.flags & kResultsFormatMask); } - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; } -Error CoroQueryResults::Iterator::GetCJSON(WrSerializer &wrser, bool withHdrLen) { +Error CoroQueryResults::Iterator::GetCJSON(WrSerializer& wrser, bool withHdrLen) { readNext(); try { switch (qr_->queryParams_.flags & kResultsFormatMask) { @@ -193,7 +195,7 @@ Error CoroQueryResults::Iterator::GetCJSON(WrSerializer &wrser, bool withHdrLen) default: return Error(errParseBin, "Server returned data in unknown format %d", qr_->queryParams_.flags & kResultsFormatMask); } - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; @@ -215,7 +217,7 @@ Item CoroQueryResults::Iterator::GetItem() { break; } case kResultsJson: { - char *endp = nullptr; + char* endp = nullptr; err = item.FromJSON(itemParams_.data, &endp); break; } @@ -226,7 +228,7 @@ Item CoroQueryResults::Iterator::GetItem() { return item; } return Item(); - } catch (const Error &) { + } catch (const Error&) { return Item(); } } @@ -248,7 +250,9 @@ std::string_view CoroQueryResults::Iterator::GetRaw() { } void CoroQueryResults::Iterator::readNext() { - if (nextPos_ != 0) return; + if (nextPos_ != 0) { + return; + } std::string_view rawResult(qr_->rawResult_.data(), qr_->rawResult_.size()); @@ -261,12 +265,12 @@ void CoroQueryResults::Iterator::readNext() { (void)joinedCnt; } nextPos_ = pos_ + ser.Pos(); - } catch (const Error &err) { - const_cast(qr_)->status_ = err; + } catch (const Error& err) { + const_cast(qr_)->status_ = err; } } -CoroQueryResults::Iterator &CoroQueryResults::Iterator::operator++() { +CoroQueryResults::Iterator& CoroQueryResults::Iterator::operator++() { try { readNext(); idx_++; @@ -274,11 +278,11 @@ CoroQueryResults::Iterator &CoroQueryResults::Iterator::operator++() { nextPos_ = 0; if (idx_ != qr_->queryParams_.qcount && idx_ == qr_->queryParams_.count + qr_->fetchOffset_) { - const_cast(qr_)->fetchNextResults(); + const_cast(qr_)->fetchNextResults(); pos_ = 0; } - } catch (const Error &err) { - const_cast(qr_)->status_ = err; + } catch (const Error& err) { + const_cast(qr_)->status_ = err; } return *this; diff --git a/cpp_src/client/coroqueryresults.h b/cpp_src/client/coroqueryresults.h index d791ae426..4a5204ca4 100644 --- a/cpp_src/client/coroqueryresults.h +++ b/cpp_src/client/coroqueryresults.h @@ -40,7 +40,7 @@ class CoroQueryResults { Iterator& operator++(); Error Status() const noexcept { return qr_->status_; } bool operator!=(const Iterator& other) const noexcept { return idx_ != other.idx_; } - bool operator==(const Iterator& other) const noexcept { return idx_ == other.idx_; }; + bool operator==(const Iterator& other) const noexcept { return idx_ == other.idx_; } Iterator& operator*() { return *this; } void readNext(); void getJSONFromCJSON(std::string_view cjson, WrSerializer& wrser, bool withHdrLen = true); diff --git a/cpp_src/client/cororeindexer.cc b/cpp_src/client/cororeindexer.cc index 66b6c9653..cf36c8c3f 100644 --- a/cpp_src/client/cororeindexer.cc +++ b/cpp_src/client/cororeindexer.cc @@ -55,12 +55,8 @@ Error CoroReindexer::GetMeta(std::string_view nsName, const std::string& key, st Error CoroReindexer::PutMeta(std::string_view nsName, const std::string& key, std::string_view data) { return impl_->PutMeta(nsName, key, data, ctx_); } -Error CoroReindexer::EnumMeta(std::string_view nsName, std::vector& keys) { - return impl_->EnumMeta(nsName, keys, ctx_); -} -Error CoroReindexer::DeleteMeta(std::string_view nsName, const std::string& key) { - return impl_->DeleteMeta(nsName, key, ctx_); -} +Error CoroReindexer::EnumMeta(std::string_view nsName, std::vector& keys) { return impl_->EnumMeta(nsName, keys, ctx_); } +Error CoroReindexer::DeleteMeta(std::string_view nsName, const std::string& key) { return impl_->DeleteMeta(nsName, key, ctx_); } Error CoroReindexer::Delete(const Query& q, CoroQueryResults& result) { return impl_->Delete(q, result, ctx_); } Error CoroReindexer::Select(std::string_view query, CoroQueryResults& result) { return impl_->Select(query, result, ctx_); } Error CoroReindexer::Select(const Query& q, CoroQueryResults& result) { return impl_->Select(q, result, ctx_); } diff --git a/cpp_src/client/cororeindexer.h b/cpp_src/client/cororeindexer.h index 9ad7dc646..a7d849d25 100644 --- a/cpp_src/client/cororeindexer.h +++ b/cpp_src/client/cororeindexer.h @@ -29,23 +29,23 @@ class CoroRPCClient; class CoroReindexer { public: /// Completion routine - typedef std::function Completion; + typedef std::function Completion; /// Create Reindexer database object - CoroReindexer(const ReindexerConfig & = ReindexerConfig()); + CoroReindexer(const ReindexerConfig& = ReindexerConfig()); /// Destroy Reindexer database object ~CoroReindexer(); - CoroReindexer(const CoroReindexer &) = delete; - CoroReindexer(CoroReindexer &&) noexcept; - CoroReindexer &operator=(const CoroReindexer &) = delete; - CoroReindexer &operator=(CoroReindexer &&) noexcept; + CoroReindexer(const CoroReindexer&) = delete; + CoroReindexer(CoroReindexer&&) noexcept; + CoroReindexer& operator=(const CoroReindexer&) = delete; + CoroReindexer& operator=(CoroReindexer&&) noexcept; /// Connect - connect to reindexer server /// @param dsn - uri of server and database, like: `cproto://user@password:127.0.0.1:6534/dbname` or /// `ucproto://user@password:/tmp/reindexer.sock:/dbname` /// @param loop - event loop for connections and coroutines handling /// @param opts - Connect options. May contain any of
- Error Connect(const std::string &dsn, dynamic_loop &loop, const client::ConnectOpts &opts = client::ConnectOpts()); + Error Connect(const std::string& dsn, dynamic_loop& loop, const client::ConnectOpts& opts = client::ConnectOpts()); /// Stop - shutdown connector void Stop(); /// Open or create namespace @@ -54,10 +54,10 @@ class CoroReindexer { /// StorageOpts::Enabled() - Enable storage. If storage is disabled, then namespace will be completely in-memory
/// StorageOpts::CreateIfMissing () - Storage will be created, if missing /// @return errOK - On success - Error OpenNamespace(std::string_view nsName, const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); + Error OpenNamespace(std::string_view nsName, const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); /// Create new namespace. Will fail, if namespace already exists /// @param nsDef - NamespaceDef with namespace initial parameters - Error AddNamespace(const NamespaceDef &nsDef); + Error AddNamespace(const NamespaceDef& nsDef); /// Close namespace. Will free all memory resources, associated with namespace. Forces sync changes to disk /// @param nsName - Name of namespace Error CloseNamespace(std::string_view nsName); @@ -70,19 +70,19 @@ class CoroReindexer { /// Rename namespace. If namespace with dstNsName exists, then it is replaced. /// @param srcNsName - Name of namespace /// @param dstNsName - desired name of namespace - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName); /// Add index to namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error AddIndex(std::string_view nsName, const IndexDef &index); + Error AddIndex(std::string_view nsName, const IndexDef& index); /// Update index in namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error UpdateIndex(std::string_view nsName, const IndexDef &index); + Error UpdateIndex(std::string_view nsName, const IndexDef& index); /// Drop index from namespace /// @param nsName - Name of namespace /// @param index - index name - Error DropIndex(std::string_view nsName, const IndexDef &index); + Error DropIndex(std::string_view nsName, const IndexDef& index); /// Set fields schema for namespace /// @param nsName - Name of namespace /// @param schema - JSON in JsonSchema format @@ -90,50 +90,50 @@ class CoroReindexer { /// Get list of all available namespaces /// @param defs - std::vector of NamespaceDef of available namespaces /// @param opts - Enumeration options - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts); /// Gets a list of available databases for a certain server. /// @param dbList - list of DB names - Error EnumDatabases(std::vector &dbList); + Error EnumDatabases(std::vector& dbList); /// Insert new Item to namespace. If item with same PK is already exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Insert(std::string_view nsName, Item &item); + Error Insert(std::string_view nsName, Item& item); /// Update Item in namespace. If item with same PK is not exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Update(std::string_view nsName, Item &item); + Error Update(std::string_view nsName, Item& item); /// Update or Insert Item in namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Upsert(std::string_view nsName, Item &item); + Error Upsert(std::string_view nsName, Item& item); /// Updates all items in namespace, that satisfy provided query. /// @param query - Query to define items set for update. /// @param result - QueryResults with IDs of deleted items. - Error Update(const Query &query, CoroQueryResults &result); + Error Update(const Query& query, CoroQueryResults& result); /// Delete Item from namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Delete(std::string_view nsName, Item &item); + Error Delete(std::string_view nsName, Item& item); /// Delete all items from namespace, which matches provided Query /// @param query - Query with conditions /// @param result - QueryResults with IDs of deleted items - Error Delete(const Query &query, CoroQueryResults &result); + Error Delete(const Query& query, CoroQueryResults& result); /// Execute SQL Query and return results /// May be used with completion /// @param query - SQL query. Only "SELECT" semantic is supported /// @param result - QueryResults with found items - Error Select(std::string_view query, CoroQueryResults &result); + Error Select(std::string_view query, CoroQueryResults& result); /// Execute Query and return results /// May be used with completion /// @param query - Query object with query attributes /// @param result - QueryResults with found items - Error Select(const Query &query, CoroQueryResults &result); + Error Select(const Query& query, CoroQueryResults& result); /// Flush changes to storage /// @param nsName - Name of namespace Error Commit(std::string_view nsName); @@ -145,34 +145,34 @@ class CoroReindexer { /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - output string with metadata - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data); /// Put metadata to storage by key /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - string with metadata - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data); /// Get list of all metadata keys /// @param nsName - Name of namespace /// @param keys - std::vector filled with meta keys - Error EnumMeta(std::string_view nsName, std::vector &keys); + Error EnumMeta(std::string_view nsName, std::vector& keys); /// Delete metadata from storage by key /// @param nsName - Name of namespace /// @param key - string with meta key - Error DeleteMeta(std::string_view nsName, const std::string &key); + Error DeleteMeta(std::string_view nsName, const std::string& key); /// Subscribe to updates of database /// @param observer - Observer interface, which will receive updates /// @param filters - Subscription filters set /// @param opts - Subscription options (allows to either add new filters or reset them) - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts = SubscriptionOpts()); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts = SubscriptionOpts()); /// Unsubscribe from updates of database /// Cancellation context doesn't affect this call /// @param observer - Observer interface, which will be unsubscribed updates - Error UnsubscribeUpdates(IUpdatesObserver *observer); + Error UnsubscribeUpdates(IUpdatesObserver* observer); /// Get possible suggestions for token (set by 'pos') in Sql query. /// @param sqlQuery - sql query. /// @param pos - position in sql query for suggestions. /// @param suggestions - all the suggestions for 'pos' position in query. - Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector &suggestions); + Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector& suggestions); /// Get current connection status Error Status(); /// Allocate new transaction for namespace @@ -180,14 +180,14 @@ class CoroReindexer { CoroTransaction NewTransaction(std::string_view nsName); /// Commit transaction - transaction will be deleted after commit /// @param tr - transaction to commit - Error CommitTransaction(CoroTransaction &tr); + Error CommitTransaction(CoroTransaction& tr); /// RollBack transaction - transaction will be deleted after rollback /// @param tr - transaction to rollback - Error RollBackTransaction(CoroTransaction &tr); + Error RollBackTransaction(CoroTransaction& tr); /// Add cancelable context /// @param cancelCtx - context pointer - CoroReindexer WithContext(const IRdxCancelContext *cancelCtx) { return CoroReindexer(impl_, ctx_.WithCancelContext(cancelCtx)); } + CoroReindexer WithContext(const IRdxCancelContext* cancelCtx) { return CoroReindexer(impl_, ctx_.WithCancelContext(cancelCtx)); } /// Add execution timeout to the next query /// @param timeout - Optional server-side execution timeout for each subquery @@ -198,8 +198,8 @@ class CoroReindexer { typedef ReindexerConfig ConfigT; private: - CoroReindexer(CoroRPCClient *impl, InternalRdxContext &&ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} - CoroRPCClient *impl_; + CoroReindexer(CoroRPCClient* impl, InternalRdxContext&& ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} + CoroRPCClient* impl_; bool owner_; InternalRdxContext ctx_; }; diff --git a/cpp_src/client/cororpcclient.cc b/cpp_src/client/cororpcclient.cc index 1776d0d8b..43b41257c 100644 --- a/cpp_src/client/cororpcclient.cc +++ b/cpp_src/client/cororpcclient.cc @@ -66,7 +66,9 @@ Error CoroRPCClient::AddNamespace(const NamespaceDef& nsDef, const InternalRdxCo nsDef.GetJSON(ser); auto status = conn_.Call(mkCommand(cproto::kCmdOpenNamespace, &ctx), ser.Slice()).Status(); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } namespaces_.emplace(nsDef.name, Namespace::Ptr(new Namespace(nsDef.name))); return errOK; @@ -92,7 +94,9 @@ Error CoroRPCClient::TruncateNamespace(std::string_view nsName, const InternalRd Error CoroRPCClient::RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx) { auto status = conn_.Call(mkCommand(cproto::kCmdRenameNamespace, &ctx), srcNsName, dstNsName).Status(); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } if (srcNsName != dstNsName) { auto namespacePtr = namespaces_.find(srcNsName); @@ -152,7 +156,9 @@ Error CoroRPCClient::modifyItem(std::string_view nsName, Item& item, int mode, s return err; } } else { - if (ret.Status().code() != errStateInvalidated || tryCount > 2) return ret.Status(); + if (ret.Status().code() != errStateInvalidated || tryCount > 2) { + return ret.Status(); + } if (withNetTimeout) { netTimeout = netDeadline - conn_.Now(); } @@ -168,7 +174,9 @@ Error CoroRPCClient::modifyItem(std::string_view nsName, Item& item, int mode, s auto newItem = NewItem(nsName); char* endp = nullptr; Error err = newItem.FromJSON(item.impl_->GetJSON(), &endp); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } item = std::move(newItem); } @@ -288,7 +296,9 @@ void vec2pack(const h_vector& vec, WrSerializer& ser) { // Get array of payload Type Versions ser.PutVarUint(vec.size()); - for (auto v : vec) ser.PutVarUint(v); + for (auto v : vec) { + ser.PutVarUint(v); + } return; } @@ -436,7 +446,9 @@ Error CoroRPCClient::GetSqlSuggestions(std::string_view query, int pos, std::vec suggests.clear(); suggests.reserve(rargs.size()); - for (auto& rarg : rargs) suggests.push_back(rarg.As()); + for (auto& rarg : rargs) { + suggests.push_back(rarg.As()); + } } return ret.Status(); } catch (const Error& err) { @@ -488,7 +500,9 @@ void CoroRPCClient::onUpdates(const cproto::CoroRPCAnswer& ans) { std::string_view nsName(args[1]); std::string_view pwalRec(args[2]); lsn_t originLSN; - if (args.size() >= 4) originLSN = lsn_t(args[3].As()); + if (args.size() >= 4) { + originLSN = lsn_t(args[3].As()); + } WALRecord wrec(pwalRec); if (wrec.type == WalItemModify) { @@ -508,7 +522,9 @@ void CoroRPCClient::onUpdates(const cproto::CoroRPCAnswer& ans) { InternalRdxContext ctx(nullptr); CoroQueryResults qr; auto err = Select(Query(std::string(nsName)).Limit(0), qr, ctx); - if (!err.ok()) return; + if (!err.ok()) { + return; + } } else { // We have bundled tagsMatcher if (bundledTagsMatcher) { diff --git a/cpp_src/client/cororpcclient.h b/cpp_src/client/cororpcclient.h index 65de044d1..696732960 100644 --- a/cpp_src/client/cororpcclient.h +++ b/cpp_src/client/cororpcclient.h @@ -25,72 +25,72 @@ using std::chrono::seconds; using namespace net; class CoroRPCClient { public: - typedef std::function Completion; - CoroRPCClient(const ReindexerConfig &config); - CoroRPCClient(const CoroRPCClient &) = delete; - CoroRPCClient(CoroRPCClient &&) = delete; - CoroRPCClient &operator=(const CoroRPCClient &) = delete; - CoroRPCClient &operator=(CoroRPCClient &&) = delete; + typedef std::function Completion; + CoroRPCClient(const ReindexerConfig& config); + CoroRPCClient(const CoroRPCClient&) = delete; + CoroRPCClient(CoroRPCClient&&) = delete; + CoroRPCClient& operator=(const CoroRPCClient&) = delete; + CoroRPCClient& operator=(CoroRPCClient&&) = delete; ~CoroRPCClient(); - Error Connect(const std::string &dsn, ev::dynamic_loop &loop, const client::ConnectOpts &opts); + Error Connect(const std::string& dsn, ev::dynamic_loop& loop, const client::ConnectOpts& opts); void Stop(); - Error OpenNamespace(std::string_view nsName, const InternalRdxContext &ctx, - const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); - Error AddNamespace(const NamespaceDef &nsDef, const InternalRdxContext &ctx); - Error CloseNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error DropNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error TruncateNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName, const InternalRdxContext &ctx); - Error AddIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error UpdateIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error DropIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext &ctx); - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts, const InternalRdxContext &ctx); - Error EnumDatabases(std::vector &dbList, const InternalRdxContext &ctx); - Error Insert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Update(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Upsert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Delete(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Delete(const Query &query, CoroQueryResults &result, const InternalRdxContext &ctx); - Error Update(const Query &query, CoroQueryResults &result, const InternalRdxContext &ctx); - Error Select(std::string_view query, CoroQueryResults &result, const InternalRdxContext &ctx) { + Error OpenNamespace(std::string_view nsName, const InternalRdxContext& ctx, + const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); + Error AddNamespace(const NamespaceDef& nsDef, const InternalRdxContext& ctx); + Error CloseNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error DropNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error TruncateNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx); + Error AddIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error UpdateIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error DropIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext& ctx); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts, const InternalRdxContext& ctx); + Error EnumDatabases(std::vector& dbList, const InternalRdxContext& ctx); + Error Insert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Update(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Upsert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Delete(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Delete(const Query& query, CoroQueryResults& result, const InternalRdxContext& ctx); + Error Update(const Query& query, CoroQueryResults& result, const InternalRdxContext& ctx); + Error Select(std::string_view query, CoroQueryResults& result, const InternalRdxContext& ctx) { return selectImpl(query, result, config_.RequestTimeout, ctx); } - Error Select(const Query &query, CoroQueryResults &result, const InternalRdxContext &ctx) { + Error Select(const Query& query, CoroQueryResults& result, const InternalRdxContext& ctx) { return selectImpl(query, result, config_.RequestTimeout, ctx); } Error Commit(std::string_view nsName); Item NewItem(std::string_view nsName); - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data, const InternalRdxContext &ctx); - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data, const InternalRdxContext &ctx); - Error EnumMeta(std::string_view nsName, std::vector &keys, const InternalRdxContext &ctx); - Error DeleteMeta(std::string_view nsName, const std::string &key, const InternalRdxContext &ctx); - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts = SubscriptionOpts()); - Error UnsubscribeUpdates(IUpdatesObserver *observer); - Error GetSqlSuggestions(std::string_view query, int pos, std::vector &suggests); - Error Status(const InternalRdxContext &ctx); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data, const InternalRdxContext& ctx); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data, const InternalRdxContext& ctx); + Error EnumMeta(std::string_view nsName, std::vector& keys, const InternalRdxContext& ctx); + Error DeleteMeta(std::string_view nsName, const std::string& key, const InternalRdxContext& ctx); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts = SubscriptionOpts()); + Error UnsubscribeUpdates(IUpdatesObserver* observer); + Error GetSqlSuggestions(std::string_view query, int pos, std::vector& suggests); + Error Status(const InternalRdxContext& ctx); - CoroTransaction NewTransaction(std::string_view nsName, const InternalRdxContext &ctx); - Error CommitTransaction(CoroTransaction &tr, const InternalRdxContext &ctx); - Error RollBackTransaction(CoroTransaction &tr, const InternalRdxContext &ctx); + CoroTransaction NewTransaction(std::string_view nsName, const InternalRdxContext& ctx); + Error CommitTransaction(CoroTransaction& tr, const InternalRdxContext& ctx); + Error RollBackTransaction(CoroTransaction& tr, const InternalRdxContext& ctx); protected: - Error selectImpl(std::string_view query, CoroQueryResults &result, seconds netTimeout, const InternalRdxContext &ctx); - Error selectImpl(const Query &query, CoroQueryResults &result, seconds netTimeout, const InternalRdxContext &ctx); - Error modifyItem(std::string_view nsName, Item &item, int mode, seconds netTimeout, const InternalRdxContext &ctx); + Error selectImpl(std::string_view query, CoroQueryResults& result, seconds netTimeout, const InternalRdxContext& ctx); + Error selectImpl(const Query& query, CoroQueryResults& result, seconds netTimeout, const InternalRdxContext& ctx); + Error modifyItem(std::string_view nsName, Item& item, int mode, seconds netTimeout, const InternalRdxContext& ctx); Error subscribeImpl(bool subscribe); - Namespace *getNamespace(std::string_view nsName); - Error addConnectEntry(const std::string &dsn, const client::ConnectOpts &opts, size_t idx); - void onUpdates(const net::cproto::CoroRPCAnswer &ans); + Namespace* getNamespace(std::string_view nsName); + Error addConnectEntry(const std::string& dsn, const client::ConnectOpts& opts, size_t idx); + void onUpdates(const net::cproto::CoroRPCAnswer& ans); void startResubRoutine(); void resubRoutine(); - void onConnFatalError(const Error &) noexcept { subscribed_ = false; } + void onConnFatalError(const Error&) noexcept { subscribed_ = false; } - cproto::CommandParams mkCommand(cproto::CmdCode cmd, const InternalRdxContext *ctx = nullptr) const noexcept; - static cproto::CommandParams mkCommand(cproto::CmdCode cmd, seconds reqTimeout, const InternalRdxContext *ctx) noexcept; + cproto::CommandParams mkCommand(cproto::CmdCode cmd, const InternalRdxContext* ctx = nullptr) const noexcept; + static cproto::CommandParams mkCommand(cproto::CmdCode cmd, seconds reqTimeout, const InternalRdxContext* ctx) noexcept; fast_hash_map namespaces_; @@ -100,10 +100,10 @@ class CoroRPCClient { bool subscribed_ = false; bool terminate_ = false; coroutine::wait_group resubWg_; - ev::dynamic_loop *loop_ = nullptr; + ev::dynamic_loop* loop_ = nullptr; }; -void vec2pack(const h_vector &vec, WrSerializer &ser); +void vec2pack(const h_vector& vec, WrSerializer& ser); } // namespace client } // namespace reindexer diff --git a/cpp_src/client/corotransaction.cc b/cpp_src/client/corotransaction.cc index f2a25e1b0..3ca1b9bd6 100644 --- a/cpp_src/client/corotransaction.cc +++ b/cpp_src/client/corotransaction.cc @@ -25,18 +25,24 @@ Error CoroTransaction::addTxItem(Item&& item, ItemModifyMode mode) { conn_->Call({net::cproto::kCmdAddTxItem, RequestTimeout_, execTimeout_, nullptr}, FormatJson, itemData, mode, "", 0, txId_); if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated || tryCount > 2) return ret.Status(); + if (ret.Status().code() != errStateInvalidated || tryCount > 2) { + return ret.Status(); + } CoroQueryResults qr; InternalRdxContext ctx; ctx = ctx.WithTimeout(execTimeout_); auto err = rpcClient_->Select(Query(nsName_).Limit(0), qr, ctx); - if (!err.ok()) return Error(errLogic, "Can't update TagsMatcher"); + if (!err.ok()) { + return Error(errLogic, "Can't update TagsMatcher"); + } auto newItem = NewItem(); char* endp = nullptr; err = newItem.FromJSON(item.impl_->GetJSON(), &endp); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } item = std::move(newItem); } else { break; @@ -48,7 +54,9 @@ Error CoroTransaction::addTxItem(Item&& item, ItemModifyMode mode) { } Item CoroTransaction::NewItem() { - if (!rpcClient_) return Item(Error(errLogic, "rpcClient not set for client transaction")); + if (!rpcClient_) { + return Item(Error(errLogic, "rpcClient not set for client transaction")); + } return rpcClient_->NewItem(nsName_); } } // namespace client diff --git a/cpp_src/client/internalrdxcontext.h b/cpp_src/client/internalrdxcontext.h index f4395ad6d..6fd813ad8 100644 --- a/cpp_src/client/internalrdxcontext.h +++ b/cpp_src/client/internalrdxcontext.h @@ -21,7 +21,9 @@ class InternalRdxContext { InternalRdxContext WithCancelContext(const IRdxCancelContext* cancelCtx) noexcept { return InternalRdxContext(cancelCtx, cmpl_, execTimeout_); } - InternalRdxContext WithCompletion(Completion cmpl, InternalRdxContext&) noexcept { return InternalRdxContext(std::move(cmpl), execTimeout_); } + InternalRdxContext WithCompletion(Completion cmpl, InternalRdxContext&) noexcept { + return InternalRdxContext(std::move(cmpl), execTimeout_); + } InternalRdxContext WithCompletion(Completion cmpl) const noexcept { return InternalRdxContext(std::move(cmpl), execTimeout_); } InternalRdxContext WithTimeout(milliseconds execTimeout) const noexcept { return InternalRdxContext(cmpl_, execTimeout); } diff --git a/cpp_src/client/item.cc b/cpp_src/client/item.cc index 81160da29..490d5d49e 100644 --- a/cpp_src/client/item.cc +++ b/cpp_src/client/item.cc @@ -8,12 +8,12 @@ namespace client { Item::Item() : status_(errNotValid) {} -Item::Item(Item &&other) noexcept : impl_(std::move(other.impl_)), status_(std::move(other.status_)), id_(other.id_) {} +Item::Item(Item&& other) noexcept : impl_(std::move(other.impl_)), status_(std::move(other.status_)), id_(other.id_) {} -Item::Item(ItemImpl *impl) : impl_(impl) {} -Item::Item(const Error &err) : impl_(nullptr), status_(err) {} +Item::Item(ItemImpl* impl) : impl_(impl) {} +Item::Item(const Error& err) : impl_(nullptr), status_(err) {} -Item &Item::operator=(Item &&other) noexcept { +Item& Item::operator=(Item&& other) noexcept { if (&other != this) { impl_ = std::move(other.impl_); status_ = std::move(other.status_); @@ -26,8 +26,8 @@ Item::~Item() {} Item::operator bool() const { return impl_ != nullptr; } -Error Item::FromJSON(std::string_view slice, char **endp, bool pkOnly) { return impl_->FromJSON(slice, endp, pkOnly); } -Error Item::FromCJSON(std::string_view slice) &noexcept { +Error Item::FromJSON(std::string_view slice, char** endp, bool pkOnly) { return impl_->FromJSON(slice, endp, pkOnly); } +Error Item::FromCJSON(std::string_view slice) & noexcept { try { impl_->FromCJSON(slice); } @@ -35,15 +35,15 @@ Error Item::FromCJSON(std::string_view slice) &noexcept { return {}; } void Item::FromCJSONImpl(std::string_view slice) & { impl_->FromCJSON(slice); } -Error Item::FromMsgPack(std::string_view slice, size_t &offset) { return impl_->FromMsgPack(slice, offset); } +Error Item::FromMsgPack(std::string_view slice, size_t& offset) { return impl_->FromMsgPack(slice, offset); } std::string_view Item::GetCJSON() { return impl_->GetCJSON(); } std::string_view Item::GetJSON() { return impl_->GetJSON(); } std::string_view Item::GetMsgPack() { return impl_->GetMsgPack(); } -void Item::SetPrecepts(const std::vector &precepts) { impl_->SetPrecepts(precepts); } +void Item::SetPrecepts(const std::vector& precepts) { impl_->SetPrecepts(precepts); } bool Item::IsTagsUpdated() { return impl_->tagsMatcher().isUpdated(); } int Item::GetStateToken() { return impl_->tagsMatcher().stateToken(); } -Item &Item::Unsafe(bool enable) { +Item& Item::Unsafe(bool enable) { impl_->Unsafe(enable); return *this; } diff --git a/cpp_src/client/item.h b/cpp_src/client/item.h index 8d7efe5dc..3a7ebee00 100644 --- a/cpp_src/client/item.h +++ b/cpp_src/client/item.h @@ -23,22 +23,22 @@ class Item { Item(); /// Destroy Item ~Item(); - Item(const Item &) = delete; - Item(Item &&) noexcept; - Item &operator=(const Item &) = delete; - Item &operator=(Item &&) noexcept; + Item(const Item&) = delete; + Item(Item&&) noexcept; + Item& operator=(const Item&) = delete; + Item& operator=(Item&&) noexcept; /// Build item from JSON
/// If Item is in *Unsafe Mode*, then Item will not store slice, but just keep pointer to data in slice, /// application *MUST* hold slice until end of life of Item /// @param slice - data slice with Json. /// @param endp - pounter to end of parsed part of slice - Error FromJSON(std::string_view slice, char **endp = nullptr, bool = false); + Error FromJSON(std::string_view slice, char** endp = nullptr, bool = false); /// Build item from JSON
/// If Item is in *Unsafe Mode*, then Item will not store slice, but just keep pointer to data in slice, /// application *MUST* hold slice until end of life of Item /// @param slice - data slice with CJson - Error FromCJSON(std::string_view slice) &noexcept; + Error FromCJSON(std::string_view slice) & noexcept; void FromCJSONImpl(std::string_view slice) &; /// Serialize item to CJSON.
/// If Item is in *Unfafe Mode*, then returned slice is allocated in temporary buffer, and can be invalidated by any next operation with @@ -56,7 +56,7 @@ class Item { /// Builds item from msgpack::object. /// @param slice - msgpack encoded data buffer. /// @param offset - position to start from. - Error FromMsgPack(std::string_view slice, size_t &offset); + Error FromMsgPack(std::string_view slice, size_t& offset); /// Get status of item /// @return data slice with JSON. Returned slice is allocated in temporary Item's buffer, and can be invalidated by any next operation /// with Item @@ -69,7 +69,7 @@ class Item { int NumFields() const noexcept; /// Set additional percepts for modify operation /// @param precepts - strings in format "fieldName=Func()" - void SetPrecepts(const std::vector &precepts); + void SetPrecepts(const std::vector& precepts); /// Check was names tags updated while modify operation /// @return true: tags was updated. bool IsTagsUpdated(); @@ -83,11 +83,11 @@ class Item { /// The advantage of unsafe mode is speed. It does not call extra memory allocation from heap and copying data.
/// The disadvantage of unsafe mode is potentially danger code. Most of C++ stl containters in many cases invalidates references - /// and in unsafe mode caller is responsibe to guarantee, that all resources passed to Item will keep valid - Item &Unsafe(bool enable = true); + Item& Unsafe(bool enable = true); private: - explicit Item(ItemImpl *impl); - explicit Item(const Error &err); + explicit Item(ItemImpl* impl); + explicit Item(const Error& err); void setID(int id) { id_ = id; } std::unique_ptr impl_; diff --git a/cpp_src/client/itemimpl.cc b/cpp_src/client/itemimpl.cc index 39217dabd..c9be720c0 100644 --- a/cpp_src/client/itemimpl.cc +++ b/cpp_src/client/itemimpl.cc @@ -8,7 +8,7 @@ namespace reindexer { namespace client { -ItemImpl &ItemImpl::operator=(ItemImpl &&other) noexcept { +ItemImpl& ItemImpl::operator=(ItemImpl&& other) noexcept { if (&other != this) { payloadType_ = std::move(other.payloadType_); payloadValue_ = std::move(other.payloadValue_); @@ -57,7 +57,7 @@ void ItemImpl::FromCJSON(std::string_view slice) { pl.Set(0, Variant(p_string(&tupleData_), Variant::no_hold_t{})); } -Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool /*pkOnly*/) { +Error ItemImpl::FromJSON(std::string_view slice, char** endp, bool /*pkOnly*/) { std::string_view data = slice; if (!unsafe_ && endp == nullptr) { holder_.emplace_back(slice); @@ -71,11 +71,13 @@ Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool /*pkOnly*/) { gason::JsonParser parser(&largeJSONStrings_); try { node = parser.Parse(giftStr(data), &len); - if (node.value.getTag() != gason::JSON_OBJECT) return Error(errParseJson, "Expected json object"); + if (node.value.getTag() != gason::JSON_OBJECT) { + return Error(errParseJson, "Expected json object"); + } if (unsafe_ && endp) { - *endp = const_cast(data.data()) + len; + *endp = const_cast(data.data()) + len; } - } catch (gason::Exception &e) { + } catch (gason::Exception& e) { return Error(errParseJson, "Error parsing json: '%s', pos: %d", e.what(), len); } @@ -94,7 +96,7 @@ Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool /*pkOnly*/) { return err; } -Error ItemImpl::FromMsgPack(std::string_view buf, size_t &offset) { +Error ItemImpl::FromMsgPack(std::string_view buf, size_t& offset) { Payload pl = GetPayload(); MsgPackDecoder decoder(tagsMatcher_); @@ -107,7 +109,7 @@ Error ItemImpl::FromMsgPack(std::string_view buf, size_t &offset) { return err; } -void ItemImpl::FromCJSON(ItemImpl *other) { +void ItemImpl::FromCJSON(ItemImpl* other) { auto cjson = other->GetCJSON(); FromCJSON(cjson); } @@ -117,7 +119,7 @@ std::string_view ItemImpl::GetMsgPack() { ConstPayload pl = GetConstPayload(); MsgPackEncoder msgpackEncoder(&tagsMatcher_); - const TagsLengths &tagsLengths = msgpackEncoder.GetTagsMeasures(pl); + const TagsLengths& tagsLengths = msgpackEncoder.GetTagsMeasures(pl); ser_.Reset(); MsgPackBuilder msgpackBuilder(ser_, &tagsLengths, &startTag, ObjType::TypePlain, &tagsMatcher_); diff --git a/cpp_src/client/itemimpl.h b/cpp_src/client/itemimpl.h index fba2bfa1e..09e441b71 100644 --- a/cpp_src/client/itemimpl.h +++ b/cpp_src/client/itemimpl.h @@ -12,45 +12,45 @@ namespace client { class ItemImpl { public: // Construct empty item - ItemImpl(PayloadType type, const TagsMatcher &tagsMatcher) + ItemImpl(PayloadType type, const TagsMatcher& tagsMatcher) : payloadType_(std::move(type)), payloadValue_(payloadType_.TotalSize(), 0, payloadType_.TotalSize() + 0x100), tagsMatcher_(tagsMatcher) { tagsMatcher_.clearUpdated(); } - ItemImpl(PayloadType type, PayloadValue v, const TagsMatcher &tagsMatcher) + ItemImpl(PayloadType type, PayloadValue v, const TagsMatcher& tagsMatcher) : payloadType_(std::move(type)), payloadValue_(std::move(v)), tagsMatcher_(tagsMatcher) { tagsMatcher_.clearUpdated(); } - ItemImpl(const ItemImpl &) = delete; - ItemImpl(ItemImpl &&o) = default; - ItemImpl &operator=(const ItemImpl &) = delete; - ItemImpl &operator=(ItemImpl &&) noexcept; + ItemImpl(const ItemImpl&) = delete; + ItemImpl(ItemImpl&& o) = default; + ItemImpl& operator=(const ItemImpl&) = delete; + ItemImpl& operator=(ItemImpl&&) noexcept; - void SetField(int field, const VariantArray &krs); + void SetField(int field, const VariantArray& krs); Variant GetField(int field); std::string_view GetJSON(); - Error FromJSON(std::string_view slice, char **endp = nullptr, bool pkOnly = false); - void FromCJSON(ItemImpl *other); + Error FromJSON(std::string_view slice, char** endp = nullptr, bool pkOnly = false); + void FromCJSON(ItemImpl* other); std::string_view GetCJSON(); void FromCJSON(std::string_view slice); std::string_view GetMsgPack(); - Error FromMsgPack(std::string_view slice, size_t &offset); + Error FromMsgPack(std::string_view slice, size_t& offset); PayloadType Type() const noexcept { return payloadType_; } - PayloadValue &Value() noexcept { return payloadValue_; } + PayloadValue& Value() noexcept { return payloadValue_; } Payload GetPayload() noexcept { return Payload(payloadType_, payloadValue_); } ConstPayload GetConstPayload() const noexcept { return ConstPayload(payloadType_, payloadValue_); } - TagsMatcher &tagsMatcher() { return tagsMatcher_; } + TagsMatcher& tagsMatcher() { return tagsMatcher_; } - void SetPrecepts(const std::vector &precepts) { precepts_ = precepts; } - const std::vector &GetPrecepts() const noexcept { return precepts_; } + void SetPrecepts(const std::vector& precepts) { precepts_ = precepts; } + const std::vector& GetPrecepts() const noexcept { return precepts_; } void Unsafe(bool enable) noexcept { unsafe_ = enable; } protected: diff --git a/cpp_src/client/queryresults.cc b/cpp_src/client/queryresults.cc index 406a647cd..e2bf53833 100644 --- a/cpp_src/client/queryresults.cc +++ b/cpp_src/client/queryresults.cc @@ -12,7 +12,7 @@ using namespace reindexer::net; QueryResults::QueryResults(int fetchFlags) : conn_(nullptr), queryID_(0), fetchOffset_(0), fetchFlags_(fetchFlags), fetchAmount_(0), requestTimeout_(0) {} -QueryResults::QueryResults(QueryResults &&obj) noexcept +QueryResults::QueryResults(QueryResults&& obj) noexcept : conn_(obj.conn_), nsArray_(std::move(obj.nsArray_)), rawResult_(std::move(obj.rawResult_)), @@ -25,7 +25,7 @@ QueryResults::QueryResults(QueryResults &&obj) noexcept status_(std::move(obj.status_)), cmpl_(std::move(obj.cmpl_)) {} -QueryResults &QueryResults::operator=(QueryResults &&obj) noexcept { +QueryResults& QueryResults::operator=(QueryResults&& obj) noexcept { if (this != &obj) { rawResult_ = std::move(obj.rawResult_); conn_ = obj.conn_; @@ -42,7 +42,7 @@ QueryResults &QueryResults::operator=(QueryResults &&obj) noexcept { return *this; } -QueryResults::QueryResults(net::cproto::ClientConnection *conn, NsArray &&nsArray, Completion cmpl, int fetchFlags, int fetchAmount, +QueryResults::QueryResults(net::cproto::ClientConnection* conn, NsArray&& nsArray, Completion cmpl, int fetchFlags, int fetchAmount, seconds timeout) : conn_(conn), nsArray_(std::move(nsArray)), @@ -53,7 +53,7 @@ QueryResults::QueryResults(net::cproto::ClientConnection *conn, NsArray &&nsArra requestTimeout_(timeout), cmpl_(std::move(cmpl)) {} -QueryResults::QueryResults(net::cproto::ClientConnection *conn, NsArray &&nsArray, Completion cmpl, std::string_view rawResult, int queryID, +QueryResults::QueryResults(net::cproto::ClientConnection* conn, NsArray&& nsArray, Completion cmpl, std::string_view rawResult, int queryID, int fetchFlags, int fetchAmount, seconds timeout) : QueryResults(conn, std::move(nsArray), std::move(cmpl), fetchFlags, fetchAmount, timeout) { Bind(rawResult, queryID); @@ -85,7 +85,7 @@ void QueryResults::Bind(std::string_view rawResult, int queryID) { PayloadType("tmp").clone()->deserialize(ser); }, ResultSerializer::AggsFlag::ClearAggregations); - } catch (const Error &err) { + } catch (const Error& err) { status_ = err; } @@ -116,7 +116,9 @@ void QueryResults::fetchNextResults() { h_vector QueryResults::GetNamespaces() const { h_vector ret; ret.reserve(nsArray_.size()); - for (auto &ns : nsArray_) ret.push_back(ns->name_); + for (auto& ns : nsArray_) { + ret.push_back(ns->name_); + } return ret; } @@ -128,14 +130,14 @@ TagsMatcher QueryResults::getTagsMatcher(int nsid) const { class AdditionalRank : public IAdditionalDatasource { public: AdditionalRank(double r) noexcept : rank_(r) {} - void PutAdditionalFields(JsonBuilder &builder) const override final { builder.Put("rank()", rank_); } - IEncoderDatasourceWithJoins *GetJoinsDatasource() noexcept override final { return nullptr; } + void PutAdditionalFields(JsonBuilder& builder) const override final { builder.Put("rank()", rank_); } + IEncoderDatasourceWithJoins* GetJoinsDatasource() noexcept override final { return nullptr; } private: double rank_; }; -void QueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSerializer &wrser, bool withHdrLen) { +void QueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSerializer& wrser, bool withHdrLen) { auto tm = qr_->getTagsMatcher(itemParams_.nsid); JsonEncoder enc(&tm); JsonBuilder builder(wrser, ObjType::TypePlain); @@ -157,7 +159,7 @@ void QueryResults::Iterator::getJSONFromCJSON(std::string_view cjson, WrSerializ } } -Error QueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { +Error QueryResults::Iterator::GetMsgPack(WrSerializer& wrser, bool withHdrLen) { readNext(); int type = qr_->queryParams_.flags & kResultsFormatMask; if (type == kResultsMsgPack) { @@ -172,7 +174,7 @@ Error QueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { return errOK; } -Error QueryResults::Iterator::GetJSON(WrSerializer &wrser, bool withHdrLen) { +Error QueryResults::Iterator::GetJSON(WrSerializer& wrser, bool withHdrLen) { readNext(); try { switch (qr_->queryParams_.flags & kResultsFormatMask) { @@ -190,13 +192,13 @@ Error QueryResults::Iterator::GetJSON(WrSerializer &wrser, bool withHdrLen) { default: return Error(errParseBin, "Server returned data in unknown format %d", qr_->queryParams_.flags & kResultsFormatMask); } - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; } -Error QueryResults::Iterator::GetCJSON(WrSerializer &wrser, bool withHdrLen) { +Error QueryResults::Iterator::GetCJSON(WrSerializer& wrser, bool withHdrLen) { readNext(); try { switch (qr_->queryParams_.flags & kResultsFormatMask) { @@ -213,7 +215,7 @@ Error QueryResults::Iterator::GetCJSON(WrSerializer &wrser, bool withHdrLen) { default: return Error(errParseBin, "Server returned data in unknown format %d", qr_->queryParams_.flags & kResultsFormatMask); } - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; @@ -239,7 +241,7 @@ Item QueryResults::Iterator::GetItem() { break; } case kResultsJson: { - char *endp = nullptr; + char* endp = nullptr; err = item.FromJSON(itemParams_.data, &endp); break; } @@ -250,7 +252,7 @@ Item QueryResults::Iterator::GetItem() { return item; } return Item(); - } catch (const Error &) { + } catch (const Error&) { return Item(); } } @@ -272,7 +274,9 @@ std::string_view QueryResults::Iterator::GetRaw() { } void QueryResults::Iterator::readNext() { - if (nextPos_ != 0) return; + if (nextPos_ != 0) { + return; + } std::string_view rawResult(qr_->rawResult_.data(), qr_->rawResult_.size()); @@ -285,12 +289,12 @@ void QueryResults::Iterator::readNext() { (void)joinedCnt; } nextPos_ = pos_ + ser.Pos(); - } catch (const Error &err) { - const_cast(qr_)->status_ = err; + } catch (const Error& err) { + const_cast(qr_)->status_ = err; } } -QueryResults::Iterator &QueryResults::Iterator::operator++() { +QueryResults::Iterator& QueryResults::Iterator::operator++() { try { readNext(); idx_++; @@ -298,11 +302,11 @@ QueryResults::Iterator &QueryResults::Iterator::operator++() { nextPos_ = 0; if (idx_ != qr_->queryParams_.qcount && idx_ == qr_->queryParams_.count + qr_->fetchOffset_) { - const_cast(qr_)->fetchNextResults(); + const_cast(qr_)->fetchNextResults(); pos_ = 0; } - } catch (const Error &err) { - const_cast(qr_)->status_ = err; + } catch (const Error& err) { + const_cast(qr_)->status_ = err; } return *this; diff --git a/cpp_src/client/reindexer.cc b/cpp_src/client/reindexer.cc index a23dc0d8f..f69a35959 100644 --- a/cpp_src/client/reindexer.cc +++ b/cpp_src/client/reindexer.cc @@ -49,12 +49,8 @@ Error Reindexer::GetMeta(std::string_view nsName, const std::string& key, std::s Error Reindexer::PutMeta(std::string_view nsName, const std::string& key, std::string_view data) { return impl_->PutMeta(nsName, key, data, ctx_); } -Error Reindexer::EnumMeta(std::string_view nsName, std::vector& keys) { - return impl_->EnumMeta(nsName, keys, ctx_); -} -Error Reindexer::DeleteMeta(std::string_view nsName, const std::string& key) { - return impl_->DeleteMeta(nsName, key, ctx_); -} +Error Reindexer::EnumMeta(std::string_view nsName, std::vector& keys) { return impl_->EnumMeta(nsName, keys, ctx_); } +Error Reindexer::DeleteMeta(std::string_view nsName, const std::string& key) { return impl_->DeleteMeta(nsName, key, ctx_); } Error Reindexer::Delete(const Query& q, QueryResults& result) { return impl_->Delete(q, result, ctx_); } Error Reindexer::Select(std::string_view query, QueryResults& result) { return impl_->Select(query, result, ctx_, nullptr); } Error Reindexer::Select(const Query& q, QueryResults& result) { return impl_->Select(q, result, ctx_, nullptr); } diff --git a/cpp_src/client/reindexer.h b/cpp_src/client/reindexer.h index 7ec39e8e0..088f9db25 100644 --- a/cpp_src/client/reindexer.h +++ b/cpp_src/client/reindexer.h @@ -29,25 +29,25 @@ class RPCClient; class Reindexer { public: /// Completion routine - typedef std::function Completion; + typedef std::function Completion; /// Create Reindexer database object - Reindexer(const ReindexerConfig & = ReindexerConfig()); + Reindexer(const ReindexerConfig& = ReindexerConfig()); /// Destroy Reindexer database object ~Reindexer(); - Reindexer(const Reindexer &) = delete; - Reindexer(Reindexer &&) noexcept; - Reindexer &operator=(const Reindexer &) = delete; - Reindexer &operator=(Reindexer &&) noexcept; + Reindexer(const Reindexer&) = delete; + Reindexer(Reindexer&&) noexcept; + Reindexer& operator=(const Reindexer&) = delete; + Reindexer& operator=(Reindexer&&) noexcept; /// Connect - connect to reindexer server /// @param dsn - uri of server and database, like: `cproto://user@password:127.0.0.1:6534/dbname` or /// `ucproto://user@password:/tmp/reindexer.sock:/dbname` /// @param opts - Connect options. May contain any of
- Error Connect(const std::string &dsn, const client::ConnectOpts &opts = client::ConnectOpts()); + Error Connect(const std::string& dsn, const client::ConnectOpts& opts = client::ConnectOpts()); /// Connect - connect to reindexer server /// @param connectData - list of server dsn + it's ConnectOpts - Error Connect(const std::vector> &connectData); + Error Connect(const std::vector>& connectData); /// Stop - shutdown connector void Stop(); /// Open or create namespace @@ -56,10 +56,10 @@ class Reindexer { /// StorageOpts::Enabled() - Enable storage. If storage is disabled, then namespace will be completely in-memory
/// StorageOpts::CreateIfMissing () - Storage will be created, if missing /// @return errOK - On success - Error OpenNamespace(std::string_view nsName, const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); + Error OpenNamespace(std::string_view nsName, const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); /// Create new namespace. Will fail, if namespace already exists /// @param nsDef - NamespaceDef with namespace initial parameters - Error AddNamespace(const NamespaceDef &nsDef); + Error AddNamespace(const NamespaceDef& nsDef); /// Close namespace. Will free all memory resources, associated with namespace. Forces sync changes to disk /// @param nsName - Name of namespace Error CloseNamespace(std::string_view nsName); @@ -72,19 +72,19 @@ class Reindexer { /// Rename namespace. If namespace with dstNsName exists, then it is replaced. /// @param srcNsName - Name of namespace /// @param dstNsName - desired name of namespace - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName); /// Add index to namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error AddIndex(std::string_view nsName, const IndexDef &index); + Error AddIndex(std::string_view nsName, const IndexDef& index); /// Update index in namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error UpdateIndex(std::string_view nsName, const IndexDef &index); + Error UpdateIndex(std::string_view nsName, const IndexDef& index); /// Drop index from namespace /// @param nsName - Name of namespace /// @param index - index name - Error DropIndex(std::string_view nsName, const IndexDef &index); + Error DropIndex(std::string_view nsName, const IndexDef& index); /// Set fields schema for namespace /// @param nsName - Name of namespace /// @param schema - JSON in JsonSchema format @@ -92,50 +92,50 @@ class Reindexer { /// Get list of all available namespaces /// @param defs - std::vector of NamespaceDef of available namespaces /// @param opts - Enumeration options - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts); /// Gets a list of available databases for a certain server. /// @param dbList - list of DB names - Error EnumDatabases(std::vector &dbList); + Error EnumDatabases(std::vector& dbList); /// Insert new Item to namespace. If item with same PK is already exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Insert(std::string_view nsName, Item &item); + Error Insert(std::string_view nsName, Item& item); /// Update Item in namespace. If item with same PK is not exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Update(std::string_view nsName, Item &item); + Error Update(std::string_view nsName, Item& item); /// Update or Insert Item in namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Upsert(std::string_view nsName, Item &item); + Error Upsert(std::string_view nsName, Item& item); /// Updates all items in namespace, that satisfy provided query. /// @param query - Query to define items set for update. /// @param result - QueryResults with IDs of deleted items. - Error Update(const Query &query, QueryResults &result); + Error Update(const Query& query, QueryResults& result); /// Delete Item from namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Delete(std::string_view nsName, Item &item); + Error Delete(std::string_view nsName, Item& item); /// Delete all items from namespace, which matches provided Query /// @param query - Query with conditions /// @param result - QueryResults with IDs of deleted items - Error Delete(const Query &query, QueryResults &result); + Error Delete(const Query& query, QueryResults& result); /// Execute SQL Query and return results /// May be used with completion /// @param query - SQL query. Only "SELECT" semantic is supported /// @param result - QueryResults with found items - Error Select(std::string_view query, QueryResults &result); + Error Select(std::string_view query, QueryResults& result); /// Execute Query and return results /// May be used with completion /// @param query - Query object with query attributes /// @param result - QueryResults with found items - Error Select(const Query &query, QueryResults &result); + Error Select(const Query& query, QueryResults& result); /// Flush changes to storage /// @param nsName - Name of namespace Error Commit(std::string_view nsName); @@ -147,34 +147,34 @@ class Reindexer { /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - output string with metadata - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data); /// Put metadata to storage by key /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - string with metadata - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data); /// Get list of all metadata keys /// @param nsName - Name of namespace /// @param keys - std::vector filled with meta keys - Error EnumMeta(std::string_view nsName, std::vector &keys); + Error EnumMeta(std::string_view nsName, std::vector& keys); /// Delete metadata from storage by key /// @param nsName - Name of namespace /// @param key - string with meta key - Error DeleteMeta(std::string_view nsName, const std::string &key); + Error DeleteMeta(std::string_view nsName, const std::string& key); /// Subscribe to updates of database /// @param observer - Observer interface, which will receive updates /// @param filters - Subscription filters set /// @param opts - Subscription options (allows to either add new filters or reset them) - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts = SubscriptionOpts()); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts = SubscriptionOpts()); /// Unsubscribe from updates of database /// Cancellation context doesn't affect this call /// @param observer - Observer interface, which will be unsubscribed updates - Error UnsubscribeUpdates(IUpdatesObserver *observer); + Error UnsubscribeUpdates(IUpdatesObserver* observer); /// Get possible suggestions for token (set by 'pos') in Sql query. /// @param sqlQuery - sql query. /// @param pos - position in sql query for suggestions. /// @param suggestions - all the suggestions for 'pos' position in query. - Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector &suggestions); + Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector& suggestions); /// Get current connection status Error Status(); /// Allocate new transaction for namespace @@ -182,14 +182,14 @@ class Reindexer { Transaction NewTransaction(std::string_view nsName); /// Commit transaction - transaction will be deleted after commit /// @param tr - transaction to commit - Error CommitTransaction(Transaction &tr); + Error CommitTransaction(Transaction& tr); /// RollBack transaction - transaction will be deleted after rollback /// @param tr - transaction to rollback - Error RollBackTransaction(Transaction &tr); + Error RollBackTransaction(Transaction& tr); /// Add cancelable context /// @param cancelCtx - context pointer - Reindexer WithContext(const IRdxCancelContext *cancelCtx) { return Reindexer(impl_, ctx_.WithCancelContext(cancelCtx)); } + Reindexer WithContext(const IRdxCancelContext* cancelCtx) { return Reindexer(impl_, ctx_.WithCancelContext(cancelCtx)); } /// Add execution timeout to the next query /// @param timeout - Optional server-side execution timeout for each subquery @@ -202,8 +202,8 @@ class Reindexer { typedef Item ItemT; private: - Reindexer(RPCClient *impl, InternalRdxContext &&ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} - RPCClient *impl_; + Reindexer(RPCClient* impl, InternalRdxContext&& ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} + RPCClient* impl_; bool owner_; InternalRdxContext ctx_; }; diff --git a/cpp_src/client/resultserializer.cc b/cpp_src/client/resultserializer.cc index 110ae75ea..9671281de 100644 --- a/cpp_src/client/resultserializer.cc +++ b/cpp_src/client/resultserializer.cc @@ -30,7 +30,9 @@ void ResultSerializer::GetRawQueryParams(ResultSerializer::QueryParams& ret, con bool firstAgg = true; for (;;) { int tag = GetVarUint(); - if (tag == QueryResultEnd) break; + if (tag == QueryResultEnd) { + break; + } if ((clearAggs == AggsFlag::DontClearAggregations) && firstAgg) { firstAgg = false; ret.aggResults.clear(); diff --git a/cpp_src/client/rpcclient.cc b/cpp_src/client/rpcclient.cc index 92fe71f7d..d7747af15 100644 --- a/cpp_src/client/rpcclient.cc +++ b/cpp_src/client/rpcclient.cc @@ -30,7 +30,9 @@ Error RPCClient::startWorkers() { connections_.resize(config_.ConnPoolSize); for (size_t i = 0; i < workers_.size(); i++) { workers_[i].thread_ = std::thread([this](size_t id) { this->run(id); }, i); - while (!workers_[i].running) std::this_thread::sleep_for(std::chrono::milliseconds(10)); + while (!workers_[i].running) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } } return errOK; } @@ -57,7 +59,9 @@ Error RPCClient::Connect(const std::string& dsn, const client::ConnectOpts& opts std::vector tmpConnectData(1); connectData_.entries.swap(tmpConnectData); Error err = addConnectEntry(dsn, opts, 0); - if (err.ok()) return startWorkers(); + if (err.ok()) { + return startWorkers(); + } return err; } @@ -72,13 +76,17 @@ Error RPCClient::Connect(const std::vectorCall(mkCommand(cproto::kCmdOpenNamespace, &ctx), ser.Slice()).Status(); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } std::unique_lock lock(nsMutex_); namespaces_.emplace(nsDef.name, Namespace::Ptr(new Namespace(nsDef.name))); @@ -166,7 +178,9 @@ Error RPCClient::TruncateNamespace(std::string_view nsName, const InternalRdxCon Error RPCClient::RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx) { auto status = getConn()->Call(mkCommand(cproto::kCmdRenameNamespace, &ctx), srcNsName, dstNsName).Status(); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } if (srcNsName != dstNsName) { std::unique_lock lock(nsMutex_); @@ -223,7 +237,9 @@ Error RPCClient::modifyItem(std::string_view nsName, Item& item, int mode, secon auto ret = conn->Call(mkCommand(cproto::kCmdModifyItem, netTimeout, &ctx), nsName, int(FormatCJson), item.GetCJSON(), mode, ser.Slice(), item.GetStateToken(), 0); if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated || tryCount > 2) return ret.Status(); + if (ret.Status().code() != errStateInvalidated || tryCount > 2) { + return ret.Status(); + } if (withNetTimeout) { netTimeout = netDeadline - conn->Now(); } @@ -239,7 +255,9 @@ Error RPCClient::modifyItem(std::string_view nsName, Item& item, int mode, secon auto newItem = NewItem(nsName); char* endp = nullptr; Error err = newItem.FromJSON(item.impl_->GetJSON(), &endp); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } item = std::move(newItem); continue; @@ -265,14 +283,18 @@ Error RPCClient::modifyItemAsync(std::string_view nsName, Item* item, int mode, ser.PutVString(p); } } - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } std::string ns(nsName); auto deadline = netTimeout.count() ? conn->Now() + netTimeout : seconds(0); conn->Call( [this, ns, mode, item, deadline, ctx](const net::cproto::RPCAnswer& ret, cproto::ClientConnection* conn) -> void { if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated) return ctx.cmpl()(ret.Status()); + if (ret.Status().code() != errStateInvalidated) { + return ctx.cmpl()(ret.Status()); + } seconds netTimeout(0); if (deadline.count()) { netTimeout = deadline - conn->Now(); @@ -281,7 +303,9 @@ Error RPCClient::modifyItemAsync(std::string_view nsName, Item* item, int mode, QueryResults* qr = new QueryResults; InternalRdxContext ctxCmpl = ctx.WithCompletion([=](const Error& ret) { delete qr; - if (!ret.ok()) return ctx.cmpl()(ret); + if (!ret.ok()) { + return ctx.cmpl()(ret); + } seconds timeout(0); if (deadline.count()) { @@ -291,15 +315,21 @@ Error RPCClient::modifyItemAsync(std::string_view nsName, Item* item, int mode, // Rebuild item with new state auto newItem = NewItem(ns); Error err = newItem.FromJSON(item->impl_->GetJSON()); - if (err.ok()) return ctx.cmpl()(err); + if (err.ok()) { + return ctx.cmpl()(err); + } newItem.SetPrecepts(item->impl_->GetPrecepts()); *item = std::move(newItem); err = modifyItemAsync(ns, item, mode, conn, timeout, ctx); - if (err.ok()) return ctx.cmpl()(err); + if (err.ok()) { + return ctx.cmpl()(err); + } }); auto err = selectImpl(Query(ns).Limit(0), *qr, conn, netTimeout, ctxCmpl); - if (err.ok()) return ctx.cmpl()(err); - } else + if (err.ok()) { + return ctx.cmpl()(err); + } + } else { try { auto args = ret.GetArgs(2); ctx.cmpl()(QueryResults(conn, {getNamespace(ns)}, nullptr, p_string(args[0]), int(args[1]), 0, config_.FetchAmount, @@ -308,6 +338,7 @@ Error RPCClient::modifyItemAsync(std::string_view nsName, Item* item, int mode, } catch (const Error& err) { ctx.cmpl()(err); } + } }, mkCommand(cproto::kCmdModifyItem, netTimeout, &ctx), ns, int(FormatCJson), item->GetCJSON(), mode, ser.Slice(), item->GetStateToken(), 0); @@ -447,7 +478,9 @@ Error RPCClient::selectImpl(std::string_view query, QueryResults& result, cproto h_vector vers; vec2pack(vers, pser); - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } result = QueryResults(conn, {}, ctx.cmpl(), result.fetchFlags_, config_.FetchAmount, config_.RequestTimeout); @@ -501,7 +534,9 @@ Error RPCClient::selectImpl(const Query& query, QueryResults& result, cproto::Cl } vec2pack(vers, pser); - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } result = QueryResults(conn, std::move(nsArray), ctx.cmpl(), result.fetchFlags_, config_.FetchAmount, config_.RequestTimeout); @@ -610,7 +645,9 @@ Error RPCClient::GetSqlSuggestions(std::string_view query, int pos, std::vector< suggests.clear(); suggests.reserve(rargs.size()); - for (auto& rarg : rargs) suggests.push_back(rarg.As()); + for (auto& rarg : rargs) { + suggests.push_back(rarg.As()); + } } return ret.Status(); } catch (const Error& err) { @@ -709,7 +746,9 @@ void RPCClient::onUpdates(net::cproto::RPCAnswer& ans, cproto::ClientConnection* std::string_view nsName(args[1]); std::string_view pwalRec(args[2]); lsn_t originLSN; - if (args.size() >= 4) originLSN = lsn_t(args[3].As()); + if (args.size() >= 4) { + originLSN = lsn_t(args[3].As()); + } WALRecord wrec(pwalRec); if (wrec.type == WalItemModify) { @@ -759,7 +798,9 @@ void RPCClient::onUpdates(net::cproto::RPCAnswer& ans, cproto::ClientConnection* serialDelays_ = 0; observers_.OnUpdatesLost(nsName); } else { - for (auto& a1 : uq) onUpdates(a1, conn); + for (auto& a1 : uq) { + onUpdates(a1, conn); + } } }), conn); @@ -799,8 +840,12 @@ void RPCClient::onUpdates(net::cproto::RPCAnswer& ans, cproto::ClientConnection* } bool RPCClient::onConnectionFail(int failedDsnIndex) { - if (!connectData_.ThereAreReconnectOptions()) return false; - if (!connectData_.CurrDsnFailed(failedDsnIndex)) return false; + if (!connectData_.ThereAreReconnectOptions()) { + return false; + } + if (!connectData_.CurrDsnFailed(failedDsnIndex)) { + return false; + } connectData_.lastFailedEntryIdx = failedDsnIndex; connectData_.validEntryIdx.store(connectData_.GetNextDsnIndex(), std::memory_order_release); diff --git a/cpp_src/client/rpcclient.h b/cpp_src/client/rpcclient.h index 349cba590..748a2c2bc 100644 --- a/cpp_src/client/rpcclient.h +++ b/cpp_src/client/rpcclient.h @@ -29,57 +29,57 @@ using std::chrono::seconds; using namespace net; class RPCClient { public: - typedef std::function Completion; - RPCClient(const ReindexerConfig &config); - RPCClient(const RPCClient &) = delete; - RPCClient(RPCClient &&) = delete; - RPCClient &operator=(const RPCClient &) = delete; - RPCClient &operator=(RPCClient &&) = delete; + typedef std::function Completion; + RPCClient(const ReindexerConfig& config); + RPCClient(const RPCClient&) = delete; + RPCClient(RPCClient&&) = delete; + RPCClient& operator=(const RPCClient&) = delete; + RPCClient& operator=(RPCClient&&) = delete; ~RPCClient(); - Error Connect(const std::string &dsn, const client::ConnectOpts &opts); - Error Connect(const std::vector> &connectData); + Error Connect(const std::string& dsn, const client::ConnectOpts& opts); + Error Connect(const std::vector>& connectData); void Stop(); - Error OpenNamespace(std::string_view nsName, const InternalRdxContext &ctx, - const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); - Error AddNamespace(const NamespaceDef &nsDef, const InternalRdxContext &ctx); - Error CloseNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error DropNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error TruncateNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName, const InternalRdxContext &ctx); - Error AddIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error UpdateIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error DropIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext &ctx); - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts, const InternalRdxContext &ctx); - Error EnumDatabases(std::vector &dbList, const InternalRdxContext &ctx); - Error Insert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Update(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Upsert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Delete(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx); - Error Delete(const Query &query, QueryResults &result, const InternalRdxContext &ctx); - Error Update(const Query &query, QueryResults &result, const InternalRdxContext &ctx); - Error Select(std::string_view query, QueryResults &result, const InternalRdxContext &ctx, cproto::ClientConnection *conn = nullptr) { + Error OpenNamespace(std::string_view nsName, const InternalRdxContext& ctx, + const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); + Error AddNamespace(const NamespaceDef& nsDef, const InternalRdxContext& ctx); + Error CloseNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error DropNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error TruncateNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx); + Error AddIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error UpdateIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error DropIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext& ctx); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts, const InternalRdxContext& ctx); + Error EnumDatabases(std::vector& dbList, const InternalRdxContext& ctx); + Error Insert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Update(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Upsert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Delete(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx); + Error Delete(const Query& query, QueryResults& result, const InternalRdxContext& ctx); + Error Update(const Query& query, QueryResults& result, const InternalRdxContext& ctx); + Error Select(std::string_view query, QueryResults& result, const InternalRdxContext& ctx, cproto::ClientConnection* conn = nullptr) { return selectImpl(query, result, conn, config_.RequestTimeout, ctx); } - Error Select(const Query &query, QueryResults &result, const InternalRdxContext &ctx, cproto::ClientConnection *conn = nullptr) { + Error Select(const Query& query, QueryResults& result, const InternalRdxContext& ctx, cproto::ClientConnection* conn = nullptr) { return selectImpl(query, result, conn, config_.RequestTimeout, ctx); } Error Commit(std::string_view nsName); Item NewItem(std::string_view nsName); - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data, const InternalRdxContext &ctx); - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data, const InternalRdxContext &ctx); - Error EnumMeta(std::string_view nsName, std::vector &keys, const InternalRdxContext &ctx); - Error DeleteMeta(std::string_view nsName, const std::string &key, const InternalRdxContext &ctx); - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts = SubscriptionOpts()); - Error UnsubscribeUpdates(IUpdatesObserver *observer); - Error GetSqlSuggestions(std::string_view query, int pos, std::vector &suggests); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data, const InternalRdxContext& ctx); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data, const InternalRdxContext& ctx); + Error EnumMeta(std::string_view nsName, std::vector& keys, const InternalRdxContext& ctx); + Error DeleteMeta(std::string_view nsName, const std::string& key, const InternalRdxContext& ctx); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts = SubscriptionOpts()); + Error UnsubscribeUpdates(IUpdatesObserver* observer); + Error GetSqlSuggestions(std::string_view query, int pos, std::vector& suggests); Error Status(); - Transaction NewTransaction(std::string_view nsName, const InternalRdxContext &ctx); - Error CommitTransaction(Transaction &tr, const InternalRdxContext &ctx); - Error RollBackTransaction(Transaction &tr, const InternalRdxContext &ctx); + Transaction NewTransaction(std::string_view nsName, const InternalRdxContext& ctx); + Error CommitTransaction(Transaction& tr, const InternalRdxContext& ctx); + Error RollBackTransaction(Transaction& tr, const InternalRdxContext& ctx); protected: struct worker { @@ -90,26 +90,26 @@ class RPCClient { std::atomic_bool running; }; - Error selectImpl(std::string_view query, QueryResults &result, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx); - Error selectImpl(const Query &query, QueryResults &result, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx); - Error modifyItem(std::string_view nsName, Item &item, int mode, seconds netTimeout, const InternalRdxContext &ctx); - Error modifyItemAsync(std::string_view nsName, Item *item, int mode, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx); + Error selectImpl(std::string_view query, QueryResults& result, cproto::ClientConnection*, seconds netTimeout, + const InternalRdxContext& ctx); + Error selectImpl(const Query& query, QueryResults& result, cproto::ClientConnection*, seconds netTimeout, + const InternalRdxContext& ctx); + Error modifyItem(std::string_view nsName, Item& item, int mode, seconds netTimeout, const InternalRdxContext& ctx); + Error modifyItemAsync(std::string_view nsName, Item* item, int mode, cproto::ClientConnection*, seconds netTimeout, + const InternalRdxContext& ctx); Error subscribeImpl(bool subscribe); - Namespace *getNamespace(std::string_view nsName); + Namespace* getNamespace(std::string_view nsName); Error startWorkers(); - Error addConnectEntry(const std::string &dsn, const client::ConnectOpts &opts, size_t idx); + Error addConnectEntry(const std::string& dsn, const client::ConnectOpts& opts, size_t idx); void run(size_t thIdx); - void onUpdates(net::cproto::RPCAnswer &ans, cproto::ClientConnection *conn); + void onUpdates(net::cproto::RPCAnswer& ans, cproto::ClientConnection* conn); bool onConnectionFail(int failedDsnIndex); void checkSubscribes(); - net::cproto::ClientConnection *getConn(); - cproto::CommandParams mkCommand(cproto::CmdCode cmd, const InternalRdxContext *ctx = nullptr) const noexcept; - static cproto::CommandParams mkCommand(cproto::CmdCode cmd, seconds reqTimeout, const InternalRdxContext *ctx) noexcept; + net::cproto::ClientConnection* getConn(); + cproto::CommandParams mkCommand(cproto::CmdCode cmd, const InternalRdxContext* ctx = nullptr) const noexcept; + static cproto::CommandParams mkCommand(cproto::CmdCode cmd, seconds reqTimeout, const InternalRdxContext* ctx) noexcept; std::vector> connections_; @@ -120,13 +120,13 @@ class RPCClient { std::atomic curConnIdx_; ReindexerConfig config_; UpdatesObservers observers_; - std::atomic updatesConn_; + std::atomic updatesConn_; std::vector delayedUpdates_; uint64_t serialDelays_ = 0; cproto::ClientConnection::ConnectData connectData_; }; -void vec2pack(const h_vector &vec, WrSerializer &ser); +void vec2pack(const h_vector& vec, WrSerializer& ser); } // namespace client } // namespace reindexer diff --git a/cpp_src/client/rpcclientmock.cc b/cpp_src/client/rpcclientmock.cc index 275414551..7b6bd9e58 100644 --- a/cpp_src/client/rpcclientmock.cc +++ b/cpp_src/client/rpcclientmock.cc @@ -54,7 +54,9 @@ Error RPCClientMock::Delete(const Query& query, QueryResults& result, const Inte }; int flags = kResultsWithItemID; - if (outputFormat == FormatMsgPack) flags |= kResultsMsgPack; + if (outputFormat == FormatMsgPack) { + flags |= kResultsMsgPack; + } auto ret = conn->Call(mkCommand(cproto::kCmdDeleteQuery, &ctx), ser.Slice(), flags); icompl(ret, conn); return ret.Status(); @@ -132,7 +134,9 @@ Error RPCClientMock::modifyItem(std::string_view nsName, Item& item, int mode, s auto ret = conn->Call(mkCommand(cproto::kCmdModifyItem, netTimeout, &ctx), nsName, format, data, mode, ser.Slice(), item.GetStateToken(), 0); if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated || tryCount > 2) return ret.Status(); + if (ret.Status().code() != errStateInvalidated || tryCount > 2) { + return ret.Status(); + } if (withNetTimeout) { netTimeout = netDeadline - conn->Now(); } @@ -148,7 +152,9 @@ Error RPCClientMock::modifyItem(std::string_view nsName, Item& item, int mode, s auto newItem = NewItem(nsName); char* endp = nullptr; Error err = newItem.FromJSON(item.impl_->GetJSON(), &endp); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } item = std::move(newItem); continue; @@ -174,7 +180,9 @@ Error RPCClientMock::modifyItemAsync(std::string_view nsName, Item* item, int mo ser.PutVString(p); } } - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } std::string_view data; switch (format) { @@ -196,7 +204,9 @@ Error RPCClientMock::modifyItemAsync(std::string_view nsName, Item* item, int mo conn->Call( [this, ns, mode, item, deadline, ctx, format](const net::cproto::RPCAnswer& ret, cproto::ClientConnection* conn) -> void { if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated) return ctx.cmpl()(ret.Status()); + if (ret.Status().code() != errStateInvalidated) { + return ctx.cmpl()(ret.Status()); + } seconds netTimeout(0); if (deadline.count()) { netTimeout = deadline - conn->Now(); @@ -205,7 +215,9 @@ Error RPCClientMock::modifyItemAsync(std::string_view nsName, Item* item, int mo QueryResults* qr = new QueryResults; InternalRdxContext ctxCmpl = ctx.WithCompletion([=](const Error& ret) { delete qr; - if (!ret.ok()) return ctx.cmpl()(ret); + if (!ret.ok()) { + return ctx.cmpl()(ret); + } seconds timeout(0); if (deadline.count()) { @@ -215,15 +227,21 @@ Error RPCClientMock::modifyItemAsync(std::string_view nsName, Item* item, int mo // Rebuild item with new state auto newItem = NewItem(ns); Error err = newItem.FromJSON(item->impl_->GetJSON()); - if (!err.ok()) return ctx.cmpl()(ret); + if (!err.ok()) { + return ctx.cmpl()(ret); + } newItem.SetPrecepts(item->impl_->GetPrecepts()); *item = std::move(newItem); err = modifyItemAsync(ns, item, mode, conn, timeout, ctx, format); - if (!err.ok()) return ctx.cmpl()(ret); + if (!err.ok()) { + return ctx.cmpl()(ret); + } }); auto err = selectImpl(Query(ns).Limit(0), *qr, conn, netTimeout, ctxCmpl, format); - if (err.ok()) return ctx.cmpl()(err); - } else + if (err.ok()) { + return ctx.cmpl()(err); + } + } else { try { auto args = ret.GetArgs(2); ctx.cmpl()(QueryResults(conn, {getNamespace(ns)}, nullptr, p_string(args[0]), int(args[1]), 0, config_.FetchAmount, @@ -232,6 +250,7 @@ Error RPCClientMock::modifyItemAsync(std::string_view nsName, Item* item, int mo } catch (const Error& err) { ctx.cmpl()(err); } + } }, mkCommand(cproto::kCmdModifyItem, netTimeout, &ctx), ns, format, data, mode, ser.Slice(), item->GetStateToken(), 0); return errOK; @@ -250,7 +269,9 @@ Error RPCClientMock::selectImpl(std::string_view query, QueryResults& result, cp h_vector vers; vec2pack(vers, pser); - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } result = QueryResults(conn, {}, ctx.cmpl(), result.fetchFlags_, config_.FetchAmount, config_.RequestTimeout); @@ -316,7 +337,9 @@ Error RPCClientMock::selectImpl(const Query& query, QueryResults& result, cproto } vec2pack(vers, pser); - if (!conn) conn = getConn(); + if (!conn) { + conn = getConn(); + } result = QueryResults(conn, std::move(nsArray), ctx.cmpl(), result.fetchFlags_, config_.FetchAmount, config_.RequestTimeout); diff --git a/cpp_src/client/rpcclientmock.h b/cpp_src/client/rpcclientmock.h index b3c72f192..1a11cc485 100644 --- a/cpp_src/client/rpcclientmock.h +++ b/cpp_src/client/rpcclientmock.h @@ -8,30 +8,30 @@ namespace client { class RPCClientMock : public RPCClient { public: - RPCClientMock(const ReindexerConfig &config = ReindexerConfig()); - Error Insert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Update(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Upsert(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Delete(std::string_view nsName, client::Item &item, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Delete(const Query &query, QueryResults &result, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Update(const Query &query, QueryResults &result, const InternalRdxContext &ctx, int outputFormat = FormatCJson); - Error Select(std::string_view query, QueryResults &result, const InternalRdxContext &ctx, cproto::ClientConnection *conn = nullptr, + RPCClientMock(const ReindexerConfig& config = ReindexerConfig()); + Error Insert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Update(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Upsert(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Delete(std::string_view nsName, client::Item& item, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Delete(const Query& query, QueryResults& result, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Update(const Query& query, QueryResults& result, const InternalRdxContext& ctx, int outputFormat = FormatCJson); + Error Select(std::string_view query, QueryResults& result, const InternalRdxContext& ctx, cproto::ClientConnection* conn = nullptr, int outputFormat = FormatCJson) { return selectImpl(query, result, conn, config_.RequestTimeout, ctx, outputFormat); } - Error Select(const Query &query, QueryResults &result, const InternalRdxContext &ctx, cproto::ClientConnection *conn = nullptr, + Error Select(const Query& query, QueryResults& result, const InternalRdxContext& ctx, cproto::ClientConnection* conn = nullptr, int outputFormat = FormatCJson) { return selectImpl(query, result, conn, config_.RequestTimeout, ctx, outputFormat); } private: - Error selectImpl(std::string_view query, QueryResults &result, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx, int outputFormat); - Error selectImpl(const Query &query, QueryResults &result, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx, int outputFormat); - Error modifyItem(std::string_view nsName, Item &item, int mode, seconds netTimeout, const InternalRdxContext &ctx, int format); - Error modifyItemAsync(std::string_view nsName, Item *item, int mode, cproto::ClientConnection *, seconds netTimeout, - const InternalRdxContext &ctx, int format); + Error selectImpl(std::string_view query, QueryResults& result, cproto::ClientConnection*, seconds netTimeout, + const InternalRdxContext& ctx, int outputFormat); + Error selectImpl(const Query& query, QueryResults& result, cproto::ClientConnection*, seconds netTimeout, const InternalRdxContext& ctx, + int outputFormat); + Error modifyItem(std::string_view nsName, Item& item, int mode, seconds netTimeout, const InternalRdxContext& ctx, int format); + Error modifyItemAsync(std::string_view nsName, Item* item, int mode, cproto::ClientConnection*, seconds netTimeout, + const InternalRdxContext& ctx, int format); }; } // namespace client diff --git a/cpp_src/client/synccoroqueryresults.cc b/cpp_src/client/synccoroqueryresults.cc index 14507bccc..8f573b562 100644 --- a/cpp_src/client/synccoroqueryresults.cc +++ b/cpp_src/client/synccoroqueryresults.cc @@ -8,7 +8,7 @@ namespace client { using namespace reindexer::net; -SyncCoroQueryResults::SyncCoroQueryResults(SyncCoroReindexer *rx, int fetchFlags) : results_(fetchFlags), rx_(rx) {} +SyncCoroQueryResults::SyncCoroQueryResults(SyncCoroReindexer* rx, int fetchFlags) : results_(fetchFlags), rx_(rx) {} void SyncCoroQueryResults::Bind(std::string_view rawResult, RPCQrId id) { results_.Bind(rawResult, id); } diff --git a/cpp_src/client/synccororeindexer.cc b/cpp_src/client/synccororeindexer.cc index 14f0c4343..630d49ade 100644 --- a/cpp_src/client/synccororeindexer.cc +++ b/cpp_src/client/synccororeindexer.cc @@ -47,12 +47,8 @@ Error SyncCoroReindexer::GetMeta(std::string_view nsName, const std::string& key Error SyncCoroReindexer::PutMeta(std::string_view nsName, const std::string& key, std::string_view data) { return impl_->PutMeta(nsName, key, data, ctx_); } -Error SyncCoroReindexer::EnumMeta(std::string_view nsName, std::vector& keys) { - return impl_->EnumMeta(nsName, keys, ctx_); -} -Error SyncCoroReindexer::DeleteMeta(std::string_view nsName, const std::string& key) { - return impl_->DeleteMeta(nsName, key, ctx_); -} +Error SyncCoroReindexer::EnumMeta(std::string_view nsName, std::vector& keys) { return impl_->EnumMeta(nsName, keys, ctx_); } +Error SyncCoroReindexer::DeleteMeta(std::string_view nsName, const std::string& key) { return impl_->DeleteMeta(nsName, key, ctx_); } Error SyncCoroReindexer::Delete(const Query& q, SyncCoroQueryResults& result) { return impl_->Delete(q, result, ctx_); } Error SyncCoroReindexer::Select(std::string_view query, SyncCoroQueryResults& result) { return impl_->Select(query, result, ctx_); } Error SyncCoroReindexer::Select(const Query& q, SyncCoroQueryResults& result) { return impl_->Select(q, result, ctx_); } diff --git a/cpp_src/client/synccororeindexer.h b/cpp_src/client/synccororeindexer.h index 7638dbb19..20c989c83 100644 --- a/cpp_src/client/synccororeindexer.h +++ b/cpp_src/client/synccororeindexer.h @@ -15,19 +15,19 @@ class SyncCoroReindexerImpl; class SyncCoroReindexer { public: /// Create Reindexer database object - SyncCoroReindexer(const ReindexerConfig & = ReindexerConfig()); - SyncCoroReindexer(SyncCoroReindexer &&rdx) noexcept; + SyncCoroReindexer(const ReindexerConfig& = ReindexerConfig()); + SyncCoroReindexer(SyncCoroReindexer&& rdx) noexcept; /// Destroy Reindexer database object ~SyncCoroReindexer(); - SyncCoroReindexer(const SyncCoroReindexer &) = delete; - SyncCoroReindexer &operator=(const SyncCoroReindexer &) = delete; - SyncCoroReindexer &operator=(SyncCoroReindexer &&rdx) noexcept; + SyncCoroReindexer(const SyncCoroReindexer&) = delete; + SyncCoroReindexer& operator=(const SyncCoroReindexer&) = delete; + SyncCoroReindexer& operator=(SyncCoroReindexer&& rdx) noexcept; /// Connect - connect to reindexer server /// @param dsn - uri of server and database, like: `cproto://user@password:127.0.0.1:6534/dbname` or /// `ucproto://user@password:/tmp/reindexer.sock:/dbname` /// @param opts - Connect options. May contain any of
- Error Connect(const std::string &dsn, const client::ConnectOpts &opts = client::ConnectOpts()); + Error Connect(const std::string& dsn, const client::ConnectOpts& opts = client::ConnectOpts()); /// Stop - shutdown connector Error Stop(); /// Open or create namespace @@ -36,10 +36,10 @@ class SyncCoroReindexer { /// StorageOpts::Enabled() - Enable storage. If storage is disabled, then namespace will be completely in-memory
/// StorageOpts::CreateIfMissing () - Storage will be created, if missing /// @return errOK - On success - Error OpenNamespace(std::string_view nsName, const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); + Error OpenNamespace(std::string_view nsName, const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); /// Create new namespace. Will fail, if namespace already exists /// @param nsDef - NamespaceDef with namespace initial parameters - Error AddNamespace(const NamespaceDef &nsDef); + Error AddNamespace(const NamespaceDef& nsDef); /// Close namespace. Will free all memory resources, associated with namespace. Forces sync changes to disk /// @param nsName - Name of namespace Error CloseNamespace(std::string_view nsName); @@ -52,19 +52,19 @@ class SyncCoroReindexer { /// Rename namespace. If namespace with dstNsName exists, then it is replaced. /// @param srcNsName - Name of namespace /// @param dstNsName - desired name of namespace - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName); /// Add index to namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error AddIndex(std::string_view nsName, const IndexDef &index); + Error AddIndex(std::string_view nsName, const IndexDef& index); /// Update index in namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error UpdateIndex(std::string_view nsName, const IndexDef &index); + Error UpdateIndex(std::string_view nsName, const IndexDef& index); /// Drop index from namespace /// @param nsName - Name of namespace /// @param index - index name - Error DropIndex(std::string_view nsName, const IndexDef &index); + Error DropIndex(std::string_view nsName, const IndexDef& index); /// Set fields schema for namespace /// @param nsName - Name of namespace /// @param schema - JSON in JsonSchema format @@ -72,50 +72,50 @@ class SyncCoroReindexer { /// Get list of all available namespaces /// @param defs - std::vector of NamespaceDef of available namespaces /// @param opts - Enumeration options - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts); /// Gets a list of available databases for a certain server. /// @param dbList - list of DB names - Error EnumDatabases(std::vector &dbList); + Error EnumDatabases(std::vector& dbList); /// Insert new Item to namespace. If item with same PK is already exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Insert(std::string_view nsName, Item &item); + Error Insert(std::string_view nsName, Item& item); /// Update Item in namespace. If item with same PK is not exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Update(std::string_view nsName, Item &item); + Error Update(std::string_view nsName, Item& item); /// Update or Insert Item in namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Upsert(std::string_view nsName, Item &item); + Error Upsert(std::string_view nsName, Item& item); /// Updates all items in namespace, that satisfy provided query. /// @param query - Query to define items set for update. /// @param result - QueryResults with IDs of deleted items. - Error Update(const Query &query, SyncCoroQueryResults &result); + Error Update(const Query& query, SyncCoroQueryResults& result); /// Delete Item from namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Delete(std::string_view nsName, Item &item); + Error Delete(std::string_view nsName, Item& item); /// Delete all items from namespace, which matches provided Query /// @param query - Query with conditions /// @param result - QueryResults with IDs of deleted items - Error Delete(const Query &query, SyncCoroQueryResults &result); + Error Delete(const Query& query, SyncCoroQueryResults& result); /// Execute SQL Query and return results /// May be used with completion /// @param query - SQL query. Only "SELECT" semantic is supported /// @param result - QueryResults with found items - Error Select(std::string_view query, SyncCoroQueryResults &result); + Error Select(std::string_view query, SyncCoroQueryResults& result); /// Execute SQL Query and return results /// May be used with completion /// @param query - Query object with query attributes /// @param result - QueryResults with found items - Error Select(const Query &query, SyncCoroQueryResults &result); + Error Select(const Query& query, SyncCoroQueryResults& result); /// Flush changes to storage /// @param nsName - Name of namespace @@ -128,25 +128,25 @@ class SyncCoroReindexer { /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - output string with metadata - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data); /// Put metadata to storage by key /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - string with metadata - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data); /// Get list of all metadata keys /// @param nsName - Name of namespace /// @param keys - std::vector filled with meta keys - Error EnumMeta(std::string_view nsName, std::vector &keys); + Error EnumMeta(std::string_view nsName, std::vector& keys); /// Delete metadata from storage by key /// @param nsName - Name of namespace /// @param key - string with meta key - Error DeleteMeta(std::string_view nsName, const std::string &key); + Error DeleteMeta(std::string_view nsName, const std::string& key); /// Get possible suggestions for token (set by 'pos') in Sql query. /// @param sqlQuery - sql query. /// @param pos - position in sql query for suggestions. /// @param suggestions - all the suggestions for 'pos' position in query. - Error GetSqlSuggestions(const std::string_view sqlQuery, int pos, std::vector &suggestions); + Error GetSqlSuggestions(const std::string_view sqlQuery, int pos, std::vector& suggestions); /// Get current connection status Error Status(); /// Allocate new transaction for namespace @@ -154,14 +154,14 @@ class SyncCoroReindexer { SyncCoroTransaction NewTransaction(std::string_view nsName); /// Commit transaction - transaction will be deleted after commit /// @param tr - transaction to commit - Error CommitTransaction(SyncCoroTransaction &tr); + Error CommitTransaction(SyncCoroTransaction& tr); /// RollBack transaction - transaction will be deleted after rollback /// @param tr - transaction to rollback - Error RollBackTransaction(SyncCoroTransaction &tr); + Error RollBackTransaction(SyncCoroTransaction& tr); /// Add cancelable context /// @param cancelCtx - context pointer - SyncCoroReindexer WithContext(const IRdxCancelContext *cancelCtx) { + SyncCoroReindexer WithContext(const IRdxCancelContext* cancelCtx) { return SyncCoroReindexer(impl_, ctx_.WithCancelContext(cancelCtx)); } @@ -174,8 +174,8 @@ class SyncCoroReindexer { private: friend SyncCoroQueryResults; - SyncCoroReindexer(SyncCoroReindexerImpl *impl, InternalRdxContext &&ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} - SyncCoroReindexerImpl *impl_; + SyncCoroReindexer(SyncCoroReindexerImpl* impl, InternalRdxContext&& ctx) : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} + SyncCoroReindexerImpl* impl_; bool owner_; InternalRdxContext ctx_; }; diff --git a/cpp_src/client/synccororeindexerimpl.cc b/cpp_src/client/synccororeindexerimpl.cc index 1aadb43d7..2d44e27cd 100644 --- a/cpp_src/client/synccororeindexerimpl.cc +++ b/cpp_src/client/synccororeindexerimpl.cc @@ -6,7 +6,7 @@ namespace client { using std::chrono::milliseconds; -SyncCoroReindexerImpl::SyncCoroReindexerImpl(const ReindexerConfig &conf) : conf_(conf) {} +SyncCoroReindexerImpl::SyncCoroReindexerImpl(const ReindexerConfig& conf) : conf_(conf) {} SyncCoroReindexerImpl::~SyncCoroReindexerImpl() { if (loopThread_->joinable()) { @@ -15,9 +15,11 @@ SyncCoroReindexerImpl::~SyncCoroReindexerImpl() { } } -Error SyncCoroReindexerImpl::Connect(const std::string &dsn, const client::ConnectOpts &opts) { +Error SyncCoroReindexerImpl::Connect(const std::string& dsn, const client::ConnectOpts& opts) { std::unique_lock lock(loopThreadMtx_); - if (loopThread_) return Error(errLogic, "Client is already started"); + if (loopThread_) { + return Error(errLogic, "Client is already started"); + } std::promise isRunningPromise; auto isRunningFuture = isRunningPromise.get_future(); @@ -36,64 +38,64 @@ Error SyncCoroReindexerImpl::Stop() { } return errOK; } -Error SyncCoroReindexerImpl::OpenNamespace(std::string_view nsName, const InternalRdxContext &ctx, const StorageOpts &opts) { +Error SyncCoroReindexerImpl::OpenNamespace(std::string_view nsName, const InternalRdxContext& ctx, const StorageOpts& opts) { return sendCommand(DbCmdOpenNamespace, std::forward(nsName), ctx, opts); } -Error SyncCoroReindexerImpl::AddNamespace(const NamespaceDef &nsDef, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::AddNamespace(const NamespaceDef& nsDef, const InternalRdxContext& ctx) { return sendCommand(DbCmdAddNamespace, nsDef, ctx); } -Error SyncCoroReindexerImpl::CloseNamespace(std::string_view nsName, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::CloseNamespace(std::string_view nsName, const InternalRdxContext& ctx) { return sendCommand(DbCmdCloseNamespace, std::forward(nsName), ctx); } -Error SyncCoroReindexerImpl::DropNamespace(std::string_view nsName, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::DropNamespace(std::string_view nsName, const InternalRdxContext& ctx) { return sendCommand(DbCmdDropNamespace, std::forward(nsName), ctx); } -Error SyncCoroReindexerImpl::TruncateNamespace(std::string_view nsName, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::TruncateNamespace(std::string_view nsName, const InternalRdxContext& ctx) { return sendCommand(DbCmdTruncateNamespace, std::forward(nsName), ctx); } -Error SyncCoroReindexerImpl::RenameNamespace(std::string_view srcNsName, const std::string &dstNsName, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx) { return sendCommand(DbCmdRenameNamespace, std::forward(srcNsName), dstNsName, ctx); } -Error SyncCoroReindexerImpl::AddIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::AddIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx) { return sendCommand(DbCmdAddIndex, std::forward(nsName), index, ctx); } -Error SyncCoroReindexerImpl::UpdateIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::UpdateIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx) { return sendCommand(DbCmdUpdateIndex, std::forward(nsName), index, ctx); } -Error SyncCoroReindexerImpl::DropIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::DropIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx) { return sendCommand(DbCmdDropIndex, std::forward(nsName), index, ctx); } -Error SyncCoroReindexerImpl::SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext& ctx) { return sendCommand(DbCmdSetSchema, std::forward(nsName), std::forward(schema), ctx); } -Error SyncCoroReindexerImpl::EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts, const InternalRdxContext& ctx) { return sendCommand(DbCmdEnumNamespaces, defs, std::forward(opts), ctx); } -Error SyncCoroReindexerImpl::EnumDatabases(std::vector &dbList, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::EnumDatabases(std::vector& dbList, const InternalRdxContext& ctx) { return sendCommand(DbCmdEnumDatabases, dbList, ctx); } -Error SyncCoroReindexerImpl::Insert(std::string_view nsName, Item &item, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Insert(std::string_view nsName, Item& item, const InternalRdxContext& ctx) { return sendCommand(DbCmdInsert, std::forward(nsName), item, ctx); } -Error SyncCoroReindexerImpl::Update(std::string_view nsName, Item &item, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Update(std::string_view nsName, Item& item, const InternalRdxContext& ctx) { return sendCommand(DbCmdUpdate, std::forward(nsName), item, ctx); } -Error SyncCoroReindexerImpl::Upsert(std::string_view nsName, Item &item, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Upsert(std::string_view nsName, Item& item, const InternalRdxContext& ctx) { return sendCommand(DbCmdUpsert, std::forward(nsName), item, ctx); } -Error SyncCoroReindexerImpl::Update(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Update(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx) { return sendCommand(DbCmdUpdateQ, query, result.results_, ctx); } -Error SyncCoroReindexerImpl::Delete(std::string_view nsName, Item &item, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Delete(std::string_view nsName, Item& item, const InternalRdxContext& ctx) { return sendCommand(DbCmdDelete, std::forward(nsName), item, ctx); } -Error SyncCoroReindexerImpl::Delete(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Delete(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx) { return sendCommand(DbCmdDeleteQ, query, result.results_, ctx); } -Error SyncCoroReindexerImpl::Select(std::string_view query, SyncCoroQueryResults &result, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Select(std::string_view query, SyncCoroQueryResults& result, const InternalRdxContext& ctx) { return sendCommand(DbCmdSelectS, std::forward(query), result, ctx); } -Error SyncCoroReindexerImpl::Select(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::Select(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx) { return sendCommand(DbCmdSelectQ, query, result, ctx); } Error SyncCoroReindexerImpl::Commit(std::string_view nsName) { @@ -103,64 +105,64 @@ Item SyncCoroReindexerImpl::NewItem(std::string_view nsName) { return sendCommand(DbCmdNewItem, std::forward(nsName)); } -Error SyncCoroReindexerImpl::GetMeta(std::string_view nsName, const std::string &key, std::string &data, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::GetMeta(std::string_view nsName, const std::string& key, std::string& data, const InternalRdxContext& ctx) { return sendCommand(DbCmdGetMeta, std::forward(nsName), key, data, ctx); } -Error SyncCoroReindexerImpl::PutMeta(std::string_view nsName, const std::string &key, std::string_view data, - const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::PutMeta(std::string_view nsName, const std::string& key, std::string_view data, + const InternalRdxContext& ctx) { return sendCommand(DbCmdPutMeta, std::forward(nsName), key, std::forward(data), ctx); } -Error SyncCoroReindexerImpl::EnumMeta(std::string_view nsName, std::vector &keys, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::EnumMeta(std::string_view nsName, std::vector& keys, const InternalRdxContext& ctx) { return sendCommand(DbCmdEnumMeta, std::forward(nsName), keys, ctx); } -Error SyncCoroReindexerImpl::DeleteMeta(std::string_view nsName, const std::string &key, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::DeleteMeta(std::string_view nsName, const std::string& key, const InternalRdxContext& ctx) { return sendCommand(DbCmdDeleteMeta, std::forward(nsName), key, ctx); } -Error SyncCoroReindexerImpl::GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector &suggestions) { +Error SyncCoroReindexerImpl::GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector& suggestions) { return sendCommand(DbCmdGetSqlSuggestions, std::forward(sqlQuery), std::forward(pos), suggestions); } -Error SyncCoroReindexerImpl::Status(const InternalRdxContext &ctx) { return sendCommand(DbCmdStatus, ctx); } +Error SyncCoroReindexerImpl::Status(const InternalRdxContext& ctx) { return sendCommand(DbCmdStatus, ctx); } -SyncCoroTransaction SyncCoroReindexerImpl::NewTransaction(std::string_view nsName, const InternalRdxContext &ctx) { +SyncCoroTransaction SyncCoroReindexerImpl::NewTransaction(std::string_view nsName, const InternalRdxContext& ctx) { CoroTransaction tx = sendCommand(DbCmdNewTransaction, std::forward(nsName), ctx); if (tx.Status().ok()) { return SyncCoroTransaction(std::move(tx), this); } return SyncCoroTransaction(tx.Status(), this); } -Error SyncCoroReindexerImpl::CommitTransaction(SyncCoroTransaction &tr, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::CommitTransaction(SyncCoroTransaction& tr, const InternalRdxContext& ctx) { Error err = sendCommand(DbCmdCommitTransaction, tr.tr_, ctx); tr = SyncCoroTransaction(errOK, this); return err; } -Error SyncCoroReindexerImpl::RollBackTransaction(SyncCoroTransaction &tr, const InternalRdxContext &ctx) { +Error SyncCoroReindexerImpl::RollBackTransaction(SyncCoroTransaction& tr, const InternalRdxContext& ctx) { Error err = sendCommand(DbCmdRollBackTransaction, tr, ctx); tr = SyncCoroTransaction(errOK, this); return err; } -Error SyncCoroReindexerImpl::fetchResults(int flags, SyncCoroQueryResults &result) { +Error SyncCoroReindexerImpl::fetchResults(int flags, SyncCoroQueryResults& result) { return sendCommand(DbCmdFetchResults, std::forward(flags), result); } -Error SyncCoroReindexerImpl::addTxItem(SyncCoroTransaction &tr, Item &&item, ItemModifyMode mode) { +Error SyncCoroReindexerImpl::addTxItem(SyncCoroTransaction& tr, Item&& item, ItemModifyMode mode) { return sendCommand(DbCmdAddTxItem, tr.tr_, std::move(item), std::forward(mode)); } -Error SyncCoroReindexerImpl::modifyTx(SyncCoroTransaction &tr, Query &&q) { +Error SyncCoroReindexerImpl::modifyTx(SyncCoroTransaction& tr, Query&& q) { return sendCommand(DbCmdModifyTx, tr.tr_, std::move(q)); } -Item SyncCoroReindexerImpl::newItemTx(CoroTransaction &tr) { return sendCommand(DbCmdNewItemTx, tr); } +Item SyncCoroReindexerImpl::newItemTx(CoroTransaction& tr) { return sendCommand(DbCmdNewItemTx, tr); } -void SyncCoroReindexerImpl::threadLoopFun(std::promise &&isRunning, const std::string &dsn, const client::ConnectOpts &opts) { - coroutine::channel chCommand; +void SyncCoroReindexerImpl::threadLoopFun(std::promise&& isRunning, const std::string& dsn, const client::ConnectOpts& opts) { + coroutine::channel chCommand; commandAsync_.set(loop_); - commandAsync_.set([this, &chCommand](net::ev::async &) { + commandAsync_.set([this, &chCommand](net::ev::async&) { loop_.spawn([this, &chCommand]() { - std::vector q; + std::vector q; commandsQueue_.Get(q); for (auto c : q) { chCommand.push(c); @@ -170,7 +172,7 @@ void SyncCoroReindexerImpl::threadLoopFun(std::promise &&isRunning, const commandAsync_.start(); closeAsync_.set(loop_); - closeAsync_.set([this, &chCommand](net::ev::async &) { loop_.spawn([&chCommand]() { chCommand.close(); }); }); + closeAsync_.set([this, &chCommand](net::ev::async&) { loop_.spawn([&chCommand]() { chCommand.close(); }); }); closeAsync_.start(); auto coro = [this, &chCommand, dsn, opts, &isRunning]() { @@ -192,124 +194,124 @@ void SyncCoroReindexerImpl::threadLoopFun(std::promise &&isRunning, const closeAsync_.stop(); } -void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient &rx, coroutine::channel &chCommand, - coroutine::wait_group &wg) { +void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient& rx, coroutine::channel& chCommand, + coroutine::wait_group& wg) { using namespace std::placeholders; coroutine::wait_group_guard wgg(wg); - for (std::pair v = chCommand.pop(); v.second == true; v = chCommand.pop()) { + for (std::pair v = chCommand.pop(); v.second == true; v = chCommand.pop()) { switch (v.first->id_) { case DbCmdOpenNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::OpenNamespace, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdAddNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::AddNamespace, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdCloseNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::CloseNamespace, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdDropNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::DropNamespace, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdTruncateNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::TruncateNamespace, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdRenameNamespace: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::RenameNamespace, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdAddIndex: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::AddIndex, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdUpdateIndex: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::UpdateIndex, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdDropIndex: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::DropIndex, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdSetSchema: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::SetSchema, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdEnumNamespaces: { - std::function &, EnumNamespacesOpts, const InternalRdxContext &)> f = + std::function&, EnumNamespacesOpts, const InternalRdxContext&)> f = std::bind(&client::CoroRPCClient::EnumNamespaces, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdEnumDatabases: { - std::function &, const InternalRdxContext &)> f = + std::function&, const InternalRdxContext&)> f = std::bind(&client::CoroRPCClient::EnumDatabases, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdInsert: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::Insert, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdUpdate: { - std::function f = - std::bind(static_cast( + std::function f = + std::bind(static_cast( &client::CoroRPCClient::Update), &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdUpsert: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::Upsert, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdUpdateQ: { - std::function f = - std::bind(static_cast( + std::function f = + std::bind(static_cast( &client::CoroRPCClient::Update), &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdDelete: { - std::function f = - std::bind(static_cast( + std::function f = + std::bind(static_cast( &client::CoroRPCClient::Delete), &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdDeleteQ: { - std::function f = - std::bind(static_cast( + std::function f = + std::bind(static_cast( &client::CoroRPCClient::Delete), &rx, _1, _2, _3); execCommand(v.first, f); @@ -323,15 +325,14 @@ void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient &rx } case DbCmdSelectS: { auto cd = - dynamic_cast *>(v.first); + dynamic_cast*>(v.first); assertrx(cd); Error err = rx.Select(std::get<0>(cd->arguments), std::get<1>(cd->arguments).results_, std::get<2>(cd->arguments)); cd->ret.set_value(std::move(err)); break; } case DbCmdSelectQ: { - auto cd = - dynamic_cast *>(v.first); + auto cd = dynamic_cast*>(v.first); assertrx(cd); Error err = rx.Select(std::get<0>(cd->arguments), std::get<1>(cd->arguments).results_, std::get<2>(cd->arguments)); cd->ret.set_value(std::move(err)); @@ -343,64 +344,64 @@ void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient &rx break; } case DbCmdGetMeta: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::GetMeta, &rx, _1, _2, _3, _4); execCommand(v.first, f); break; } case DbCmdPutMeta: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::PutMeta, &rx, _1, _2, _3, _4); execCommand(v.first, f); break; } case DbCmdEnumMeta: { - std::function &, const InternalRdxContext &)> f = + std::function&, const InternalRdxContext&)> f = std::bind(&client::CoroRPCClient::EnumMeta, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdDeleteMeta: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::DeleteMeta, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdGetSqlSuggestions: { - std::function &)> f = + std::function&)> f = std::bind(&client::CoroRPCClient::GetSqlSuggestions, &rx, _1, _2, _3); execCommand(v.first, f); break; } case DbCmdStatus: { - std::function f = std::bind(&client::CoroRPCClient::Status, &rx, _1); + std::function f = std::bind(&client::CoroRPCClient::Status, &rx, _1); execCommand(v.first, f); break; } case DbCmdNewTransaction: { - auto *cd = dynamic_cast *>(v.first); + auto* cd = dynamic_cast*>(v.first); assertrx(cd); CoroTransaction coroTrans = rx.NewTransaction(std::get<0>(cd->arguments), std::get<1>(cd->arguments)); cd->ret.set_value(std::move(coroTrans)); break; } case DbCmdCommitTransaction: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::CommitTransaction, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdRollBackTransaction: { - std::function f = + std::function f = std::bind(&client::CoroRPCClient::RollBackTransaction, &rx, _1, _2); execCommand(v.first, f); break; } case DbCmdFetchResults: { - auto cd = dynamic_cast *>(v.first); + auto cd = dynamic_cast*>(v.first); assertrx(cd); - CoroQueryResults &coroResults = std::get<1>(cd->arguments).results_; + CoroQueryResults& coroResults = std::get<1>(cd->arguments).results_; auto ret = coroResults.conn_->Call( {reindexer::net::cproto::kCmdFetchResults, coroResults.requestTimeout_, milliseconds(0), nullptr}, coroResults.queryID_.main, std::get<0>(cd->arguments), coroResults.queryParams_.count + coroResults.fetchOffset_, @@ -427,21 +428,21 @@ void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient &rx break; } case DbCmdNewItemTx: { - auto cd = dynamic_cast *>(v.first); + auto cd = dynamic_cast*>(v.first); assertrx(cd); Item item = execNewItemTx(std::get<0>(cd->arguments)); cd->ret.set_value(std::move(item)); break; } case DbCmdAddTxItem: { - auto cd = dynamic_cast *>(v.first); + auto cd = dynamic_cast*>(v.first); assertrx(cd); Error err = std::get<0>(cd->arguments).addTxItem(std::move(std::get<1>(cd->arguments)), std::get<2>(cd->arguments)); cd->ret.set_value(err); break; } case DbCmdModifyTx: { - auto cd = dynamic_cast *>(v.first); + auto cd = dynamic_cast*>(v.first); assertrx(cd); CoroTransaction tr = std::get<0>(cd->arguments); Error err(errLogic, "Connection pointer in transaction is nullptr."); @@ -460,19 +461,21 @@ void SyncCoroReindexerImpl::coroInterpreter(reindexer::client::CoroRPCClient &rx } } -Item SyncCoroReindexerImpl::execNewItemTx(CoroTransaction &tr) { - if (!tr.rpcClient_) return Item(Error(errLogic, "rpcClient not set for client transaction")); +Item SyncCoroReindexerImpl::execNewItemTx(CoroTransaction& tr) { + if (!tr.rpcClient_) { + return Item(Error(errLogic, "rpcClient not set for client transaction")); + } return tr.rpcClient_->NewItem(tr.nsName_); } -void SyncCoroReindexerImpl::CommandsQueue::Push(net::ev::async &ev, DatabaseCommandBase *cmd) { +void SyncCoroReindexerImpl::CommandsQueue::Push(net::ev::async& ev, DatabaseCommandBase* cmd) { { std::unique_lock lock(mtx_); queue_.emplace_back(cmd); } ev.send(); } -void SyncCoroReindexerImpl::CommandsQueue::Get(std::vector &cmds) { +void SyncCoroReindexerImpl::CommandsQueue::Get(std::vector& cmds) { std::unique_lock lock(mtx_); cmds.swap(queue_); } diff --git a/cpp_src/client/synccororeindexerimpl.h b/cpp_src/client/synccororeindexerimpl.h index 960f77722..f7ea0442b 100644 --- a/cpp_src/client/synccororeindexerimpl.h +++ b/cpp_src/client/synccororeindexerimpl.h @@ -15,57 +15,57 @@ class SyncCoroTransaction; class SyncCoroReindexerImpl { public: /// Create Reindexer database object - SyncCoroReindexerImpl(const ReindexerConfig & = ReindexerConfig()); + SyncCoroReindexerImpl(const ReindexerConfig& = ReindexerConfig()); /// Destrory Reindexer database object ~SyncCoroReindexerImpl(); - SyncCoroReindexerImpl(const SyncCoroReindexerImpl &) = delete; - SyncCoroReindexerImpl &operator=(const SyncCoroReindexerImpl &) = delete; + SyncCoroReindexerImpl(const SyncCoroReindexerImpl&) = delete; + SyncCoroReindexerImpl& operator=(const SyncCoroReindexerImpl&) = delete; - Error Connect(const std::string &dsn, const client::ConnectOpts &opts = client::ConnectOpts()); + Error Connect(const std::string& dsn, const client::ConnectOpts& opts = client::ConnectOpts()); Error Stop(); - Error OpenNamespace(std::string_view nsName, const InternalRdxContext &ctx, - const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); - Error AddNamespace(const NamespaceDef &nsDef, const InternalRdxContext &ctx); - Error CloseNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error DropNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error TruncateNamespace(std::string_view nsName, const InternalRdxContext &ctx); - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName, const InternalRdxContext &ctx); - Error AddIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error UpdateIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error DropIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx); - Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext &ctx); - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts, const InternalRdxContext &ctx); - Error EnumDatabases(std::vector &dbList, const InternalRdxContext &ctx); - Error Insert(std::string_view nsName, Item &item, const InternalRdxContext &ctx); - Error Update(std::string_view nsName, Item &item, const InternalRdxContext &ctx); - Error Upsert(std::string_view nsName, Item &item, const InternalRdxContext &ctx); - Error Update(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx); - Error Delete(std::string_view nsName, Item &item, const InternalRdxContext &ctx); - Error Delete(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx); - Error Select(std::string_view query, SyncCoroQueryResults &result, const InternalRdxContext &ctx); - Error Select(const Query &query, SyncCoroQueryResults &result, const InternalRdxContext &ctx); + Error OpenNamespace(std::string_view nsName, const InternalRdxContext& ctx, + const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); + Error AddNamespace(const NamespaceDef& nsDef, const InternalRdxContext& ctx); + Error CloseNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error DropNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error TruncateNamespace(std::string_view nsName, const InternalRdxContext& ctx); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx); + Error AddIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error UpdateIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error DropIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx); + Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext& ctx); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts, const InternalRdxContext& ctx); + Error EnumDatabases(std::vector& dbList, const InternalRdxContext& ctx); + Error Insert(std::string_view nsName, Item& item, const InternalRdxContext& ctx); + Error Update(std::string_view nsName, Item& item, const InternalRdxContext& ctx); + Error Upsert(std::string_view nsName, Item& item, const InternalRdxContext& ctx); + Error Update(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx); + Error Delete(std::string_view nsName, Item& item, const InternalRdxContext& ctx); + Error Delete(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx); + Error Select(std::string_view query, SyncCoroQueryResults& result, const InternalRdxContext& ctx); + Error Select(const Query& query, SyncCoroQueryResults& result, const InternalRdxContext& ctx); Error Commit(std::string_view nsName); Item NewItem(std::string_view nsName); - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data, const InternalRdxContext &ctx); - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data, const InternalRdxContext &ctx); - Error EnumMeta(std::string_view nsName, std::vector &keys, const InternalRdxContext &ctx); - Error DeleteMeta(std::string_view nsName, const std::string &key, const InternalRdxContext &ctx); - Error GetSqlSuggestions(const std::string_view sqlQuery, int pos, std::vector &suggestions); - Error Status(const InternalRdxContext &ctx); - SyncCoroTransaction NewTransaction(std::string_view nsName, const InternalRdxContext &ctx); - Error CommitTransaction(SyncCoroTransaction &tr, const InternalRdxContext &ctx); - Error RollBackTransaction(SyncCoroTransaction &tr, const InternalRdxContext &ctx); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data, const InternalRdxContext& ctx); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data, const InternalRdxContext& ctx); + Error EnumMeta(std::string_view nsName, std::vector& keys, const InternalRdxContext& ctx); + Error DeleteMeta(std::string_view nsName, const std::string& key, const InternalRdxContext& ctx); + Error GetSqlSuggestions(const std::string_view sqlQuery, int pos, std::vector& suggestions); + Error Status(const InternalRdxContext& ctx); + SyncCoroTransaction NewTransaction(std::string_view nsName, const InternalRdxContext& ctx); + Error CommitTransaction(SyncCoroTransaction& tr, const InternalRdxContext& ctx); + Error RollBackTransaction(SyncCoroTransaction& tr, const InternalRdxContext& ctx); private: friend class SyncCoroQueryResults; friend class SyncCoroTransaction; - Error fetchResults(int flags, SyncCoroQueryResults &result); - Error addTxItem(SyncCoroTransaction &tr, Item &&item, ItemModifyMode mode); - Error modifyTx(SyncCoroTransaction &tr, Query &&q); - Item execNewItemTx(CoroTransaction &tr); - Item newItemTx(CoroTransaction &tr); - Error execAddTxItem(CoroTransaction &tr, Item &item, ItemModifyMode mode); - void threadLoopFun(std::promise &&isRunning, const std::string &dsn, const client::ConnectOpts &opts); + Error fetchResults(int flags, SyncCoroQueryResults& result); + Error addTxItem(SyncCoroTransaction& tr, Item&& item, ItemModifyMode mode); + Error modifyTx(SyncCoroTransaction& tr, Query&& q); + Item execNewItemTx(CoroTransaction& tr); + Item newItemTx(CoroTransaction& tr); + Error execAddTxItem(CoroTransaction& tr, Item& item, ItemModifyMode mode); + void threadLoopFun(std::promise&& isRunning, const std::string& dsn, const client::ConnectOpts& opts); bool exit_ = false; enum CmdName { @@ -117,12 +117,12 @@ class SyncCoroReindexerImpl { struct DatabaseCommand : public DatabaseCommandBase { std::promise ret; std::tuple arguments; - DatabaseCommand(CmdName id, std::promise r, P &&...p) + DatabaseCommand(CmdName id, std::promise r, P&&... p) : DatabaseCommandBase(id), ret(std::move(r)), arguments(std::forward

(p)...) {} }; template - R sendCommand(CmdName c, Args &&...args) { + R sendCommand(CmdName c, Args&&... args) { std::promise promise; std::future future = promise.get_future(); DatabaseCommand cmd(c, std::move(promise), std::forward(args)...); @@ -132,8 +132,8 @@ class SyncCoroReindexerImpl { } template - void execCommand(DatabaseCommandBase *cmd, const std::function &fun) { - auto cd = dynamic_cast *>(cmd); + void execCommand(DatabaseCommandBase* cmd, const std::function& fun) { + auto cd = dynamic_cast*>(cmd); if (cd) { R r = std::apply(fun, cd->arguments); cd->ret.set_value(std::move(r)); @@ -145,11 +145,11 @@ class SyncCoroReindexerImpl { class CommandsQueue { public: CommandsQueue() {} - void Push(net::ev::async &ev, DatabaseCommandBase *cmd); - void Get(std::vector &cmds); + void Push(net::ev::async& ev, DatabaseCommandBase* cmd); + void Get(std::vector& cmds); private: - std::vector queue_; + std::vector queue_; std::mutex mtx_; }; @@ -160,8 +160,8 @@ class SyncCoroReindexerImpl { net::ev::async commandAsync_; net::ev::async closeAsync_; const ReindexerConfig conf_; - void coroInterpreter(reindexer::client::CoroRPCClient &rx, coroutine::channel &chCommand, - coroutine::wait_group &wg); + void coroInterpreter(reindexer::client::CoroRPCClient& rx, coroutine::channel& chCommand, + coroutine::wait_group& wg); }; } // namespace client diff --git a/cpp_src/client/transaction.cc b/cpp_src/client/transaction.cc index 19b5adcaf..e7b107bd4 100644 --- a/cpp_src/client/transaction.cc +++ b/cpp_src/client/transaction.cc @@ -12,7 +12,9 @@ void Transaction::Modify(Query&& query) { WrSerializer ser; query.Serialize(ser); auto ret = conn_->Call({cproto::kCmdUpdateQueryTx, RequestTimeout_, execTimeout_, nullptr}, ser.Slice(), txId_).Status(); - if (!ret.ok()) throw ret; + if (!ret.ok()) { + throw ret; + } } throw Error(errLogic, "Connection pointer in transaction is nullptr."); } @@ -26,29 +28,38 @@ void Transaction::addTxItem(Item&& item, ItemModifyMode mode) { conn_->Call({net::cproto::kCmdAddTxItem, RequestTimeout_, execTimeout_, nullptr}, FormatJson, itemData, mode, "", 0, txId_); if (!ret.Status().ok()) { - if (ret.Status().code() != errStateInvalidated || tryCount > 2) throw ret.Status(); + if (ret.Status().code() != errStateInvalidated || tryCount > 2) { + throw ret.Status(); + } QueryResults qr; InternalRdxContext ctx; ctx = ctx.WithTimeout(execTimeout_); auto err = rpcClient_->Select(Query(nsName_).Limit(0), qr, ctx, conn_); - if (!err.ok()) throw Error(errLogic, "Can't update TagsMatcher"); + if (!err.ok()) { + throw Error(errLogic, "Can't update TagsMatcher"); + } auto newItem = NewItem(); char* endp = nullptr; err = newItem.FromJSON(item.impl_->GetJSON(), &endp); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } item = std::move(newItem); } else { break; } } - } else + } else { throw Error(errLogic, "Connection pointer in transaction is nullptr."); + } } Item Transaction::NewItem() { - if (!rpcClient_) throw Error(errLogic, "rpcClient not set for client transaction"); + if (!rpcClient_) { + throw Error(errLogic, "rpcClient not set for client transaction"); + } return rpcClient_->NewItem(nsName_); } } // namespace client diff --git a/cpp_src/cmake/modules/RxPrepareInstallFiles.cmake b/cpp_src/cmake/modules/RxPrepareInstallFiles.cmake index de02c8710..6e7023499 100644 --- a/cpp_src/cmake/modules/RxPrepareInstallFiles.cmake +++ b/cpp_src/cmake/modules/RxPrepareInstallFiles.cmake @@ -56,7 +56,7 @@ if (NOT WIN32) SET(DIST_INCLUDE_FILES "tools/errors.h" "tools/serializer.h" "tools/varint.h" "tools/stringstools.h" "tools/customhash.h" "tools/assertrx.h" "tools/jsonstring.h" "tools/verifying_updater.h" "tools/customlocal.h" "tools/clock.h" - "core/reindexer.h" "core/type_consts.h" "core/item.h" "core/payload/payloadvalue.h" "core/payload/payloadiface.h" "core/indexopts.h" + "core/reindexer.h" "core/type_consts.h" "core/type_formats.h" "core/item.h" "core/payload/payloadvalue.h" "core/payload/payloadiface.h" "core/indexopts.h" "core/namespacedef.h" "core/keyvalue/variant.h" "core/keyvalue/geometry.h" "core/sortingprioritiestable.h" "core/rdxcontext.h" "core/activity_context.h" "core/type_consts_helpers.h" "core/payload/fieldsset.h" "core/payload/payloadtype.h" "core/cbinding/reindexer_c.h" "core/cbinding/reindexer_ctypes.h" "core/transaction.h" "core/payload/payloadfieldtype.h" "core/reindexerconfig.h" diff --git a/cpp_src/cmd/reindexer_server/contrib/Dockerfile b/cpp_src/cmd/reindexer_server/contrib/Dockerfile index db8c9a379..5e9da49cd 100644 --- a/cpp_src/cmd/reindexer_server/contrib/Dockerfile +++ b/cpp_src/cmd/reindexer_server/contrib/Dockerfile @@ -1,11 +1,11 @@ -FROM alpine:3.19 AS build +FROM alpine:3.20 AS build RUN cd /tmp && apk update && \ apk add git curl autoconf automake libtool linux-headers g++ make libunwind-dev grpc-dev protobuf-dev c-ares-dev patch && \ git clone https://github.com/gperftools/gperftools.git && \ cd gperftools && git checkout gperftools-2.15 && \ sed -i s/_sigev_un\._tid/sigev_notify_thread_id/ src/profile-handler.cc && \ - ./autogen.sh && ./configure --disable-dependency-tracking && make -j8 && make install + ./autogen.sh && ./configure --disable-dependency-tracking && make -j6 && make install ADD . /src @@ -15,7 +15,7 @@ RUN ./dependencies.sh && \ mkdir build && \ cd build && \ cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. -DENABLE_GRPC=On -DGRPC_PACKAGE_PROVIDER="" && \ - make -j8 reindexer_server reindexer_tool && \ + make -j6 reindexer_server reindexer_tool && \ make install -C cpp_src/cmd/reindexer_server && \ make install -C cpp_src/cmd/reindexer_tool && \ make install -C cpp_src/server/grpc && \ @@ -23,18 +23,18 @@ RUN ./dependencies.sh && \ rm -rf /usr/local/lib/*.a /usr/local/include /usr/local/lib/libtcmalloc_debug* /usr/local/lib/libtcmalloc_minimal* \ /usr/local/lib/libprofiler* /usr/local/lib/libtcmalloc.* /usr/local/share/doc /usr/local/share/man /usr/local/share/perl5 /usr/local/bin/pprof* -FROM alpine:3.19 +FROM alpine:3.20 COPY --from=build /usr/local /usr/local COPY --from=build /entrypoint.sh /entrypoint.sh RUN apk update && apk add libstdc++ libunwind snappy leveldb c-ares libprotobuf xz-libs grpc-cpp && rm -rf /var/cache/apk/* -ENV RX_DATABASE /db -ENV RX_CORELOG stdout -ENV RX_HTTPLOG stdout -ENV RX_RPCLOG stdout -ENV RX_SERVERLOG stdout -ENV RX_LOGLEVEL info +ENV RX_DATABASE=/db +ENV RX_CORELOG=stdout +ENV RX_HTTPLOG=stdout +ENV RX_RPCLOG=stdout +ENV RX_SERVERLOG=stdout +ENV RX_LOGLEVEL=info RUN chmod +x /entrypoint.sh diff --git a/cpp_src/cmd/reindexer_server/contrib/Dockerfile.deb b/cpp_src/cmd/reindexer_server/contrib/Dockerfile.deb index d64e65dc2..3efe1de23 100644 --- a/cpp_src/cmd/reindexer_server/contrib/Dockerfile.deb +++ b/cpp_src/cmd/reindexer_server/contrib/Dockerfile.deb @@ -21,12 +21,12 @@ COPY --from=build /usr/local /usr/local COPY --from=build /entrypoint.sh /entrypoint.sh RUN apt update -y && apt install -y libleveldb1d libunwind8 libjemalloc2 libgrpc++1.51 && rm -rf /var/lib/apt -ENV RX_DATABASE /db -ENV RX_CORELOG stdout -ENV RX_HTTPLOG stdout -ENV RX_RPCLOG stdout -ENV RX_SERVERLOG stdout -ENV RX_LOGLEVEL info +ENV RX_DATABASE=/db +ENV RX_CORELOG=stdout +ENV RX_HTTPLOG=stdout +ENV RX_RPCLOG=stdout +ENV RX_SERVERLOG=stdout +ENV RX_LOGLEVEL=info RUN chmod +x /entrypoint.sh diff --git a/cpp_src/cmd/reindexer_server/main.cc b/cpp_src/cmd/reindexer_server/main.cc index 26ad80512..57d8b6c30 100644 --- a/cpp_src/cmd/reindexer_server/main.cc +++ b/cpp_src/cmd/reindexer_server/main.cc @@ -26,6 +26,6 @@ int main(int argc, char* argv[]) { svc.EnableHandleSignals(); int ret = svc.Start(); - spdlog::drop_all(); + spdlog::shutdown(); return ret; } diff --git a/cpp_src/cmd/reindexer_server/test/test_storage_compatibility.sh b/cpp_src/cmd/reindexer_server/test/test_storage_compatibility.sh new file mode 100755 index 000000000..d189d3841 --- /dev/null +++ b/cpp_src/cmd/reindexer_server/test/test_storage_compatibility.sh @@ -0,0 +1,195 @@ +#!/bin/bash +# Task: https://github.com/restream/reindexer/-/issues/1188 +set -e + +function KillAndRemoveServer { + local pid=$1 + kill $pid + wait $pid + yum remove -y 'reindexer*' > /dev/null +} + +function WaitForDB { + # wait until DB is loaded + set +e # disable "exit on error" so the script won't stop when DB's not loaded yet + is_connected=$(reindexer_tool --dsn $ADDRESS --command '\databases list'); + while [[ $is_connected != "test" ]] + do + sleep 2 + is_connected=$(reindexer_tool --dsn $ADDRESS --command '\databases list'); + done + set -e +} + +function CompareNamespacesLists { + local ns_list_actual=$1 + local ns_list_expected=$2 + local pid=$3 + + diff=$(echo ${ns_list_actual[@]} ${ns_list_expected[@]} | tr ' ' '\n' | sort | uniq -u) # compare in any order + if [ "$diff" == "" ]; then + echo "## PASS: namespaces list not changed" + else + echo "##### FAIL: namespaces list was changed" + echo "expected: $ns_list_expected" + echo "actual: $ns_list_actual" + KillAndRemoveServer $pid; + exit 1 + fi +} + +function CompareMemstats { + local actual=$1 + local expected=$2 + local pid=$3 + diff=$(echo ${actual[@]} ${expected[@]} | tr ' ' '\n' | sed 's/\(.*\),$/\1/' | sort | uniq -u) # compare in any order + if [ "$diff" == "" ]; then + echo "## PASS: memstats not changed" + else + echo "##### FAIL: memstats was changed" + echo "expected: $expected" + echo "actual: $actual" + KillAndRemoveServer $pid; + exit 1 + fi +} + + +RX_SERVER_CURRENT_VERSION_RPM="$(basename build/reindexer-*server*.rpm)" +VERSION_FROM_RPM=$(echo "$RX_SERVER_CURRENT_VERSION_RPM" | grep -o '.*server-..') +VERSION=$(echo ${VERSION_FROM_RPM: -2:1}) # one-digit version + +echo "## choose latest release rpm file" +if [ $VERSION == 3 ]; then + LATEST_RELEASE=$(python3 cpp_src/cmd/reindexer_server/test/get_last_rx_version.py -v 3) + namespaces_list_expected=$'purchase_options_ext_dict\nchild_account_recommendations\n#config\n#activitystats\nradio_channels\ncollections\n#namespaces\nwp_imports_tasks\nepg_genres\nrecom_media_items_personal\nrecom_epg_archive_default\n#perfstats\nrecom_epg_live_default\nmedia_view_templates\nasset_video_servers\nwp_tasks_schedule\nadmin_roles\n#clientsstats\nrecom_epg_archive_personal\nrecom_media_items_similars\nmenu_items\naccount_recommendations\nkaraoke_items\nmedia_items\nbanners\n#queriesperfstats\nrecom_media_items_default\nrecom_epg_live_personal\nservices\n#memstats\nchannels\nmedia_item_recommendations\nwp_tasks_tasks\nepg' +elif [ $VERSION == 4 ]; then + LATEST_RELEASE=$(python3 cpp_src/cmd/reindexer_server/test/get_last_rx_version.py -v 4) + # replicationstats ns added for v4 + namespaces_list_expected=$'purchase_options_ext_dict\nchild_account_recommendations\n#config\n#activitystats\n#replicationstats\nradio_channels\ncollections\n#namespaces\nwp_imports_tasks\nepg_genres\nrecom_media_items_personal\nrecom_epg_archive_default\n#perfstats\nrecom_epg_live_default\nmedia_view_templates\nasset_video_servers\nwp_tasks_schedule\nadmin_roles\n#clientsstats\nrecom_epg_archive_personal\nrecom_media_items_similars\nmenu_items\naccount_recommendations\nkaraoke_items\nmedia_items\nbanners\n#queriesperfstats\nrecom_media_items_default\nrecom_epg_live_personal\nservices\n#memstats\nchannels\nmedia_item_recommendations\nwp_tasks_tasks\nepg' +else + echo "Unknown version" + exit 1 +fi + +echo "## downloading latest release rpm file: $LATEST_RELEASE" +curl "http://repo.itv.restr.im/itv-api-ng/7/x86_64/$LATEST_RELEASE" --output $LATEST_RELEASE; +echo "## downloading example DB" +curl "https://git.restream.ru/MaksimKravchuk/reindexer_testdata/-/raw/master/big.zip" --output big.zip; +unzip -o big.zip # unzips into mydb_big.rxdump; + +ADDRESS="cproto://127.0.0.1:6534/" +DB_NAME="test" + +memstats_expected=$'[ +{"replication":{"data_hash":24651210926,"data_count":3}}, +{"replication":{"data_hash":6252344969,"data_count":1}}, +{"replication":{"data_hash":37734732881,"data_count":28}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":1024095024522,"data_count":1145}}, +{"replication":{"data_hash":8373644068,"data_count":1315}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":7404222244,"data_count":97}}, +{"replication":{"data_hash":94132837196,"data_count":4}}, +{"replication":{"data_hash":1896088071,"data_count":2}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":-672103903,"data_count":33538}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":6833710705,"data_count":1}}, +{"replication":{"data_hash":5858155773472,"data_count":4500}}, +{"replication":{"data_hash":-473221280268823592,"data_count":65448}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":8288213744,"data_count":3}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":0,"data_count":0}}, +{"replication":{"data_hash":354171024786967,"data_count":3941}}, +{"replication":{"data_hash":-6520334670,"data_count":35886}}, +{"replication":{"data_hash":112772074632,"data_count":281}}, +{"replication":{"data_hash":-12679568198538,"data_count":1623116}} +] +Returned 27 rows' + +echo "##### Forward compatibility test #####" + +DB_PATH=$(pwd)"/rx_db" + +echo "Database: "$DB_PATH + +echo "## installing latest release: $LATEST_RELEASE" +yum install -y $LATEST_RELEASE > /dev/null; +# run RX server with disabled logging +reindexer_server -l warning --httplog=none --rpclog=none --db $DB_PATH & +server_pid=$! +sleep 2; + +reindexer_tool --dsn $ADDRESS$DB_NAME -f mydb_big.rxdump --createdb; +sleep 1; + +namespaces_1=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command '\namespaces list'); +echo $namespaces_1; +CompareNamespacesLists "${namespaces_1[@]}" "${namespaces_list_expected[@]}" $server_pid; + +memstats_1=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command 'select replication.data_hash, replication.data_count from #memstats'); +CompareMemstats "${memstats_1[@]}" "${memstats_expected[@]}" $server_pid; + +KillAndRemoveServer $server_pid; + +echo "## installing current version: $RX_SERVER_CURRENT_VERSION_RPM" +yum install -y build/*.rpm > /dev/null; +reindexer_server -l0 --corelog=none --httplog=none --rpclog=none --db $DB_PATH & +server_pid=$! +sleep 2; + +WaitForDB + +namespaces_2=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command '\namespaces list'); +echo $namespaces_2; +CompareNamespacesLists "${namespaces_2[@]}" "${namespaces_1[@]}" $server_pid; + +memstats_2=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command 'select replication.data_hash, replication.data_count from #memstats'); +CompareMemstats "${memstats_2[@]}" "${memstats_1[@]}" $server_pid; + +KillAndRemoveServer $server_pid; +rm -rf $DB_PATH; +sleep 1; + +echo "##### Backward compatibility test #####" + +echo "## installing current version: $RX_SERVER_CURRENT_VERSION_RPM" +yum install -y build/*.rpm > /dev/null; +reindexer_server -l warning --httplog=none --rpclog=none --db $DB_PATH & +server_pid=$! +sleep 2; + +reindexer_tool --dsn $ADDRESS$DB_NAME -f mydb_big.rxdump --createdb; +sleep 1; + +namespaces_3=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command '\namespaces list'); +echo $namespaces_3; +CompareNamespacesLists "${namespaces_3[@]}" "${namespaces_list_expected[@]}" $server_pid; + +memstats_3=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command 'select replication.data_hash, replication.data_count from #memstats'); +CompareMemstats "${memstats_3[@]}" "${memstats_expected[@]}" $server_pid; + +KillAndRemoveServer $server_pid; + +echo "## installing latest release: $LATEST_RELEASE" +yum install -y $LATEST_RELEASE > /dev/null; +reindexer_server -l warning --httplog=none --rpclog=none --db $DB_PATH & +server_pid=$! +sleep 2; + +WaitForDB + +namespaces_4=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command '\namespaces list'); +echo $namespaces_4; +CompareNamespacesLists "${namespaces_4[@]}" "${namespaces_3[@]}" $server_pid; + +memstats_4=$(reindexer_tool --dsn $ADDRESS$DB_NAME --command 'select replication.data_hash, replication.data_count from #memstats'); +CompareMemstats "${memstats_4[@]}" "${memstats_3[@]}" $server_pid; + +KillAndRemoveServer $server_pid; +rm -rf $DB_PATH; diff --git a/cpp_src/cmd/reindexer_tool/commandsexecutor.cc b/cpp_src/cmd/reindexer_tool/commandsexecutor.cc index e5e4ff453..0802cf656 100644 --- a/cpp_src/cmd/reindexer_tool/commandsexecutor.cc +++ b/cpp_src/cmd/reindexer_tool/commandsexecutor.cc @@ -214,7 +214,9 @@ Error CommandsExecutor::runImpl(const std::string& dsn, Args&&... a if (err.ok() && !uri_.parse(dsn)) { err = Error(errNotValid, "Cannot connect to DB: Not a valid uri"); } - if (err.ok()) err = db().Connect(dsn, std::forward(args)...); + if (err.ok()) { + err = db().Connect(dsn, std::forward(args)...); + } if (err.ok()) { loop_.spawn( [this] { @@ -303,7 +305,9 @@ std::string CommandsExecutor::getCurrentDsn(bool withPath) const { template Error CommandsExecutor::queryResultsToJson(std::ostream& o, const typename DBInterface::QueryResultsT& r, bool isWALQuery, bool fstream) { - if (cancelCtx_.IsCancelled()) return errOK; + if (cancelCtx_.IsCancelled()) { + return errOK; + } WrSerializer ser; size_t i = 0; bool scrollable = !fstream && !reindexer::isStdoutRedirected(); @@ -314,8 +318,12 @@ Error CommandsExecutor::queryResultsToJson(std::ostream& o, const t } bool prettyPrint = variables_[kVariableOutput] == kOutputModePretty; for (auto it : r) { - if (auto err = it.Status(); !err.ok()) return err; - if (cancelCtx_.IsCancelled()) break; + if (auto err = it.Status(); !err.ok()) { + return err; + } + if (cancelCtx_.IsCancelled()) { + break; + } if (isWALQuery) { ser << '#'; { @@ -337,19 +345,27 @@ Error CommandsExecutor::queryResultsToJson(std::ostream& o, const t return std::move(err); } } else { - if (isWALQuery) ser << "WalItemUpdate "; + if (isWALQuery) { + ser << "WalItemUpdate "; + } if (prettyPrint) { WrSerializer json; Error err = it.GetJSON(json, false); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } prettyPrintJSON(reindexer::giftStr(json.Slice()), ser); } else { Error err = it.GetJSON(ser, false); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } } - if ((++i != r.Count()) && !isWALQuery) ser << ','; + if ((++i != r.Count()) && !isWALQuery) { + ser << ','; + } ser << '\n'; if ((ser.Len() > 0x100000) || prettyPrint || scrollable) { if (scrollable && (i % (terminalSize.height - 1) == 0)) { @@ -376,7 +392,7 @@ Error CommandsExecutor::getAvailableDatabases(std::vector< } template -void CommandsExecutor::addCommandsSuggestions(std::string const& cmd, std::vector& suggestions) { +void CommandsExecutor::addCommandsSuggestions(const std::string& cmd, std::vector& suggestions) { LineParser parser(cmd); std::string_view token = parser.NextToken(); @@ -440,7 +456,9 @@ template void CommandsExecutor::checkForNsNameMatch(std::string_view str, std::vector& suggestions) { std::vector allNsDefs; Error err = db().EnumNamespaces(allNsDefs, reindexer::EnumNamespacesOpts().WithClosed()); - if (!err.ok()) return; + if (!err.ok()) { + return; + } for (auto& ns : allNsDefs) { if (str.empty() || reindexer::isBlank(str) || ((str.length() < ns.name.length()) && reindexer::checkIfStartsWith(str, ns.name))) { suggestions.emplace_back(ns.name); @@ -463,7 +481,9 @@ Error CommandsExecutor::processImpl(const std::string& command) noe LineParser parser(command); auto token = parser.NextToken(); - if (!token.length() || token.substr(0, 2) == "--") return errOK; + if (!token.length() || token.substr(0, 2) == "--") { + return errOK; + } Error ret; for (auto& c : cmds_) { @@ -561,7 +581,9 @@ Error CommandsExecutor::commandSelect(const std::string& command) n } if (!cancelCtx_.IsCancelled()) { output_() << "Returned " << results.Count() << " rows"; - if (results.TotalCount()) output_() << ", total count " << results.TotalCount(); + if (results.TotalCount()) { + output_() << ", total count " << results.TotalCount(); + } output_() << std::endl; } @@ -589,14 +611,18 @@ Error CommandsExecutor::commandSelect(const std::string& command) n rowWidth += mW; } for (size_t i = 0; i < agg.fields.size(); ++i) { - if (i != 0) output_() << "| "; + if (i != 0) { + output_() << "| "; + } output_() << std::left << std::setw(maxW.at(i)) << agg.fields[i]; } output_() << "| count" << std::endl; output_() << std::left << std::setw(rowWidth) << std::setfill('-') << "" << std::endl << std::setfill(' '); for (auto& row : agg.facets) { for (size_t i = 0; i < row.values.size(); ++i) { - if (i != 0) output_() << "| "; + if (i != 0) { + output_() << "| "; + } output_() << std::left << std::setw(maxW.at(i)) << row.values[i]; } output_() << "| " << row.count << std::endl; @@ -683,10 +709,14 @@ Error CommandsExecutor::commandDelete(const std::string& command) { auto nsName = reindexer::unescapeString(parser.NextToken()); auto item = db().NewItem(nsName); - if (!item.Status().ok()) return item.Status(); + if (!item.Status().ok()) { + return item.Status(); + } auto err = item.Unsafe().FromJSON(parser.CurPtr()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } return db().Delete(nsName, item); } @@ -714,7 +744,9 @@ Error CommandsExecutor::commandDump(const std::string& command) { std::vector allNsDefs, doNsDefs; auto err = db().WithContext(&cancelCtx_).EnumNamespaces(allNsDefs, reindexer::EnumNamespacesOpts()); - if (err) return err; + if (err) { + return err; + } if (!parser.End()) { // build list of namespaces for dumped @@ -739,7 +771,9 @@ Error CommandsExecutor::commandDump(const std::string& command) { for (auto& nsDef : doNsDefs) { // skip system namespaces, except #config - if (reindexer::isSystemNamespaceNameFast(nsDef.name) && nsDef.name != "#config") continue; + if (reindexer::isSystemNamespaceNameFast(nsDef.name) && nsDef.name != "#config") { + continue; + } wrser << "-- Dumping namespace '" << nsDef.name << "' ..." << '\n'; @@ -767,16 +801,22 @@ Error CommandsExecutor::commandDump(const std::string& command) { typename DBInterface::QueryResultsT itemResults; err = db().WithContext(&cancelCtx_).Select(Query(nsDef.name), itemResults); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (auto it : itemResults) { - if (auto err = it.Status(); !err.ok()) return err; + if (auto err = it.Status(); !err.ok()) { + return err; + } if (cancelCtx_.IsCancelled()) { return Error(errCanceled, "Canceled"); } wrser << "\\UPSERT " << reindexer::escapeString(nsDef.name) << ' '; err = it.GetJSON(wrser, false); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } wrser << '\n'; if (wrser.Len() > 0x100000) { output_() << wrser.Slice(); @@ -797,7 +837,7 @@ Error CommandsExecutor::commandNamespaces(const std::string& comman std::string_view subCommand = parser.NextToken(); if (iequals(subCommand, "add")) { - parser.NextToken(); // nsName + parser.NextToken(); // nsName NamespaceDef def(""); Error err = def.FromJSON(reindexer::giftStr(parser.CurPtr())); @@ -866,11 +906,15 @@ Error CommandsExecutor::commandMeta(const std::string& command) { auto nsName = reindexer::unescapeString(parser.NextToken()); std::vector allMeta; auto err = db().EnumMeta(nsName, allMeta); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (auto& metaKey : allMeta) { std::string metaData; err = db().GetMeta(nsName, metaKey, metaData); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } output_() << metaKey << " = " << metaData << std::endl; } return err; @@ -950,7 +994,9 @@ Error CommandsExecutor::commandBench(const std::string& command) { nsDef.AddIndex("id", "hash", "int", IndexOpts().PK()); err = db().AddNamespace(nsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } output_() << "Seeding " << kBenchItemsCount << " documents to bench namespace..." << std::endl; err = seedBenchItems(); @@ -968,8 +1014,12 @@ Error CommandsExecutor::commandBench(const std::string& command) { auto worker = std::bind(getBenchWorkerFn(count, errCount), deadline); const auto numThreads = std::min(std::max(numThreads_, 1u), 65535u); auto threads = std::unique_ptr(new std::thread[numThreads]); - for (unsigned i = 0; i < numThreads; i++) threads[i] = std::thread(worker); - for (unsigned i = 0; i < numThreads; i++) threads[i].join(); + for (unsigned i = 0; i < numThreads; i++) { + threads[i] = std::thread(worker); + } + for (unsigned i = 0; i < numThreads; i++) { + threads[i].join(); + } output_() << "Done. Got " << count / benchTime << " QPS, " << errCount << " errors" << std::endl; return err; @@ -1035,15 +1085,23 @@ Error CommandsExecutor::commandProcessDatabase if (subCommand == "list"sv) { std::vector dbList; Error err = getAvailableDatabases(dbList); - if (!err.ok()) return err; - for (const std::string& dbName : dbList) output_() << dbName << std::endl; + if (!err.ok()) { + return err; + } + for (const std::string& dbName : dbList) { + output_() << dbName << std::endl; + } return Error(); } else if (subCommand == "use"sv) { std::string currentDsn = getCurrentDsn() + std::string(parser.NextToken()); stop(false); auto err = db().Connect(currentDsn, loop_); - if (err.ok()) err = db().Status(); - if (err.ok()) output_() << "Succesfully connected to " << currentDsn << std::endl; + if (err.ok()) { + err = db().Status(); + } + if (err.ok()) { + output_() << "Succesfully connected to " << currentDsn << std::endl; + } return err; } else if (subCommand == "create"sv) { auto dbName = parser.NextToken(); @@ -1081,10 +1139,14 @@ Error CommandsExecutor::seedBenchItems() { JsonBuilder(ser).Put("id", i).Put("data", i); auto err = item.Unsafe().FromJSON(ser.Slice()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } err = db().Upsert(kBenchNamespace, item); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } return errOK; } @@ -1101,7 +1163,9 @@ Error CommandsExecutor::seedBenchItems() { JsonBuilder(ser).Put("id", i).Put("data", i); auto intErr = item.Unsafe().FromJSON(ser.Slice()); - if (intErr.ok()) intErr = db().Upsert(kBenchNamespace, item); + if (intErr.ok()) { + intErr = db().Upsert(kBenchNamespace, item); + } if (!intErr.ok()) { err = intErr; return; @@ -1144,7 +1208,9 @@ std::function CommandsExecutor CommandsExecutor::OnWALUpdate(reindexer::LSNPair LSNs, std::st template void CommandsExecutor::OnConnectionState(const Error& err) { - if (err.ok()) + if (err.ok()) { output_() << "[OnConnectionState] connected" << std::endl; - else + } else { output_() << "[OnConnectionState] closed, reason: " << err.what() << std::endl; + } } template diff --git a/cpp_src/cmd/reindexer_tool/commandsexecutor.h b/cpp_src/cmd/reindexer_tool/commandsexecutor.h index 2a6ff0af9..899940b86 100644 --- a/cpp_src/cmd/reindexer_tool/commandsexecutor.h +++ b/cpp_src/cmd/reindexer_tool/commandsexecutor.h @@ -73,7 +73,7 @@ class CommandsExecutor : public reindexer::IUpdatesObserver { Error queryResultsToJson(std::ostream& o, const typename DBInterface::QueryResultsT& r, bool isWALQuery, bool fstream); Error getAvailableDatabases(std::vector&); - void addCommandsSuggestions(std::string const& input, std::vector& suggestions); + void addCommandsSuggestions(const std::string& input, std::vector& suggestions); void checkForNsNameMatch(std::string_view str, std::vector& suggestions); void checkForCommandNameMatch(std::string_view str, std::initializer_list cmds, std::vector& suggestions); diff --git a/cpp_src/cmd/reindexer_tool/commandsprocessor.cc b/cpp_src/cmd/reindexer_tool/commandsprocessor.cc index 9f7cf47b1..fb435a0de 100644 --- a/cpp_src/cmd/reindexer_tool/commandsprocessor.cc +++ b/cpp_src/cmd/reindexer_tool/commandsprocessor.cc @@ -29,8 +29,8 @@ Error CommandsProcessor::process(const std::string& command) { #if REINDEX_WITH_REPLXX template template -void CommandsProcessor::setCompletionCallback(T& rx, void (T::*set_completion_callback)(new_v_callback_t const&)) { - (rx.*set_completion_callback)([this](std::string const& input, int) -> replxx::Replxx::completions_t { +void CommandsProcessor::setCompletionCallback(T& rx, void (T::*set_completion_callback)(const new_v_callback_t&)) { + (rx.*set_completion_callback)([this](const std::string& input, int) -> replxx::Replxx::completions_t { std::vector completions; const auto err = executor_.GetSuggestions(input, completions); replxx::Replxx::completions_t result; @@ -45,12 +45,14 @@ void CommandsProcessor::setCompletionCallback(T& rx, void (T::*set_ template template -void CommandsProcessor::setCompletionCallback(T& rx, void (T::*set_completion_callback)(old_v_callback_t const&, void*)) { +void CommandsProcessor::setCompletionCallback(T& rx, void (T::*set_completion_callback)(const old_v_callback_t&, void*)) { (rx.*set_completion_callback)( - [this](std::string const& input, int, void*) -> replxx::Replxx::completions_t { + [this](const std::string& input, int, void*) -> replxx::Replxx::completions_t { std::vector completions; const auto err = executor_.GetSuggestions(input, completions); - if (!err.ok()) return {}; + if (!err.ok()) { + return {}; + } return completions; }, nullptr); @@ -95,14 +97,18 @@ bool CommandsProcessor::interactive() { // main repl loop while (executor_.GetStatus().running) { - char const* input = nullptr; + const char* input = nullptr; do { input = rx.input(prompt); } while (!input && errno == EAGAIN); - if (input == nullptr) break; + if (input == nullptr) { + break; + } - if (!*input) continue; + if (!*input) { + continue; + } Error err = process(input); if (!err.ok()) { @@ -119,7 +125,9 @@ bool CommandsProcessor::interactive() { while (executor_.GetStatus().running) { std::string command; std::cout << prompt; - if (!std::getline(std::cin, command)) break; + if (!std::getline(std::cin, command)) { + break; + } Error err = process(command); if (!err.ok()) { std::cerr << "ERROR: " << err.what() << std::endl; diff --git a/cpp_src/cmd/reindexer_tool/commandsprocessor.h b/cpp_src/cmd/reindexer_tool/commandsprocessor.h index 85ed9df2d..46874628b 100644 --- a/cpp_src/cmd/reindexer_tool/commandsprocessor.h +++ b/cpp_src/cmd/reindexer_tool/commandsprocessor.h @@ -9,8 +9,8 @@ namespace reindexer_tool { #if REINDEX_WITH_REPLXX -typedef std::function old_v_callback_t; -typedef std::function new_v_callback_t; +typedef std::function old_v_callback_t; +typedef std::function new_v_callback_t; #endif // REINDEX_WITH_REPLXX template @@ -35,9 +35,9 @@ class CommandsProcessor { #if REINDEX_WITH_REPLXX template - void setCompletionCallback(T& rx, void (T::*set_completion_callback)(new_v_callback_t const&)); + void setCompletionCallback(T& rx, void (T::*set_completion_callback)(const new_v_callback_t&)); template - void setCompletionCallback(T& rx, void (T::*set_completion_callback)(old_v_callback_t const&, void*)); + void setCompletionCallback(T& rx, void (T::*set_completion_callback)(const old_v_callback_t&, void*)); #endif // REINDEX_WITH_REPLXX Error process(const std::string& command); diff --git a/cpp_src/cmd/reindexer_tool/iotools.h b/cpp_src/cmd/reindexer_tool/iotools.h index 2d0f04159..8f56648b0 100644 --- a/cpp_src/cmd/reindexer_tool/iotools.h +++ b/cpp_src/cmd/reindexer_tool/iotools.h @@ -17,7 +17,9 @@ class Output { } std::ostream& operator()() { - if (!isCout_ && !f_.is_open()) throw Error(errLogic, "%s", strerror(errState_)); + if (!isCout_ && !f_.is_open()) { + throw Error(errLogic, "%s", strerror(errState_)); + } return isCout_ ? std::cout : f_; } @@ -34,13 +36,19 @@ class LineParser { public: LineParser(const std::string& line) : line_(line), cur_(line.data()) {} std::string_view NextToken() { - while (*cur_ == ' ' || *cur_ == '\t') cur_++; + while (*cur_ == ' ' || *cur_ == '\t') { + cur_++; + } const char* next = cur_; - while (*next != ' ' && *next != '\t' && *next) next++; + while (*next != ' ' && *next != '\t' && *next) { + next++; + } std::string_view ret(cur_, next - cur_); cur_ = next; - while (*cur_ == ' ' || *cur_ == '\t') cur_++; + while (*cur_ == ' ' || *cur_ == '\t') { + cur_++; + } return ret; } bool End() { return *cur_ == 0; } diff --git a/cpp_src/cmd/reindexer_tool/reindexer_tool.cc b/cpp_src/cmd/reindexer_tool/reindexer_tool.cc index 2e2368a85..5ccc70ea9 100644 --- a/cpp_src/cmd/reindexer_tool/reindexer_tool.cc +++ b/cpp_src/cmd/reindexer_tool/reindexer_tool.cc @@ -35,7 +35,7 @@ static void InstallLogLevel(const std::vector& args) { std::cout << buf << std::endl; } }, - reindexer::LoggerPolicy::WithoutLocks); + reindexer::LoggerPolicy::WithoutLocks, llevel); } } // namespace reindexer_tool @@ -161,11 +161,15 @@ int main(int argc, char* argv[]) { CommandsProcessor commandsProcessor(args::get(outFileName), args::get(fileName), args::get(connThreads), config); err = commandsProcessor.Connect(dsn, reindexer::client::ConnectOpts().CreateDBIfMissing(createDBF && args::get(createDBF))); - if (err.ok()) ok = commandsProcessor.Run(args::get(command)); + if (err.ok()) { + ok = commandsProcessor.Run(args::get(command)); + } } else if (checkIfStartsWithCS("builtin://"sv, dsn)) { CommandsProcessor commandsProcessor(args::get(outFileName), args::get(fileName), args::get(connThreads)); err = commandsProcessor.Connect(dsn, ConnectOpts().DisableReplication()); - if (err.ok()) ok = commandsProcessor.Run(args::get(command)); + if (err.ok()) { + ok = commandsProcessor.Run(args::get(command)); + } } else { #ifdef _WIN32 std::cerr << "Invalid DSN format: " << dsn << " Must begin from cproto:// or builtin://" << std::endl; diff --git a/cpp_src/cmd/reindexer_tool/tableviewscroller.cc b/cpp_src/cmd/reindexer_tool/tableviewscroller.cc index 75ebf609e..dacf7f6f0 100644 --- a/cpp_src/cmd/reindexer_tool/tableviewscroller.cc +++ b/cpp_src/cmd/reindexer_tool/tableviewscroller.cc @@ -62,7 +62,9 @@ TableViewScroller::TableViewScroller(const QueryResultsT& r, rein template void TableViewScroller::Scroll(Output& output, const std::function& isCanceled) { - if (isCanceled()) return; + if (isCanceled()) { + return; + } reindexer::TerminalSize terminalSize = reindexer::getTerminalSize(); reindexer::TableCalculator tableCalculator(r_, terminalSize.width); @@ -71,7 +73,9 @@ void TableViewScroller::Scroll(Output& output, const std::functio #ifndef WIN32 FILE* pfile = nullptr; - if (viaMoreCmd) pfile = popen("more", "w"); + if (viaMoreCmd) { + pfile = popen("more", "w"); + } #else viaMoreCmd = false; #endif @@ -96,7 +100,9 @@ void TableViewScroller::Scroll(Output& output, const std::functio } #ifndef WIN32 - if (pfile) pclose(pfile); + if (pfile) { + pclose(pfile); + } #endif } diff --git a/cpp_src/core/activity_context.cc b/cpp_src/core/activity_context.cc index af2c7d52c..3027cc1e2 100644 --- a/cpp_src/core/activity_context.cc +++ b/cpp_src/core/activity_context.cc @@ -28,7 +28,9 @@ void ActivityContainer::Unregister(const RdxActivityContext* context) { } void ActivityContainer::Reregister(const RdxActivityContext* oldCtx, const RdxActivityContext* newCtx) { - if (oldCtx == newCtx) return; + if (oldCtx == newCtx) { + return; + } std::unique_lock lck(mtx_); const auto eraseCount = cont_.erase(oldCtx); @@ -46,7 +48,9 @@ std::vector ActivityContainer::List() { { std::lock_guard lck(mtx_); ret.reserve(cont_.size()); - for (const RdxActivityContext* ctx : cont_) ret.emplace_back(*ctx); + for (const RdxActivityContext* ctx : cont_) { + ret.emplace_back(*ctx); + } } return ret; } @@ -86,7 +90,9 @@ void Activity::GetJSON(WrSerializer& ser) const { using namespace std::chrono; JsonBuilder builder(ser); builder.Put("client", activityTracer); - if (!user.empty()) builder.Put("user", user); + if (!user.empty()) { + builder.Put("user", user); + } builder.Put("query", query); builder.Put("query_id", id); std::time_t t = system_clock_w::to_time_t(startTime); @@ -96,7 +102,9 @@ void Activity::GetJSON(WrSerializer& ser) const { ss << buffer << '.' << std::setw(3) << std::setfill('0') << (duration_cast(startTime.time_since_epoch()).count() % 1000); builder.Put("query_start", ss.str()); builder.Put("state", DescribeState(state)); - if (state == WaitLock) builder.Put("lock_description", "Wait lock for " + std::string(description)); + if (state == WaitLock) { + builder.Put("lock_description", "Wait lock for " + std::string(description)); + } builder.End(); } @@ -105,18 +113,16 @@ RdxActivityContext::RdxActivityContext(std::string_view activityTracer, std::str : data_{nextId(), std::string(activityTracer), std::string(user), std::string(query), ipConnectionId, Activity::InProgress, system_clock_w::now(), ""sv}, state_(serializeState(clientState ? Activity::Sending : Activity::InProgress)), - parent_(&parent) -{ + parent_(&parent) { parent_->Register(this); } // NOLINTNEXTLINE (performance-noexcept-move-constructor) RdxActivityContext::RdxActivityContext(RdxActivityContext&& other) - : data_(other.data_), - state_(other.state_.load(std::memory_order_relaxed)), - parent_(other.parent_) -{ - if (parent_) parent_->Reregister(&other, this); + : data_(other.data_), state_(other.state_.load(std::memory_order_relaxed)), parent_(other.parent_) { + if (parent_) { + parent_->Reregister(&other, this); + } other.parent_ = nullptr; } diff --git a/cpp_src/core/activity_context.h b/cpp_src/core/activity_context.h index b6780f5b6..f8cef62df 100644 --- a/cpp_src/core/activity_context.h +++ b/cpp_src/core/activity_context.h @@ -94,7 +94,9 @@ class RdxActivityContext { int ipConnectionId, bool clientState = false); RdxActivityContext(RdxActivityContext&&); ~RdxActivityContext() { - if (parent_) parent_->Unregister(this); + if (parent_) { + parent_->Unregister(this); + } assertrx(refCount_.load(std::memory_order_relaxed) == 0u); } operator Activity() const; diff --git a/cpp_src/core/cbinding/reindexer_c.cc b/cpp_src/core/cbinding/reindexer_c.cc index a7f21ffbc..0aa64b49b 100644 --- a/cpp_src/core/cbinding/reindexer_c.cc +++ b/cpp_src/core/cbinding/reindexer_c.cc @@ -449,17 +449,25 @@ reindexer_error reindexer_connect(uintptr_t rx, reindexer_string dsn, ConnectOpt } Reindexer* db = reinterpret_cast(rx); - if (!db) return error2c(err_not_init); + if (!db) { + return error2c(err_not_init); + } Error err = db->Connect(str2c(dsn), opts); - if (err.ok() && db->NeedTraceActivity()) db->SetActivityTracer("builtin", ""); + if (err.ok() && db->NeedTraceActivity()) { + db->SetActivityTracer("builtin", ""); + } return error2c(err); } reindexer_error reindexer_init_system_namespaces(uintptr_t rx) { Reindexer* db = reinterpret_cast(rx); - if (!db) return error2c(err_not_init); + if (!db) { + return error2c(err_not_init); + } Error err = db->InitSystemNamespaces(); - if (err.ok() && db->NeedTraceActivity()) db->SetActivityTracer("builtin", ""); + if (err.ok() && db->NeedTraceActivity()) { + db->SetActivityTracer("builtin", ""); + } return error2c(err); } @@ -520,7 +528,9 @@ reindexer_ret reindexer_select_query(uintptr_t rx, struct reindexer_buffer in, i ActiveQueryScope scope(q, QuerySelect); err = rdxKeeper.db().Select(q, *result); - if (q.GetDebugLevel() >= LogError && err.code() != errOK) logPrintf(LogError, "Query error %s", err.what()); + if (q.GetDebugLevel() >= LogError && err.code() != errOK) { + logPrintf(LogError, "Query error %s", err.what()); + } if (err.ok()) { results2c(std::move(result), &out, as_json, pt_versions, pt_versions_count); } else { @@ -555,7 +565,9 @@ reindexer_ret reindexer_delete_query(uintptr_t rx, reindexer_buffer in, reindexe ActiveQueryScope scope(q, QueryDelete); res = rdxKeeper.db().Delete(q, *result); - if (q.GetDebugLevel() >= LogError && res.code() != errOK) logPrintf(LogError, "Query error %s", res.what()); + if (q.GetDebugLevel() >= LogError && res.code() != errOK) { + logPrintf(LogError, "Query error %s", res.what()); + } if (res.ok()) { results2c(std::move(result), &out); } @@ -584,7 +596,9 @@ reindexer_ret reindexer_update_query(uintptr_t rx, reindexer_buffer in, reindexe ActiveQueryScope scope(q, QueryUpdate); res = rdxKeeper.db().Update(q, *result); - if (q.GetDebugLevel() >= LogError && res.code() != errOK) logPrintf(LogError, "Query error %s", res.what()); + if (q.GetDebugLevel() >= LogError && res.code() != errOK) { + logPrintf(LogError, "Query error %s", res.what()); + } if (res.ok()) { int32_t ptVers = -1; results2c(std::move(result), &out, 0, &ptVers, 1); @@ -737,9 +751,9 @@ reindexer_error reindexer_commit(uintptr_t rx, reindexer_string nsName) { return error2c(!db ? err_not_init : db->Commit(str2cv(nsName))); } -void reindexer_enable_logger(void (*logWriter)(int, char*)) { logInstallWriter(logWriter, LoggerPolicy::WithLocks); } +void reindexer_enable_logger(void (*logWriter)(int, char*)) { logInstallWriter(logWriter, LoggerPolicy::WithLocks, int(LogTrace)); } -void reindexer_disable_logger() { logInstallWriter(nullptr, LoggerPolicy::WithLocks); } +void reindexer_disable_logger() { logInstallWriter(nullptr, LoggerPolicy::WithLocks, int(LogNone)); } reindexer_error reindexer_free_buffer(reindexer_resbuffer in) { constexpr static put_results_to_pool putResultsToPool; diff --git a/cpp_src/core/cbinding/reindexer_c.h b/cpp_src/core/cbinding/reindexer_c.h index 5b2129040..cc1fc55c6 100644 --- a/cpp_src/core/cbinding/reindexer_c.h +++ b/cpp_src/core/cbinding/reindexer_c.h @@ -5,8 +5,8 @@ extern "C" { #endif #include -#include "reindexer_ctypes.h" #include "core/type_consts.h" +#include "reindexer_ctypes.h" uintptr_t init_reindexer(); uintptr_t init_reindexer_with_config(reindexer_config config); @@ -41,10 +41,10 @@ reindexer_ret reindexer_commit_transaction(uintptr_t rx, uintptr_t tr, reindexer reindexer_error reindexer_rollback_transaction(uintptr_t rx, uintptr_t tr); reindexer_ret reindexer_modify_item_packed(uintptr_t rx, reindexer_buffer args, reindexer_buffer data, reindexer_ctx_info ctx_info); -reindexer_ret reindexer_select(uintptr_t rx, reindexer_string query, int as_json, int32_t *pt_versions, int pt_versions_count, +reindexer_ret reindexer_select(uintptr_t rx, reindexer_string query, int as_json, int32_t* pt_versions, int pt_versions_count, reindexer_ctx_info ctx_info); -reindexer_ret reindexer_select_query(uintptr_t rx, reindexer_buffer in, int as_json, int32_t *pt_versions, int pt_versions_count, +reindexer_ret reindexer_select_query(uintptr_t rx, reindexer_buffer in, int as_json, int32_t* pt_versions, int pt_versions_count, reindexer_ctx_info ctx_info); reindexer_ret reindexer_delete_query(uintptr_t rx, reindexer_buffer in, reindexer_ctx_info ctx_info); reindexer_ret reindexer_update_query(uintptr_t rx, reindexer_buffer in, reindexer_ctx_info ctx_info); @@ -53,7 +53,7 @@ reindexer_buffer reindexer_cptr2cjson(uintptr_t results_ptr, uintptr_t cptr, int void reindexer_free_cjson(reindexer_buffer b); reindexer_error reindexer_free_buffer(reindexer_resbuffer in); -reindexer_error reindexer_free_buffers(reindexer_resbuffer *in, int count); +reindexer_error reindexer_free_buffers(reindexer_resbuffer* in, int count); reindexer_error reindexer_commit(uintptr_t rx, reindexer_string nsName); @@ -65,7 +65,7 @@ reindexer_error reindexer_delete_meta(uintptr_t rx, reindexer_string ns, reindex reindexer_error reindexer_cancel_context(reindexer_ctx_info ctx_info, ctx_cancel_type how); -void reindexer_enable_logger(void (*logWriter)(int level, char *msg)); +void reindexer_enable_logger(void (*logWriter)(int level, char* msg)); void reindexer_disable_logger(); void reindexer_init_locale(); diff --git a/cpp_src/core/cbinding/reindexer_ctypes.h b/cpp_src/core/cbinding/reindexer_ctypes.h index 32e4188c7..07d6fcdee 100644 --- a/cpp_src/core/cbinding/reindexer_ctypes.h +++ b/cpp_src/core/cbinding/reindexer_ctypes.h @@ -12,7 +12,7 @@ typedef struct reindexer_config { } reindexer_config; typedef struct reindexer_buffer { - uint8_t *data; + uint8_t* data; int len; } reindexer_buffer; @@ -24,12 +24,12 @@ typedef struct reindexer_resbuffer { } reindexer_resbuffer; typedef struct reindexer_error { - const char *what; + const char* what; int code; } reindexer_error; typedef struct reindexer_string { - void *p; + void* p; int32_t n; int8_t reserved[4]; } reindexer_string; diff --git a/cpp_src/core/cbinding/resultserializer.cc b/cpp_src/core/cbinding/resultserializer.cc index a5085e52a..0c0041566 100644 --- a/cpp_src/core/cbinding/resultserializer.cc +++ b/cpp_src/core/cbinding/resultserializer.cc @@ -41,7 +41,9 @@ void WrResultSerializer::putQueryParams(const QueryResults* results) { for (int i = 0; i < totalCnt; i++) { const TagsMatcher& tm = results->getTagsMatcher(i); - if (int32_t(tm.version() ^ tm.stateToken()) != opts_.ptVersions[i]) cnt++; + if (int32_t(tm.version() ^ tm.stateToken()) != opts_.ptVersions[i]) { + cnt++; + } } PutVarUint(cnt); for (int i = 0; i < totalCnt; i++) { @@ -149,7 +151,9 @@ void WrResultSerializer::putItemParams(const QueryResults* result, int idx, bool default: throw Error(errParams, "Can't serialize query results: unknown format %d", int((opts_.flags & kResultsFormatMask))); } - if (!err.ok()) throw Error(errParseBin, "Internal error serializing query results: %s", err.what()); + if (!err.ok()) { + throw Error(errParseBin, "Internal error serializing query results: %s", err.what()); + } } void WrResultSerializer::putPayloadType(const QueryResults* results, int nsid) { @@ -180,14 +184,24 @@ bool WrResultSerializer::PutResults(const QueryResults* result) { } // Result has items from multiple namespaces, so pass nsid to each item - if (result->getMergedNSCount() > 1) opts_.flags |= kResultsWithNsID; + if (result->getMergedNSCount() > 1) { + opts_.flags |= kResultsWithNsID; + } // Result has joined items, so pass them to client within items from main NS - if (result->joined_.size() > 0) opts_.flags |= kResultsWithJoined; + if (result->joined_.size() > 0) { + opts_.flags |= kResultsWithJoined; + } - if (result->haveRank) opts_.flags |= kResultsWithRank; - if (result->needOutputRank) opts_.flags |= kResultsNeedOutputRank; + if (result->haveRank) { + opts_.flags |= kResultsWithRank; + } + if (result->needOutputRank) { + opts_.flags |= kResultsNeedOutputRank; + } // If data is not cacheable, just do not pass item's ID and LSN. Clients should not cache this data - if (result->nonCacheableData) opts_.flags &= ~kResultsWithItemID; + if (result->nonCacheableData) { + opts_.flags &= ~kResultsWithItemID; + } // MsgPack items contain fields names so there is no need to transfer payload types // and joined data, as well as for JSON (they both contain it already) if ((opts_.flags & kResultsFormatMask) == kResultsJson || (opts_.flags & kResultsFormatMask) == kResultsMsgPack) { @@ -212,15 +226,21 @@ bool WrResultSerializer::PutResults(const QueryResults* result) { } for (auto it = jIt.begin(), end = jIt.end(); it != end; ++it, ++joinedField) { PutVarUint(it.ItemsCount()); - if (it.ItemsCount() == 0) continue; + if (it.ItemsCount() == 0) { + continue; + } QueryResults qr = it.ToQueryResults(); qr.addNSContext(result->getPayloadType(joinedField), result->getTagsMatcher(joinedField), result->getFieldsFilter(joinedField), result->getSchema(joinedField)); - for (size_t idx = 0, qrCnt = qr.Count(); idx < qrCnt; ++idx) putItemParams(&qr, idx, false); + for (size_t idx = 0, qrCnt = qr.Count(); idx < qrCnt; ++idx) { + putItemParams(&qr, idx, false); + } } } } - if (i == 0) grow((opts_.fetchLimit - 1) * (len_ - saveLen)); + if (i == 0) { + grow((opts_.fetchLimit - 1) * (len_ - saveLen)); + } } return opts_.fetchOffset + opts_.fetchLimit >= result->Count(); } diff --git a/cpp_src/core/cjson/baseencoder.cc b/cpp_src/core/cjson/baseencoder.cc index 5b6dfe564..992a268a6 100644 --- a/cpp_src/core/cjson/baseencoder.cc +++ b/cpp_src/core/cjson/baseencoder.cc @@ -27,8 +27,7 @@ void BaseEncoder::Encode(std::string_view tuple, Builder& builder, IAdd [[maybe_unused]] const ctag begTag = rdser.GetCTag(); assertrx(begTag.Type() == TAG_OBJECT); Builder objNode = builder.Object(nullptr); - while (encode(nullptr, rdser, objNode, true)) - ; + while (encode(nullptr, rdser, objNode, true)); if (ds) { assertrx(!ds->GetJoinsDatasource()); ds->PutAdditionalFields(objNode); @@ -51,8 +50,7 @@ void BaseEncoder::Encode(ConstPayload& pl, Builder& builder, IAdditiona [[maybe_unused]] const ctag begTag = rdser.GetCTag(); assertrx(begTag.Type() == TAG_OBJECT); Builder objNode = builder.Object(nullptr); - while (encode(&pl, rdser, objNode, true)) - ; + while (encode(&pl, rdser, objNode, true)); if (ds) { if (const auto joinsDs = ds->GetJoinsDatasource()) { @@ -93,7 +91,9 @@ const TagsLengths& BaseEncoder::GetTagsMeasures(ConstPayload& pl, IEnco template void BaseEncoder::collectJoinedItemsTagsSizes(IEncoderDatasourceWithJoins* ds, size_t rowid) { const size_t itemsCount = ds->GetJoinedRowItemsCount(rowid); - if (!itemsCount) return; + if (!itemsCount) { + return; + } BaseEncoder subEnc(&ds->GetJoinedItemTagsMatcher(rowid), &ds->GetJoinedItemFieldsFilter(rowid)); for (size_t i = 0; i < itemsCount; ++i) { @@ -105,7 +105,9 @@ void BaseEncoder::collectJoinedItemsTagsSizes(IEncoderDatasourceWithJoi template void BaseEncoder::encodeJoinedItems(Builder& builder, IEncoderDatasourceWithJoins* ds, size_t rowid) { const size_t itemsCount = ds->GetJoinedRowItemsCount(rowid); - if (!itemsCount) return; + if (!itemsCount) { + return; + } std::string nsTagName("joined_" + ds->GetJoinedItemNamespace(rowid)); auto arrNode = builder.Array(nsTagName); @@ -144,7 +146,9 @@ bool BaseEncoder::encode(ConstPayload* pl, Serializer& rdser, Builder& // get field from indexed field if (tagField >= 0) { - if (!pl) throw Error(errParams, "Trying to encode index field %d without payload", tagField); + if (!pl) { + throw Error(errParams, "Trying to encode index field %d without payload", tagField); + } const auto& f = pl->Type().Field(tagField); if (!f.IsArray() && objectScalarIndexes_.test(tagField)) { throw Error(errParams, "Non-array field '%s' [%d] from '%s' can only be encoded once.", f.Name(), tagField, pl->Type().Name()); @@ -172,7 +176,9 @@ bool BaseEncoder::encode(ConstPayload* pl, Serializer& rdser, Builder& } case TAG_NULL: objectScalarIndexes_.set(tagField); - if (visible) builder.Null(tagName); + if (visible) { + builder.Null(tagName); + } break; case TAG_VARINT: case TAG_DOUBLE: @@ -182,7 +188,9 @@ bool BaseEncoder::encode(ConstPayload* pl, Serializer& rdser, Builder& case TAG_OBJECT: case TAG_UUID: objectScalarIndexes_.set(tagField); - if (visible) builder.Put(tagName, pl->Get(tagField, cnt), cnt); + if (visible) { + builder.Put(tagName, pl->Get(tagField, cnt), cnt); + } ++cnt; break; } @@ -210,19 +218,19 @@ bool BaseEncoder::encode(ConstPayload* pl, Serializer& rdser, Builder& builder.Array(tagName, rdser, atagType, atagCount); } else { const KeyValueType kvt{atagType}; - for (size_t i = 0; i < atagCount; ++i) rdser.SkipRawVariant(kvt); + for (size_t i = 0; i < atagCount; ++i) { + rdser.SkipRawVariant(kvt); + } } break; } case TAG_OBJECT: { if (visible) { auto objNode = builder.Object(tagName); - while (encode(pl, rdser, objNode, true)) - ; + while (encode(pl, rdser, objNode, true)); } else { thread_local static Builder objNode; - while (encode(pl, rdser, objNode, false)) - ; + while (encode(pl, rdser, objNode, false)); } break; } @@ -320,7 +328,9 @@ bool BaseEncoder::collectTagsSizes(ConstPayload& pl, Serializer& rdser) } } } - if (tagName && filter_) curTagsPath_.pop_back(); + if (tagName && filter_) { + curTagsPath_.pop_back(); + } return true; } diff --git a/cpp_src/core/cjson/baseencoder.h b/cpp_src/core/cjson/baseencoder.h index 1ad04b51c..9eafa4808 100644 --- a/cpp_src/core/cjson/baseencoder.h +++ b/cpp_src/core/cjson/baseencoder.h @@ -23,26 +23,26 @@ class IEncoderDatasourceWithJoins { virtual size_t GetJoinedRowsCount() const noexcept = 0; virtual size_t GetJoinedRowItemsCount(size_t rowId) const = 0; virtual ConstPayload GetJoinedItemPayload(size_t rowid, size_t plIndex) const = 0; - virtual const std::string &GetJoinedItemNamespace(size_t rowid) const noexcept = 0; - virtual const TagsMatcher &GetJoinedItemTagsMatcher(size_t rowid) noexcept = 0; - virtual const FieldsSet &GetJoinedItemFieldsFilter(size_t rowid) noexcept = 0; + virtual const std::string& GetJoinedItemNamespace(size_t rowid) const noexcept = 0; + virtual const TagsMatcher& GetJoinedItemTagsMatcher(size_t rowid) noexcept = 0; + virtual const FieldsSet& GetJoinedItemFieldsFilter(size_t rowid) noexcept = 0; }; template class IAdditionalDatasource { public: - virtual void PutAdditionalFields(Builder &) const = 0; - virtual IEncoderDatasourceWithJoins *GetJoinsDatasource() noexcept = 0; + virtual void PutAdditionalFields(Builder&) const = 0; + virtual IEncoderDatasourceWithJoins* GetJoinsDatasource() noexcept = 0; }; template class BaseEncoder { public: - BaseEncoder(const TagsMatcher *tagsMatcher, const FieldsSet *filter = nullptr); - void Encode(ConstPayload &pl, Builder &builder, IAdditionalDatasource * = nullptr); - void Encode(std::string_view tuple, Builder &wrSer, IAdditionalDatasource *); + BaseEncoder(const TagsMatcher* tagsMatcher, const FieldsSet* filter = nullptr); + void Encode(ConstPayload& pl, Builder& builder, IAdditionalDatasource* = nullptr); + void Encode(std::string_view tuple, Builder& wrSer, IAdditionalDatasource*); - const TagsLengths &GetTagsMeasures(ConstPayload &pl, IEncoderDatasourceWithJoins *ds = nullptr); + const TagsLengths& GetTagsMeasures(ConstPayload& pl, IEncoderDatasourceWithJoins* ds = nullptr); protected: using IndexedTagsPathInternalT = IndexedTagsPathImpl<16>; @@ -50,20 +50,20 @@ class BaseEncoder { constexpr static bool kWithFieldExtractor = std::is_same_v; struct DummyTagsPathScope { - DummyTagsPathScope(TagsPath & /*tagsPath*/, int16_t /*tagName*/) noexcept {} + DummyTagsPathScope(TagsPath& /*tagsPath*/, int16_t /*tagName*/) noexcept {} }; using PathScopeT = std::conditional_t, DummyTagsPathScope>; - bool encode(ConstPayload *pl, Serializer &rdser, Builder &builder, bool visible); - void encodeJoinedItems(Builder &builder, IEncoderDatasourceWithJoins *ds, size_t joinedIdx); - bool collectTagsSizes(ConstPayload &pl, Serializer &rdser); - void collectJoinedItemsTagsSizes(IEncoderDatasourceWithJoins *ds, size_t rowid); + bool encode(ConstPayload* pl, Serializer& rdser, Builder& builder, bool visible); + void encodeJoinedItems(Builder& builder, IEncoderDatasourceWithJoins* ds, size_t joinedIdx); + bool collectTagsSizes(ConstPayload& pl, Serializer& rdser); + void collectJoinedItemsTagsSizes(IEncoderDatasourceWithJoins* ds, size_t rowid); - std::string_view getPlTuple(ConstPayload &pl); + std::string_view getPlTuple(ConstPayload& pl); - const TagsMatcher *tagsMatcher_; + const TagsMatcher* tagsMatcher_; std::array fieldsoutcnt_{0}; - const FieldsSet *filter_; + const FieldsSet* filter_; WrSerializer tmpPlTuple_; TagsPath curTagsPath_; IndexedTagsPathInternalT indexedTagsPath_; diff --git a/cpp_src/core/cjson/cjsonbuilder.cc b/cpp_src/core/cjson/cjsonbuilder.cc index 9c32c5c4d..9273e5b11 100644 --- a/cpp_src/core/cjson/cjsonbuilder.cc +++ b/cpp_src/core/cjson/cjsonbuilder.cc @@ -2,7 +2,7 @@ namespace reindexer { -CJsonBuilder::CJsonBuilder(WrSerializer &ser, ObjType type, const TagsMatcher *tm, int tagName) : tm_(tm), ser_(&ser), type_(type) { +CJsonBuilder::CJsonBuilder(WrSerializer& ser, ObjType type, const TagsMatcher* tm, int tagName) : tm_(tm), ser_(&ser), type_(type) { switch (type_) { case ObjType::TypeArray: case ObjType::TypeObjectArray: @@ -39,7 +39,7 @@ void CJsonBuilder::Array(int tagName, span data, int /*offset*/) { } } -CJsonBuilder &CJsonBuilder::Put(int tagName, bool arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, bool arg, int /*offset*/) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_BOOL; } else { @@ -50,7 +50,7 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, bool arg, int /*offset*/) { return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, int64_t arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, int64_t arg, int /*offset*/) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_VARINT; } else { @@ -61,7 +61,7 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, int64_t arg, int /*offset*/) { return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, int arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, int arg, int /*offset*/) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_VARINT; } else { @@ -72,7 +72,7 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, int arg, int /*offset*/) { return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, double arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, double arg, int /*offset*/) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_DOUBLE; } else { @@ -83,7 +83,7 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, double arg, int /*offset*/) { return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, std::string_view arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, std::string_view arg, int /*offset*/) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_STRING; } else { @@ -94,13 +94,13 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, std::string_view arg, int /*offset* return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, Uuid arg, int /*offset*/) { +CJsonBuilder& CJsonBuilder::Put(int tagName, Uuid arg, int /*offset*/) { ser_->PutCTag(ctag{TAG_UUID, tagName}); ser_->PutUuid(arg); return *this; } -CJsonBuilder &CJsonBuilder::Null(int tagName) { +CJsonBuilder& CJsonBuilder::Null(int tagName) { if (type_ == ObjType::TypeArray) { itemType_ = TAG_NULL; } else { @@ -110,37 +110,24 @@ CJsonBuilder &CJsonBuilder::Null(int tagName) { return *this; } -CJsonBuilder &CJsonBuilder::Ref(int tagName, const Variant &v, int field) { - v.Type().EvaluateOneOf( - [&](OneOf) { - ser_->PutCTag(ctag{TAG_VARINT, tagName, field}); - }, - [&](KeyValueType::Bool) { - ser_->PutCTag(ctag{TAG_BOOL, tagName, field}); - }, - [&](KeyValueType::Double) { - ser_->PutCTag(ctag{TAG_DOUBLE, tagName, field}); - }, - [&](KeyValueType::String) { - ser_->PutCTag(ctag{TAG_STRING, tagName, field}); - }, - [&](KeyValueType::Uuid) { - ser_->PutCTag(ctag{TAG_UUID, tagName, field}); - }, - [&](OneOf) { - ser_->PutCTag(ctag{TAG_NULL, tagName}); - }, - [](OneOf) noexcept { std::abort(); }); +CJsonBuilder& CJsonBuilder::Ref(int tagName, const Variant& v, int field) { + v.Type().EvaluateOneOf([&](OneOf) { ser_->PutCTag(ctag{TAG_VARINT, tagName, field}); }, + [&](KeyValueType::Bool) { ser_->PutCTag(ctag{TAG_BOOL, tagName, field}); }, + [&](KeyValueType::Double) { ser_->PutCTag(ctag{TAG_DOUBLE, tagName, field}); }, + [&](KeyValueType::String) { ser_->PutCTag(ctag{TAG_STRING, tagName, field}); }, + [&](KeyValueType::Uuid) { ser_->PutCTag(ctag{TAG_UUID, tagName, field}); }, + [&](OneOf) { ser_->PutCTag(ctag{TAG_NULL, tagName}); }, + [](OneOf) noexcept { std::abort(); }); return *this; } -CJsonBuilder &CJsonBuilder::ArrayRef(int tagName, int field, int count) { +CJsonBuilder& CJsonBuilder::ArrayRef(int tagName, int field, int count) { ser_->PutCTag(ctag{TAG_ARRAY, tagName, field}); ser_->PutVarUint(count); return *this; } -CJsonBuilder &CJsonBuilder::Put(int tagName, const Variant &kv, int offset) { +CJsonBuilder& CJsonBuilder::Put(int tagName, const Variant& kv, int offset) { kv.Type().EvaluateOneOf([&](KeyValueType::Int) { Put(tagName, int(kv), offset); }, [&](KeyValueType::Int64) { Put(tagName, int64_t(kv), offset); }, [&](KeyValueType::Double) { Put(tagName, double(kv), offset); }, @@ -148,7 +135,7 @@ CJsonBuilder &CJsonBuilder::Put(int tagName, const Variant &kv, int offset) { [&](KeyValueType::Null) { Null(tagName); }, [&](KeyValueType::Bool) { Put(tagName, bool(kv), offset); }, [&](KeyValueType::Tuple) { auto arrNode = Array(tagName); - for (auto &val : kv.getCompositeValues()) { + for (auto& val : kv.getCompositeValues()) { arrNode.Put(nullptr, val); } }, diff --git a/cpp_src/core/cjson/cjsonbuilder.h b/cpp_src/core/cjson/cjsonbuilder.h index ed3d79c8d..4ecd4a7bf 100644 --- a/cpp_src/core/cjson/cjsonbuilder.h +++ b/cpp_src/core/cjson/cjsonbuilder.h @@ -7,23 +7,23 @@ namespace reindexer { -void copyCJsonValue(TagType tagType, Serializer &rdser, WrSerializer &wrser); +void copyCJsonValue(TagType tagType, Serializer& rdser, WrSerializer& wrser); class CJsonBuilder { public: - CJsonBuilder(WrSerializer &ser, ObjType = ObjType::TypeObject, const TagsMatcher *tm = nullptr, int tagName = 0); + CJsonBuilder(WrSerializer& ser, ObjType = ObjType::TypeObject, const TagsMatcher* tm = nullptr, int tagName = 0); CJsonBuilder() noexcept : tm_(nullptr), ser_(nullptr), type_(ObjType::TypePlain) {} ~CJsonBuilder() { End(); } - CJsonBuilder(const CJsonBuilder &) = delete; - CJsonBuilder(CJsonBuilder &&other) noexcept + CJsonBuilder(const CJsonBuilder&) = delete; + CJsonBuilder(CJsonBuilder&& other) noexcept : tm_(other.tm_), ser_(other.ser_), type_(other.type_), savePos_(other.savePos_), count_(other.count_), itemType_(other.itemType_) { other.type_ = ObjType::TypePlain; } - CJsonBuilder &operator=(const CJsonBuilder &) = delete; - CJsonBuilder &operator=(CJsonBuilder &&) = delete; + CJsonBuilder& operator=(const CJsonBuilder&) = delete; + CJsonBuilder& operator=(CJsonBuilder&&) = delete; - void SetTagsMatcher(const TagsMatcher *tm) noexcept { tm_ = tm; } + void SetTagsMatcher(const TagsMatcher* tm) noexcept { tm_ = tm; } /// Start new object CJsonBuilder Object(int tagName); @@ -37,62 +37,74 @@ class CJsonBuilder { void Array(int tagName, span data, int /*offset*/ = 0) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(data.size(), TAG_STRING)); - for (auto d : data) ser_->PutVString(d); + for (auto d : data) { + ser_->PutVString(d); + } } void Array(int tagName, span data, int offset = 0); void Array(int tagName, span data, int /*offset*/ = 0) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(data.size(), TAG_VARINT)); - for (auto d : data) ser_->PutVarint(d); + for (auto d : data) { + ser_->PutVarint(d); + } } void Array(int tagName, span data, int /*offset*/ = 0) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(data.size(), TAG_VARINT)); - for (auto d : data) ser_->PutVarint(d); + for (auto d : data) { + ser_->PutVarint(d); + } } void Array(int tagName, span data, int /*offset*/ = 0) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(data.size(), TAG_BOOL)); - for (auto d : data) ser_->PutBool(d); + for (auto d : data) { + ser_->PutBool(d); + } } void Array(int tagName, span data, int /*offset*/ = 0) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(data.size(), TAG_DOUBLE)); - for (auto d : data) ser_->PutDouble(d); + for (auto d : data) { + ser_->PutDouble(d); + } } - void Array(int tagName, Serializer &ser, TagType tagType, int count) { + void Array(int tagName, Serializer& ser, TagType tagType, int count) { ser_->PutCTag(ctag{TAG_ARRAY, tagName}); ser_->PutCArrayTag(carraytag(count, tagType)); - while (count--) copyCJsonValue(tagType, ser, *ser_); + while (count--) { + copyCJsonValue(tagType, ser, *ser_); + } } template - CJsonBuilder &Put(std::nullptr_t, const T &arg, int offset = 0) { + CJsonBuilder& Put(std::nullptr_t, const T& arg, int offset = 0) { return Put(0, arg, offset); } void Write(std::string_view data) { ser_->Write(data); } - CJsonBuilder &Null(std::nullptr_t) { return Null(0); } - - CJsonBuilder &Put(int tagName, bool arg, int offset = 0); - CJsonBuilder &Put(int tagName, int arg, int offset = 0); - CJsonBuilder &Put(int tagName, int64_t arg, int offset = 0); - CJsonBuilder &Put(int tagName, double arg, int offset = 0); - CJsonBuilder &Put(int tagName, std::string_view arg, int offset = 0); - CJsonBuilder &Put(int tagName, Uuid arg, int offset = 0); - CJsonBuilder &Ref(int tagName, const Variant &v, int field); - CJsonBuilder &ArrayRef(int tagName, int field, int count); - CJsonBuilder &Null(int tagName); - CJsonBuilder &Put(int tagName, const Variant &kv, int offset = 0); - CJsonBuilder &Put(int tagName, const char *arg, int offset = 0) { return Put(tagName, std::string_view(arg), offset); } - CJsonBuilder &End() { + CJsonBuilder& Null(std::nullptr_t) { return Null(0); } + + CJsonBuilder& Put(int tagName, bool arg, int offset = 0); + CJsonBuilder& Put(int tagName, int arg, int offset = 0); + CJsonBuilder& Put(int tagName, int64_t arg, int offset = 0); + CJsonBuilder& Put(int tagName, double arg, int offset = 0); + CJsonBuilder& Put(int tagName, std::string_view arg, int offset = 0); + CJsonBuilder& Put(int tagName, Uuid arg, int offset = 0); + CJsonBuilder& Ref(int tagName, const Variant& v, int field); + CJsonBuilder& ArrayRef(int tagName, int field, int count); + CJsonBuilder& Null(int tagName); + CJsonBuilder& Put(int tagName, const Variant& kv, int offset = 0); + CJsonBuilder& Put(int tagName, const char* arg, int offset = 0) { return Put(tagName, std::string_view(arg), offset); } + CJsonBuilder& End() { switch (type_) { case ObjType::TypeArray: - *(reinterpret_cast(ser_->Buf() + savePos_)) = carraytag(count_, itemType_); + *(reinterpret_cast(ser_->Buf() + savePos_)) = carraytag(count_, itemType_); break; case ObjType::TypeObjectArray: - *(reinterpret_cast(ser_->Buf() + savePos_)) = carraytag(count_, TAG_OBJECT); + *(reinterpret_cast(ser_->Buf() + savePos_)) = carraytag(count_, TAG_OBJECT); break; case ObjType::TypeObject: ser_->PutCTag(kCTagEnd); @@ -109,8 +121,8 @@ class CJsonBuilder { private: inline void putTag(int tagName, TagType tagType) { ser_->PutCTag(ctag{tagType, tagName}); } - const TagsMatcher *tm_; - WrSerializer *ser_; + const TagsMatcher* tm_; + WrSerializer* ser_; ObjType type_; int savePos_ = 0; int count_ = 0; diff --git a/cpp_src/core/cjson/cjsondecoder.cc b/cpp_src/core/cjson/cjsondecoder.cc index 10bd1a7f8..26c7d8549 100644 --- a/cpp_src/core/cjson/cjsondecoder.cc +++ b/cpp_src/core/cjson/cjsondecoder.cc @@ -7,7 +7,7 @@ namespace reindexer { template -bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrser, FilterT filter, RecoderT recoder, TagOptT) { +bool CJsonDecoder::decodeCJson(Payload& pl, Serializer& rdser, WrSerializer& wrser, FilterT filter, RecoderT recoder, TagOptT) { const ctag tag = rdser.GetCTag(); TagType tagType = tag.Type(); if (tagType == TAG_END) { @@ -38,7 +38,7 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs } else if (recoder.Recode(rdser, pl, tagName, wrser)) { // No more actions needed after recoding } else { - const auto &fieldRef{pl.Type().Field(field)}; + const auto& fieldRef{pl.Type().Field(field)}; const KeyValueType fieldType{fieldRef.Type()}; if (tagType == TAG_ARRAY) { if rx_unlikely (!fieldRef.IsArray()) { @@ -65,9 +65,7 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs objectScalarIndexes_.set(field); pl.Set(field, cjsonValueToVariant(tagType, rdser, fieldType), true); fieldType.EvaluateOneOf( - [&](OneOf) { - wrser.PutCTag(ctag{TAG_VARINT, tagName, field}); - }, + [&](OneOf) { wrser.PutCTag(ctag{TAG_VARINT, tagName, field}); }, [&](OneOf) { wrser.PutCTag(ctag{fieldType.ToTagType(), tagName, field}); }, @@ -84,8 +82,7 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs tagType = recoder.RegisterTagType(tagType, tagsPath_); wrser.PutCTag(ctag{tagType, tagName, field}); if (tagType == TAG_OBJECT) { - while (decodeCJson(pl, rdser, wrser, filter.MakeCleanCopy(), recoder.MakeCleanCopy(), NamedTagOpt{})) - ; + while (decodeCJson(pl, rdser, wrser, filter.MakeCleanCopy(), recoder.MakeCleanCopy(), NamedTagOpt{})); } else if (recoder.Recode(rdser, wrser)) { // No more actions needed after recoding } else if (tagType == TAG_ARRAY) { @@ -112,8 +109,7 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs } else { // !match wrser.PutCTag(ctag{tagType, tagName, field}); - while (decodeCJson(pl, rdser, wrser, filter.MakeSkipFilter(), recoder.MakeCleanCopy(), NamedTagOpt{})) - ; + while (decodeCJson(pl, rdser, wrser, filter.MakeSkipFilter(), recoder.MakeCleanCopy(), NamedTagOpt{})); } } @@ -124,7 +120,7 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs return true; } -[[nodiscard]] Variant CJsonDecoder::cjsonValueToVariant(TagType tagType, Serializer &rdser, KeyValueType fieldType) { +[[nodiscard]] Variant CJsonDecoder::cjsonValueToVariant(TagType tagType, Serializer& rdser, KeyValueType fieldType) { if (fieldType.Is() && tagType != TagType::TAG_STRING) { storage_.emplace_back(rdser.GetRawVariant(KeyValueType{tagType}).As()); return Variant(p_string(&storage_.back()), Variant::no_hold_t{}); @@ -133,22 +129,22 @@ bool CJsonDecoder::decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrs } } -RX_NO_INLINE void CJsonDecoder::throwTagReferenceError(ctag tag, const Payload &pl) { +RX_NO_INLINE void CJsonDecoder::throwTagReferenceError(ctag tag, const Payload& pl) { throw Error(errLogic, "Reference tag was found in transport CJSON for field %d[%s] in ns [%s]", tag.Field(), tagsMatcher_.tag2name(tag.Name()), pl.Type().Name()); } -RX_NO_INLINE void CJsonDecoder::throwUnexpectedArrayError(const PayloadFieldType &fieldRef) { +RX_NO_INLINE void CJsonDecoder::throwUnexpectedArrayError(const PayloadFieldType& fieldRef) { throw Error(errLogic, "Error parsing cjson field '%s' - got array, expected scalar %s", fieldRef.Name(), fieldRef.Type().Name()); } template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::DummyFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::DummyFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::DummyFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::DummyFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::RestrictingFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::RestrictingFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::RestrictingFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::RestrictingFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); } // namespace reindexer diff --git a/cpp_src/core/cjson/cjsondecoder.h b/cpp_src/core/cjson/cjsondecoder.h index 69221c7b6..443fea4c7 100644 --- a/cpp_src/core/cjson/cjsondecoder.h +++ b/cpp_src/core/cjson/cjsondecoder.h @@ -15,18 +15,18 @@ class WrSerializer; class Recoder { public: [[nodiscard]] virtual TagType Type(TagType oldTagType) = 0; - virtual void Recode(Serializer &, WrSerializer &) const = 0; - virtual void Recode(Serializer &, Payload &, int tagName, WrSerializer &) = 0; + virtual void Recode(Serializer&, WrSerializer&) const = 0; + virtual void Recode(Serializer&, Payload&, int tagName, WrSerializer&) = 0; [[nodiscard]] virtual bool Match(int field) noexcept = 0; - [[nodiscard]] virtual bool Match(TagType, const TagsPath &) = 0; - virtual void Serialize(WrSerializer &wrser) = 0; + [[nodiscard]] virtual bool Match(TagType, const TagsPath&) = 0; + virtual void Serialize(WrSerializer& wrser) = 0; virtual bool Reset() = 0; virtual ~Recoder() = default; }; class CJsonDecoder { public: - explicit CJsonDecoder(TagsMatcher &tagsMatcher, std::deque &storage) noexcept + explicit CJsonDecoder(TagsMatcher& tagsMatcher, std::deque& storage) noexcept : tagsMatcher_(tagsMatcher), storage_(storage) {} class SkipFilter { public: @@ -34,39 +34,39 @@ class CJsonDecoder { SkipFilter MakeSkipFilter() const noexcept { return SkipFilter(); } RX_ALWAYS_INLINE bool contains([[maybe_unused]] int field) const noexcept { return false; } - RX_ALWAYS_INLINE bool match(const TagsPath &) const noexcept { return false; } + RX_ALWAYS_INLINE bool match(const TagsPath&) const noexcept { return false; } }; class DummyFilter { public: DummyFilter MakeCleanCopy() const noexcept { return DummyFilter(); } SkipFilter MakeSkipFilter() const noexcept { return SkipFilter(); } - RX_ALWAYS_INLINE bool HasArraysFields(const PayloadTypeImpl &) const noexcept { return false; } + RX_ALWAYS_INLINE bool HasArraysFields(const PayloadTypeImpl&) const noexcept { return false; } RX_ALWAYS_INLINE bool contains([[maybe_unused]] int field) const noexcept { return true; } - RX_ALWAYS_INLINE bool match(const TagsPath &) const noexcept { return true; } + RX_ALWAYS_INLINE bool match(const TagsPath&) const noexcept { return true; } }; class IndexedSkipFilter { public: - IndexedSkipFilter(const FieldsSet &f) noexcept : f_(&f) {} + IndexedSkipFilter(const FieldsSet& f) noexcept : f_(&f) {} IndexedSkipFilter MakeCleanCopy() const noexcept { return IndexedSkipFilter(*f_); } IndexedSkipFilter MakeSkipFilter() const noexcept { return IndexedSkipFilter(*f_); } RX_ALWAYS_INLINE bool contains(int field) const noexcept { return f_->contains(field); } - RX_ALWAYS_INLINE bool match(const TagsPath &) const noexcept { return false; } + RX_ALWAYS_INLINE bool match(const TagsPath&) const noexcept { return false; } private: - const FieldsSet *f_; + const FieldsSet* f_; }; class RestrictingFilter { public: - RestrictingFilter(const FieldsSet &f) noexcept : f_(&f), match_(true) {} + RestrictingFilter(const FieldsSet& f) noexcept : f_(&f), match_(true) {} RestrictingFilter MakeCleanCopy() const noexcept { return RestrictingFilter(*f_); } IndexedSkipFilter MakeSkipFilter() const noexcept { return IndexedSkipFilter(*f_); } - RX_ALWAYS_INLINE bool HasArraysFields(const PayloadTypeImpl &pt) const noexcept { + RX_ALWAYS_INLINE bool HasArraysFields(const PayloadTypeImpl& pt) const noexcept { for (auto f : *f_) { if (f >= 0 && pt.Field(f).IsArray()) { return true; @@ -79,38 +79,38 @@ class CJsonDecoder { match_ = f_->contains(field); return match_; } - RX_ALWAYS_INLINE bool match(const TagsPath &tagsPath) noexcept { + RX_ALWAYS_INLINE bool match(const TagsPath& tagsPath) noexcept { match_ = match_ && f_->getTagsPathsLength() && f_->match(tagsPath); return match_; } private: - const FieldsSet *f_; + const FieldsSet* f_; bool match_; }; class DummyRecoder { public: RX_ALWAYS_INLINE DummyRecoder MakeCleanCopy() const noexcept { return DummyRecoder(); } - RX_ALWAYS_INLINE bool Recode(Serializer &, WrSerializer &) const noexcept { return false; } - RX_ALWAYS_INLINE bool Recode(Serializer &, Payload &, int, WrSerializer &) const noexcept { return false; } + RX_ALWAYS_INLINE bool Recode(Serializer&, WrSerializer&) const noexcept { return false; } + RX_ALWAYS_INLINE bool Recode(Serializer&, Payload&, int, WrSerializer&) const noexcept { return false; } RX_ALWAYS_INLINE TagType RegisterTagType(TagType tagType, int) const noexcept { return tagType; } - RX_ALWAYS_INLINE TagType RegisterTagType(TagType tagType, const TagsPath &) const noexcept { return tagType; } - RX_ALWAYS_INLINE void Serialize(WrSerializer &) const {} + RX_ALWAYS_INLINE TagType RegisterTagType(TagType tagType, const TagsPath&) const noexcept { return tagType; } + RX_ALWAYS_INLINE void Serialize(WrSerializer&) const {} }; class DefaultRecoder { public: - DefaultRecoder(Recoder &r) noexcept : r_(&r), needToRecode_(false) {} + DefaultRecoder(Recoder& r) noexcept : r_(&r), needToRecode_(false) {} RX_ALWAYS_INLINE DefaultRecoder MakeCleanCopy() const noexcept { return DefaultRecoder(*r_); } - RX_ALWAYS_INLINE bool Recode(Serializer &ser, WrSerializer &wser) const { + RX_ALWAYS_INLINE bool Recode(Serializer& ser, WrSerializer& wser) const { if (needToRecode_) { r_->Recode(ser, wser); } return needToRecode_; } - RX_ALWAYS_INLINE bool Recode(Serializer &ser, Payload &pl, int tagName, WrSerializer &wser) const { + RX_ALWAYS_INLINE bool Recode(Serializer& ser, Payload& pl, int tagName, WrSerializer& wser) const { if (needToRecode_) { r_->Recode(ser, pl, tagName, wser); } @@ -120,21 +120,21 @@ class CJsonDecoder { needToRecode_ = r_->Match(field); return needToRecode_ ? r_->Type(tagType) : tagType; } - RX_ALWAYS_INLINE TagType RegisterTagType(TagType tagType, const TagsPath &tagsPath) { + RX_ALWAYS_INLINE TagType RegisterTagType(TagType tagType, const TagsPath& tagsPath) { needToRecode_ = r_->Match(tagType, tagsPath); return needToRecode_ ? r_->Type(tagType) : tagType; } - RX_ALWAYS_INLINE void Serialize(WrSerializer &wser) const { r_->Serialize(wser); } + RX_ALWAYS_INLINE void Serialize(WrSerializer& wser) const { r_->Serialize(wser); } private: - Recoder *r_; + Recoder* r_; bool needToRecode_; }; struct NamedTagOpt {}; struct NamelessTagOpt {}; template - void Decode(Payload &pl, Serializer &rdSer, WrSerializer &wrSer, FilterT filter = FilterT(), RecoderT recoder = RecoderT()) { + void Decode(Payload& pl, Serializer& rdSer, WrSerializer& wrSer, FilterT filter = FilterT(), RecoderT recoder = RecoderT()) { static_assert(std::is_same_v || std::is_same_v, "Other filter types are not allowed for the public API"); static_assert(std::is_same_v || std::is_same_v, @@ -157,28 +157,28 @@ class CJsonDecoder { private: template - bool decodeCJson(Payload &pl, Serializer &rdser, WrSerializer &wrser, FilterT filter, RecoderT recoder, TagOptT); + bool decodeCJson(Payload& pl, Serializer& rdser, WrSerializer& wrser, FilterT filter, RecoderT recoder, TagOptT); bool isInArray() const noexcept { return arrayLevel_ > 0; } - [[noreturn]] void throwTagReferenceError(ctag, const Payload &); - [[noreturn]] void throwUnexpectedArrayError(const PayloadFieldType &); + [[noreturn]] void throwTagReferenceError(ctag, const Payload&); + [[noreturn]] void throwUnexpectedArrayError(const PayloadFieldType&); - [[nodiscard]] Variant cjsonValueToVariant(TagType tag, Serializer &rdser, KeyValueType dstType); + [[nodiscard]] Variant cjsonValueToVariant(TagType tag, Serializer& rdser, KeyValueType dstType); - TagsMatcher &tagsMatcher_; + TagsMatcher& tagsMatcher_; TagsPath tagsPath_; int32_t arrayLevel_ = 0; ScalarIndexesSetT objectScalarIndexes_; // storage for owning strings obtained from numbers - std::deque &storage_; + std::deque& storage_; }; extern template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::DummyFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::DummyFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); extern template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::DummyFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::DummyFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); extern template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::RestrictingFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::RestrictingFilter, CJsonDecoder::DummyRecoder, CJsonDecoder::NamelessTagOpt); extern template bool CJsonDecoder::decodeCJson( - Payload &, Serializer &, WrSerializer &, CJsonDecoder::RestrictingFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); + Payload&, Serializer&, WrSerializer&, CJsonDecoder::RestrictingFilter, CJsonDecoder::DefaultRecoder, CJsonDecoder::NamelessTagOpt); } // namespace reindexer diff --git a/cpp_src/core/cjson/cjsonmodifier.cc b/cpp_src/core/cjson/cjsonmodifier.cc index ab6506079..101cb4809 100644 --- a/cpp_src/core/cjson/cjsonmodifier.cc +++ b/cpp_src/core/cjson/cjsonmodifier.cc @@ -11,11 +11,11 @@ const std::string_view kWrongFieldsAmountMsg = "Number of fields for update shou class CJsonModifier::Context { public: - Context(const IndexedTagsPath &fieldPath, const VariantArray &v, WrSerializer &ser, std::string_view tuple, FieldModifyMode m, - const Payload *pl = nullptr) + Context(const IndexedTagsPath& fieldPath, const VariantArray& v, WrSerializer& ser, std::string_view tuple, FieldModifyMode m, + const Payload* pl = nullptr) : value(v), wrser(ser), rdser(tuple), mode(m), payload(pl) { jsonPath.reserve(fieldPath.size()); - for (const IndexedPathNode &node : fieldPath) { + for (const IndexedPathNode& node : fieldPath) { isForAllItems_ = isForAllItems_ || node.IsForAllItems(); jsonPath.emplace_back(node.NameTag()); } @@ -29,23 +29,23 @@ class CJsonModifier::Context { } [[nodiscard]] bool IsForAllItems() const noexcept { return isForAllItems_; } - const VariantArray &value; - WrSerializer &wrser; + const VariantArray& value; + WrSerializer& wrser; Serializer rdser; TagsPath jsonPath; IndexedTagsPath currObjPath; FieldModifyMode mode = FieldModeSet; bool fieldUpdated = false; bool updateArrayElements = false; - const Payload *payload = nullptr; + const Payload* payload = nullptr; std::array fieldsArrayOffsets; private: bool isForAllItems_ = false; }; -void CJsonModifier::SetFieldValue(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, WrSerializer &ser, - const Payload &pl) { +void CJsonModifier::SetFieldValue(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, WrSerializer& ser, + const Payload& pl) { auto ctx = initState(tuple, fieldPath, val, ser, &pl, FieldModifyMode::FieldModeSet); updateFieldInTuple(ctx); if (!ctx.fieldUpdated && !ctx.IsForAllItems()) { @@ -53,8 +53,8 @@ void CJsonModifier::SetFieldValue(std::string_view tuple, const IndexedTagsPath } } -void CJsonModifier::SetObject(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, WrSerializer &ser, - const Payload &pl) { +void CJsonModifier::SetObject(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, WrSerializer& ser, + const Payload& pl) { auto ctx = initState(tuple, fieldPath, val, ser, &pl, FieldModifyMode::FieldModeSetJson); buildCJSON(ctx); if (!ctx.fieldUpdated && !ctx.IsForAllItems()) { @@ -62,13 +62,13 @@ void CJsonModifier::SetObject(std::string_view tuple, const IndexedTagsPath &fie } } -void CJsonModifier::RemoveField(std::string_view tuple, const IndexedTagsPath &fieldPath, WrSerializer &wrser) { +void CJsonModifier::RemoveField(std::string_view tuple, const IndexedTagsPath& fieldPath, WrSerializer& wrser) { auto ctx = initState(tuple, fieldPath, {}, wrser, nullptr, FieldModeDrop); dropFieldInTuple(ctx); } -CJsonModifier::Context CJsonModifier::initState(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, - WrSerializer &ser, const Payload *pl, FieldModifyMode mode) { +CJsonModifier::Context CJsonModifier::initState(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, + WrSerializer& ser, const Payload* pl, FieldModifyMode mode) { if (fieldPath.empty()) { throw Error(errLogic, kWrongFieldsAmountMsg); } @@ -79,12 +79,12 @@ CJsonModifier::Context CJsonModifier::initState(std::string_view tuple, const In return ctx; } -void CJsonModifier::updateObject(Context &ctx, int tagName) const { +void CJsonModifier::updateObject(Context& ctx, int tagName) const { ctx.fieldUpdated = true; JsonDecoder jsonDecoder(tagsMatcher_); if (ctx.value.IsArrayValue()) { CJsonBuilder cjsonBuilder(ctx.wrser, ObjType::TypeArray, &tagsMatcher_, tagName); - for (const auto &item : ctx.value) { + for (const auto& item : ctx.value) { auto objBuilder = cjsonBuilder.Object(nullptr); jsonDecoder.Decode(std::string_view(item), objBuilder, ctx.jsonPath); } @@ -96,7 +96,7 @@ void CJsonModifier::updateObject(Context &ctx, int tagName) const { jsonDecoder.Decode(std::string_view(ctx.value.front()), cjsonBuilder, ctx.jsonPath); } -void CJsonModifier::insertField(Context &ctx) const { +void CJsonModifier::insertField(Context& ctx) const { ctx.fieldUpdated = true; assertrx(ctx.currObjPath.size() < fieldPath_.size()); @@ -127,10 +127,14 @@ void CJsonModifier::insertField(Context &ctx) const { ctx.currObjPath.clear(); } -bool CJsonModifier::needToInsertField(const Context &ctx) const { +bool CJsonModifier::needToInsertField(const Context& ctx) const { assertrx_throw(!fieldPath_.empty()); - if (ctx.fieldUpdated || fieldPath_.back().IsArrayNode()) return false; - if (ctx.currObjPath.size() >= fieldPath_.size()) return false; + if (ctx.fieldUpdated || fieldPath_.back().IsArrayNode()) { + return false; + } + if (ctx.currObjPath.size() >= fieldPath_.size()) { + return false; + } assertrx_throw(ctx.currObjPath.size() <= fieldPath_.size()); for (unsigned i = 0; i < ctx.currObjPath.size(); ++i) { if (fieldPath_[i] != ctx.currObjPath[i]) { @@ -148,11 +152,11 @@ bool CJsonModifier::needToInsertField(const Context &ctx) const { return true; } -TagType CJsonModifier::determineUpdateTagType(const Context &ctx, int field) const { +TagType CJsonModifier::determineUpdateTagType(const Context& ctx, int field) const { if (isIndexed(field)) { - const PayloadFieldType &fieldType = pt_.Field(field); + const PayloadFieldType& fieldType = pt_.Field(field); if (!fieldType.IsArray() || ctx.updateArrayElements || !ctx.value.IsNullValue()) { - for (auto &v : ctx.value) { + for (auto& v : ctx.value) { if (!fieldType.Type().IsSame(v.Type())) { throw Error(errParams, "Inserted field %s type [%s] doesn't match it's index type [%s]", fieldType.Name(), v.Type().Name(), fieldType.Type().Name()); @@ -169,10 +173,12 @@ TagType CJsonModifier::determineUpdateTagType(const Context &ctx, int field) con return arrayKvType2Tag(ctx.value); } -bool CJsonModifier::checkIfFoundTag(Context &ctx, bool isLastItem) const { - if (tagsPath_.empty() || !fieldPath_.Compare(tagsPath_)) return false; +bool CJsonModifier::checkIfFoundTag(Context& ctx, bool isLastItem) const { + if (tagsPath_.empty() || !fieldPath_.Compare(tagsPath_)) { + return false; + } - const auto &backFieldPath = fieldPath_.back(); + const auto& backFieldPath = fieldPath_.back(); if (!backFieldPath.IsArrayNode() || ((!backFieldPath.IsForAllItems() || isLastItem))) { ctx.fieldUpdated = true; } @@ -180,11 +186,11 @@ bool CJsonModifier::checkIfFoundTag(Context &ctx, bool isLastItem) const { return true; } -void CJsonModifier::setArray(Context &ctx) const { +void CJsonModifier::setArray(Context& ctx) const { auto type = arrayKvType2Tag(ctx.value); ctx.wrser.PutCArrayTag(carraytag{ctx.value.size(), type}); const bool isObjsArr = (type == TAG_OBJECT); - for (const auto &item : ctx.value) { + for (const auto& item : ctx.value) { if (isObjsArr) { type = item.Type().ToTagType(); ctx.wrser.PutCTag(ctag{type}); @@ -193,7 +199,7 @@ void CJsonModifier::setArray(Context &ctx) const { } } -void CJsonModifier::writeCTag(const ctag &tag, Context &ctx) { +void CJsonModifier::writeCTag(const ctag& tag, Context& ctx) { bool tagMatched = checkIfFoundTag(ctx); const TagType tagType = tag.Type(); const int field = tag.Field(); @@ -201,7 +207,7 @@ void CJsonModifier::writeCTag(const ctag &tag, Context &ctx) { if (tagType == TAG_ARRAY) { const auto count = ctx.rdser.GetVarUint(); if (!tagMatched || !ctx.fieldUpdated) { - auto &lastTag = tagsPath_.back(); + auto& lastTag = tagsPath_.back(); for (uint64_t i = 0; i < count; ++i) { lastTag.SetIndex(i); const bool isLastItem = (i + 1 == count); @@ -241,7 +247,7 @@ void CJsonModifier::writeCTag(const ctag &tag, Context &ctx) { } } -void CJsonModifier::updateArray(TagType atagType, uint32_t count, int tagName, Context &ctx) { +void CJsonModifier::updateArray(TagType atagType, uint32_t count, int tagName, Context& ctx) { assertrx_throw(!ctx.value.IsArrayValue()); // Unable to update array's element with array-value Variant value; @@ -293,7 +299,7 @@ void CJsonModifier::updateArray(TagType atagType, uint32_t count, int tagName, C assertrx_throw(ctx.fieldUpdated); } -void CJsonModifier::copyArray(int tagName, Context &ctx) { +void CJsonModifier::copyArray(int tagName, Context& ctx) { const carraytag atag = ctx.rdser.GetCArrayTag(); const TagType atagType = atag.Type(); const auto count = atag.Count(); @@ -360,7 +366,7 @@ void CJsonModifier::copyArray(int tagName, Context &ctx) { } } -bool CJsonModifier::updateFieldInTuple(Context &ctx) { +bool CJsonModifier::updateFieldInTuple(Context& ctx) { const ctag tag = ctx.rdser.GetCTag(); const TagType tagType = tag.Type(); if (tagType == TAG_END) { @@ -415,7 +421,7 @@ bool CJsonModifier::updateFieldInTuple(Context &ctx) { return true; } -bool CJsonModifier::dropFieldInTuple(Context &ctx) { +bool CJsonModifier::dropFieldInTuple(Context& ctx) { const ctag tag = ctx.rdser.GetCTag(); const TagType tagType = tag.Type(); if (tagType == TAG_END) { @@ -494,7 +500,7 @@ bool CJsonModifier::dropFieldInTuple(Context &ctx) { return true; } -void CJsonModifier::embedFieldValue(TagType type, int field, Context &ctx, size_t idx) const { +void CJsonModifier::embedFieldValue(TagType type, int field, Context& ctx, size_t idx) const { if (isIndexed(field)) { assertrx(ctx.payload); const Variant v = ctx.payload->Get(field, ctx.fieldsArrayOffsets[field] + idx); @@ -505,11 +511,13 @@ void CJsonModifier::embedFieldValue(TagType type, int field, Context &ctx, size_ copyCJsonValue(type, ctx.rdser, ctx.wrser); } -bool CJsonModifier::buildCJSON(Context &ctx) { +bool CJsonModifier::buildCJSON(Context& ctx) { const auto tag = ctx.rdser.GetCTag(); TagType tagType = tag.Type(); if (tagType == TAG_END) { - if (needToInsertField(ctx)) insertField(ctx); + if (needToInsertField(ctx)) { + insertField(ctx); + } ctx.wrser.PutCTag(kCTagEnd); return false; } diff --git a/cpp_src/core/cjson/cjsonmodifier.h b/cpp_src/core/cjson/cjsonmodifier.h index baa804d3e..c907b437c 100644 --- a/cpp_src/core/cjson/cjsonmodifier.h +++ b/cpp_src/core/cjson/cjsonmodifier.h @@ -10,34 +10,34 @@ class TagsMatcher; class CJsonModifier { public: - CJsonModifier(TagsMatcher &tagsMatcher, PayloadType pt) noexcept : pt_(std::move(pt)), tagsMatcher_(tagsMatcher) {} - void SetFieldValue(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, WrSerializer &ser, - const Payload &pl); - void SetObject(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, WrSerializer &ser, const Payload &pl); - void RemoveField(std::string_view tuple, const IndexedTagsPath &fieldPath, WrSerializer &wrser); + CJsonModifier(TagsMatcher& tagsMatcher, PayloadType pt) noexcept : pt_(std::move(pt)), tagsMatcher_(tagsMatcher) {} + void SetFieldValue(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, WrSerializer& ser, + const Payload& pl); + void SetObject(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, WrSerializer& ser, const Payload& pl); + void RemoveField(std::string_view tuple, const IndexedTagsPath& fieldPath, WrSerializer& wrser); private: class Context; - Context initState(std::string_view tuple, const IndexedTagsPath &fieldPath, const VariantArray &val, WrSerializer &ser, - const Payload *pl, FieldModifyMode mode); - bool updateFieldInTuple(Context &ctx); - bool dropFieldInTuple(Context &ctx); - bool buildCJSON(Context &ctx); - [[nodiscard]] bool needToInsertField(const Context &ctx) const; - void insertField(Context &ctx) const; - void embedFieldValue(TagType, int field, Context &ctx, size_t idx) const; - void updateObject(Context &ctx, int tagName) const; - void setArray(Context &ctx) const; - void writeCTag(const ctag &tag, Context &ctx); - void updateArray(TagType atagType, uint32_t count, int tagName, Context &ctx); - void copyArray(int TagName, Context &ctx); - [[nodiscard]] TagType determineUpdateTagType(const Context &ctx, int field) const; - [[nodiscard]] bool checkIfFoundTag(Context &ctx, bool isLastItem = false) const; + Context initState(std::string_view tuple, const IndexedTagsPath& fieldPath, const VariantArray& val, WrSerializer& ser, + const Payload* pl, FieldModifyMode mode); + bool updateFieldInTuple(Context& ctx); + bool dropFieldInTuple(Context& ctx); + bool buildCJSON(Context& ctx); + [[nodiscard]] bool needToInsertField(const Context& ctx) const; + void insertField(Context& ctx) const; + void embedFieldValue(TagType, int field, Context& ctx, size_t idx) const; + void updateObject(Context& ctx, int tagName) const; + void setArray(Context& ctx) const; + void writeCTag(const ctag& tag, Context& ctx); + void updateArray(TagType atagType, uint32_t count, int tagName, Context& ctx); + void copyArray(int TagName, Context& ctx); + [[nodiscard]] TagType determineUpdateTagType(const Context& ctx, int field) const; + [[nodiscard]] bool checkIfFoundTag(Context& ctx, bool isLastItem = false) const; [[nodiscard]] bool isIndexed(int field) const noexcept { return (field >= 0); } PayloadType pt_; IndexedTagsPath fieldPath_, tagsPath_; - TagsMatcher &tagsMatcher_; + TagsMatcher& tagsMatcher_; }; } // namespace reindexer diff --git a/cpp_src/core/cjson/cjsontools.cc b/cpp_src/core/cjson/cjsontools.cc index 4b95f3761..ecce2bdc4 100644 --- a/cpp_src/core/cjson/cjsontools.cc +++ b/cpp_src/core/cjson/cjsontools.cc @@ -1,10 +1,11 @@ #include "cjsontools.h" +#include #include "cjsonbuilder.h" #include "core/type_consts_helpers.h" namespace reindexer { -TagType arrayKvType2Tag(const VariantArray &values) { +TagType arrayKvType2Tag(const VariantArray& values) { if (values.empty()) { return TAG_NULL; } @@ -21,8 +22,10 @@ TagType arrayKvType2Tag(const VariantArray &values) { return type; } -void copyCJsonValue(TagType tagType, const Variant &value, WrSerializer &wrser) { - if (value.Type().Is()) return; +void copyCJsonValue(TagType tagType, const Variant& value, WrSerializer& wrser) { + if (value.Type().Is()) { + return; + } switch (tagType) { case TAG_DOUBLE: wrser.PutDouble(static_cast(value.convert(KeyValueType::Double{}))); @@ -55,7 +58,7 @@ void copyCJsonValue(TagType tagType, const Variant &value, WrSerializer &wrser) } } -void putCJsonRef(TagType tagType, int tagName, int tagField, const VariantArray &values, WrSerializer &wrser) { +void putCJsonRef(TagType tagType, int tagName, int tagField, const VariantArray& values, WrSerializer& wrser) { if (values.IsArrayValue()) { wrser.PutCTag(ctag{TAG_ARRAY, tagName, tagField}); wrser.PutVarUint(values.size()); @@ -64,19 +67,21 @@ void putCJsonRef(TagType tagType, int tagName, int tagField, const VariantArray } } -void putCJsonValue(TagType tagType, int tagName, const VariantArray &values, WrSerializer &wrser) { +void putCJsonValue(TagType tagType, int tagName, const VariantArray& values, WrSerializer& wrser) { if (values.IsArrayValue()) { const TagType elemType = arrayKvType2Tag(values); wrser.PutCTag(ctag{TAG_ARRAY, tagName}); wrser.PutCArrayTag(carraytag{values.size(), elemType}); if (elemType == TAG_OBJECT) { - for (const Variant &value : values) { + for (const Variant& value : values) { auto itemType = value.Type().ToTagType(); wrser.PutCTag(ctag{itemType}); copyCJsonValue(itemType, value, wrser); } } else { - for (const Variant &value : values) copyCJsonValue(elemType, value, wrser); + for (const Variant& value : values) { + copyCJsonValue(elemType, value, wrser); + } } } else if (values.size() == 1) { wrser.PutCTag(ctag{tagType, tagName}); @@ -86,7 +91,7 @@ void putCJsonValue(TagType tagType, int tagName, const VariantArray &values, WrS } } -void copyCJsonValue(TagType tagType, Serializer &rdser, WrSerializer &wrser) { +void copyCJsonValue(TagType tagType, Serializer& rdser, WrSerializer& wrser) { switch (tagType) { case TAG_DOUBLE: wrser.PutDouble(rdser.GetDouble()); @@ -115,7 +120,7 @@ void copyCJsonValue(TagType tagType, Serializer &rdser, WrSerializer &wrser) { } } -void skipCjsonTag(ctag tag, Serializer &rdser, std::array *fieldsArrayOffsets) { +void skipCjsonTag(ctag tag, Serializer& rdser, std::array* fieldsArrayOffsets) { switch (tag.Type()) { case TAG_ARRAY: { const auto field = tag.Field(); @@ -164,17 +169,17 @@ void skipCjsonTag(ctag tag, Serializer &rdser, std::array } } -Variant cjsonValueToVariant(TagType tagType, Serializer &rdser, KeyValueType dstType) { +Variant cjsonValueToVariant(TagType tagType, Serializer& rdser, KeyValueType dstType) { return rdser .GetRawVariant(dstType.Is() && tagType == TAG_VARINT ? KeyValueType{KeyValueType::Int{}} : KeyValueType{tagType}) .convert(dstType); } template -void buildPayloadTuple(const PayloadIface &pl, const TagsMatcher *tagsMatcher, WrSerializer &wrser) { +void buildPayloadTuple(const PayloadIface& pl, const TagsMatcher* tagsMatcher, WrSerializer& wrser) { CJsonBuilder builder(wrser, ObjType::TypeObject); for (int field = 1, numFields = pl.NumFields(); field < numFields; ++field) { - const PayloadFieldType &fieldType = pl.Type().Field(field); + const PayloadFieldType& fieldType = pl.Type().Field(field); if (fieldType.JsonPaths().size() < 1 || fieldType.JsonPaths()[0].empty()) { continue; } @@ -190,16 +195,192 @@ void buildPayloadTuple(const PayloadIface &pl, const TagsMatcher *tagsMatcher } } -template void buildPayloadTuple(const PayloadIface &, const TagsMatcher *, WrSerializer &); -template void buildPayloadTuple(const PayloadIface &, const TagsMatcher *, WrSerializer &); +template void buildPayloadTuple(const PayloadIface&, const TagsMatcher*, WrSerializer&); +template void buildPayloadTuple(const PayloadIface&, const TagsMatcher*, WrSerializer&); -void throwUnexpectedNestedArrayError(std::string_view parserName, const PayloadFieldType &f) { +void throwUnexpectedNestedArrayError(std::string_view parserName, const PayloadFieldType& f) { throw Error(errLogic, "Error parsing %s field '%s' - got value nested into the array, but expected scalar %s", parserName, f.Name(), f.Type().Name()); } -void throwScalarMultipleEncodesError(const Payload &pl, const PayloadFieldType &f, int field) { +void throwScalarMultipleEncodesError(const Payload& pl, const PayloadFieldType& f, int field) { throw Error(errLogic, "Non-array field '%s' [%d] from '%s' can only be encoded once.", f.Name(), field, pl.Type().Name()); } +static void dumpCjsonValue(TagType type, Serializer& cjson, std::ostream& dump) { + switch (type) { + case TAG_VARINT: + dump << cjson.GetVarint(); + break; + case TAG_DOUBLE: + dump << cjson.GetDouble(); + break; + case TAG_STRING: + dump << '"' << std::string_view{cjson.GetPVString()} << '"'; + break; + case TAG_BOOL: + dump << std::boolalpha << bool(cjson.GetVarUint()); + break; + case TAG_UUID: + dump << std::string{cjson.GetUuid()}; + break; + case TAG_NULL: + case TAG_OBJECT: + case TAG_ARRAY: + case TAG_END: + assertrx(0); + } +} + +template +static void dumpCjsonObject(Serializer& cjson, std::ostream& dump, const TagsMatcher* tm, const PL* pl, std::string_view tab, + unsigned indentLevel) { + const auto indent = [&dump, tab](unsigned indLvl) { + for (unsigned i = 0; i < indLvl; ++i) { + dump << tab; + } + }; + VariantArray buf; + while (!cjson.Eof()) { + const ctag tag = cjson.GetCTag(); + const TagType type = tag.Type(); + const auto name = tag.Name(); + const auto field = tag.Field(); + if (type == TAG_END) { + assertrx(indentLevel > 0); + --indentLevel; + } + indent(indentLevel); + dump << std::left << std::setw(10) << TagTypeToStr(type); + dump << std::right << std::setw(4) << name; + dump << std::right << std::setw(4) << field; + if (tm && name > 0) { + dump << " \"" << tm->tag2name(name) << '"'; + } + if (field >= 0) { + switch (type) { + case TAG_VARINT: + case TAG_DOUBLE: + case TAG_STRING: + case TAG_BOOL: + case TAG_UUID: + if (pl) { + buf.clear(); + pl->Get(field, buf); + assertrx(buf.size() == 1); + dump << " -> " << buf[0].As(); + } + break; + case TAG_ARRAY: { + dump << '\n'; + indent(indentLevel + 1); + const size_t count = cjson.GetVarUint(); + dump << "Count: " << count; + if (pl) { + dump << " -> ["; + buf.clear(); + pl->Get(field, buf); + assertrx(buf.size() == count); + for (size_t i = 0; i < count; ++i) { + if (i != 0) { + dump << ", "; + } + dump << buf[i].As(); + } + dump << ']'; + } + } break; + case TAG_NULL: + case TAG_OBJECT: + case TAG_END: + assertrx(0); + } + dump << '\n'; + } else { + dump << '\n'; + switch (type) { + case TAG_VARINT: + case TAG_DOUBLE: + case TAG_STRING: + case TAG_BOOL: + case TAG_UUID: + indent(indentLevel + 1); + dumpCjsonValue(type, cjson, dump); + dump << '\n'; + break; + case TAG_NULL: + break; + case TAG_ARRAY: { + const carraytag arr = cjson.GetCArrayTag(); + const size_t count = arr.Count(); + if (arr.Type() == TAG_OBJECT) { + indent(indentLevel + 1); + dump << " count: " << count << '\n'; + for (size_t i = 0; i < count; ++i) { + const ctag t = cjson.GetCTag(); + assertrx(t.Name() == 0); + assertrx(t.Field() < 0); + indent(indentLevel + 2); + dump << TagTypeToStr(t.Type()); + dump << ": "; + if (t.Type() == TAG_OBJECT) { + dump << "{\n"; + dumpCjsonObject(cjson, dump, tm, pl, tab, indentLevel + 3); + indent(indentLevel + 2); + dump << "}\n"; + } else { + dumpCjsonValue(t.Type(), cjson, dump); + dump << '\n'; + } + } + } else { + indent(indentLevel + 1); + dump << TagTypeToStr(arr.Type()) << " count: " << count << '\n'; + indent(indentLevel + 2); + dump << '['; + if (arr.Type() == TAG_OBJECT && count > 0) { + dump << '\n'; + for (size_t i = 0; i < count; ++i) { + indent(indentLevel + 3); + dump << TagTypeToStr(arr.Type()) << '\n'; + dumpCjsonObject(cjson, dump, tm, pl, tab, indentLevel + 4); + } + indent(indentLevel + 2); + } else { + for (size_t i = 0; i < count; ++i) { + if (i != 0) { + dump << ", "; + } + dumpCjsonValue(arr.Type(), cjson, dump); + } + } + dump << "]\n"; + } + } break; + case TAG_OBJECT: + dumpCjsonObject(cjson, dump, tm, pl, tab, indentLevel + 1); + break; + case TAG_END: + return; + } + } + } +} + +void DumpCjson(Serializer& cjson, std::ostream& dump, const Payload* pl, const TagsMatcher* tm, std::string_view tab) { + const auto osFlags = dump.flags(); + dump.exceptions(std::ostream::failbit | std::ostream::badbit); + dump << "TAG_TYPE NAME FIELD\n"; + dumpCjsonObject(cjson, dump, tm, pl, tab, 0); + dump.flags(osFlags); +} + +void DumpCjson(Serializer& cjson, std::ostream& dump, const ConstPayload* pl, const TagsMatcher* tm, std::string_view tab) { + const auto osFlags = dump.flags(); + dump.exceptions(std::ostream::failbit | std::ostream::badbit); + dump << "TAG_TYPE NAME FIELD\n"; + dumpCjsonObject(cjson, dump, tm, pl, tab, 0); + dump.flags(osFlags); +} + } // namespace reindexer diff --git a/cpp_src/core/cjson/cjsontools.h b/cpp_src/core/cjson/cjsontools.h index dddfbf2a5..93c618524 100644 --- a/cpp_src/core/cjson/cjsontools.h +++ b/cpp_src/core/cjson/cjsontools.h @@ -5,21 +5,21 @@ namespace reindexer { template -void buildPayloadTuple(const PayloadIface &pl, const TagsMatcher *tagsMatcher, WrSerializer &wrser); +void buildPayloadTuple(const PayloadIface& pl, const TagsMatcher* tagsMatcher, WrSerializer& wrser); -void copyCJsonValue(TagType tagType, Serializer &rdser, WrSerializer &wrser); -void copyCJsonValue(TagType tagType, const Variant &value, WrSerializer &wrser); -void putCJsonRef(TagType tagType, int tagName, int tagField, const VariantArray &values, WrSerializer &wrser); -void putCJsonValue(TagType tagType, int tagName, const VariantArray &values, WrSerializer &wrser); +void copyCJsonValue(TagType tagType, Serializer& rdser, WrSerializer& wrser); +void copyCJsonValue(TagType tagType, const Variant& value, WrSerializer& wrser); +void putCJsonRef(TagType tagType, int tagName, int tagField, const VariantArray& values, WrSerializer& wrser); +void putCJsonValue(TagType tagType, int tagName, const VariantArray& values, WrSerializer& wrser); -[[nodiscard]] TagType arrayKvType2Tag(const VariantArray &values); -void skipCjsonTag(ctag tag, Serializer &rdser, std::array *fieldsArrayOffsets = nullptr); -[[nodiscard]] Variant cjsonValueToVariant(TagType tag, Serializer &rdser, KeyValueType dstType); +[[nodiscard]] TagType arrayKvType2Tag(const VariantArray& values); +void skipCjsonTag(ctag tag, Serializer& rdser, std::array* fieldsArrayOffsets = nullptr); +[[nodiscard]] Variant cjsonValueToVariant(TagType tag, Serializer& rdser, KeyValueType dstType); -[[noreturn]] void throwUnexpectedNestedArrayError(std::string_view parserName, const PayloadFieldType &f); -[[noreturn]] void throwScalarMultipleEncodesError(const Payload &pl, const PayloadFieldType &f, int field); -RX_ALWAYS_INLINE void validateNonArrayFieldRestrictions(const ScalarIndexesSetT &scalarIndexes, const Payload &pl, - const PayloadFieldType &f, int field, bool isInArray, std::string_view parserName) { +[[noreturn]] void throwUnexpectedNestedArrayError(std::string_view parserName, const PayloadFieldType& f); +[[noreturn]] void throwScalarMultipleEncodesError(const Payload& pl, const PayloadFieldType& f, int field); +RX_ALWAYS_INLINE void validateNonArrayFieldRestrictions(const ScalarIndexesSetT& scalarIndexes, const Payload& pl, + const PayloadFieldType& f, int field, bool isInArray, std::string_view parserName) { if (!f.IsArray()) { if rx_unlikely (isInArray) { throwUnexpectedNestedArrayError(parserName, f); @@ -30,4 +30,23 @@ RX_ALWAYS_INLINE void validateNonArrayFieldRestrictions(const ScalarIndexesSetT } } +void DumpCjson(Serializer& cjson, std::ostream& dump, const ConstPayload*, const TagsMatcher* = nullptr, std::string_view tab = " "); +inline void DumpCjson(Serializer&& cjson, std::ostream& dump, const ConstPayload* pl, const TagsMatcher* tm = nullptr, + std::string_view tab = " ") { + DumpCjson(cjson, dump, pl, tm, tab); +} + +void DumpCjson(Serializer& cjson, std::ostream& dump, const Payload*, const TagsMatcher* = nullptr, std::string_view tab = " "); +inline void DumpCjson(Serializer&& cjson, std::ostream& dump, const Payload* pl, const TagsMatcher* tm = nullptr, + std::string_view tab = " ") { + DumpCjson(cjson, dump, pl, tm, tab); +} + +inline void DumpCjson(Serializer& cjson, std::ostream& dump, const TagsMatcher* tm = nullptr, std::string_view tab = " ") { + DumpCjson(cjson, dump, static_cast(nullptr), tm, tab); +} +inline void DumpCjson(Serializer&& cjson, std::ostream& dump, const TagsMatcher* tm = nullptr, std::string_view tab = " ") { + DumpCjson(cjson, dump, tm, tab); +} + } // namespace reindexer diff --git a/cpp_src/core/cjson/csvbuilder.cc b/cpp_src/core/cjson/csvbuilder.cc index 25b2eca49..a00a583c3 100644 --- a/cpp_src/core/cjson/csvbuilder.cc +++ b/cpp_src/core/cjson/csvbuilder.cc @@ -2,7 +2,7 @@ namespace reindexer { -CsvBuilder::CsvBuilder(ObjType type, const CsvBuilder &parent) +CsvBuilder::CsvBuilder(ObjType type, const CsvBuilder& parent) : ser_(parent.ser_), tm_(parent.tm_), type_(type), @@ -36,7 +36,7 @@ CsvBuilder::CsvBuilder(ObjType type, const CsvBuilder &parent) } } -CsvBuilder::CsvBuilder(WrSerializer &ser, CsvOrdering &ordering) +CsvBuilder::CsvBuilder(WrSerializer& ser, CsvOrdering& ordering) : ser_(&ser), level_(-1), ordering_(!ordering.ordering_.empty() ? &ordering.ordering_ : nullptr), @@ -46,7 +46,7 @@ CsvBuilder::~CsvBuilder() { End(); } std::string_view CsvBuilder::getNameByTag(int tagName) { return tagName ? tm_->tag2name(tagName) : std::string_view(); } -CsvBuilder &CsvBuilder::End() { +CsvBuilder& CsvBuilder::End() { if (!positions_.empty()) { postProcessing(); } @@ -89,9 +89,13 @@ void CsvBuilder::putName(std::string_view name) { tmProcessing(name); } - if (count_++) (*ser_) << ','; + if (count_++) { + (*ser_) << ','; + } - if (level_ < 1) return; + if (level_ < 1) { + return; + } if (name.data()) { (*ser_) << '"'; @@ -106,7 +110,7 @@ void CsvBuilder::tmProcessing(std::string_view name) { auto prevFinishPos = ser_->Len(); if (tag > 0) { - auto it = std::find_if(ordering_->begin(), ordering_->end(), [&tag](const auto &t) { return t == tag; }); + auto it = std::find_if(ordering_->begin(), ordering_->end(), [&tag](const auto& t) { return t == tag; }); if (it != ordering_->end()) { if (curTagPos_ > -1) { @@ -125,7 +129,9 @@ void CsvBuilder::tmProcessing(std::string_view name) { if (curTagPos_ > -1) { positions_[curTagPos_].second = prevFinishPos; } - if (count_) (*ser_) << ','; + if (count_) { + (*ser_) << ','; + } (*ser_) << "\"{"; type_ = ObjType::TypeObject; @@ -148,7 +154,7 @@ void CsvBuilder::postProcessing() { auto joinedData = std::string_view(ser_->Slice().data() + positions_[curTagPos_].second, ser_->Len() - positions_[curTagPos_].second); bool needDelim = false; - for (auto &[begin, end] : positions_) { + for (auto& [begin, end] : positions_) { if (needDelim) { *buf_ << ','; } else { @@ -162,7 +168,7 @@ void CsvBuilder::postProcessing() { *ser_ << buf_->Slice(); } -CsvBuilder &CsvBuilder::Put(std::string_view name, std::string_view arg, [[maybe_unused]] int offset) { +CsvBuilder& CsvBuilder::Put(std::string_view name, std::string_view arg, [[maybe_unused]] int offset) { putName(name); std::string_view optQuote = level_ > 0 ? "\"" : ""; @@ -173,32 +179,32 @@ CsvBuilder &CsvBuilder::Put(std::string_view name, std::string_view arg, [[maybe return *this; } -CsvBuilder &CsvBuilder::Put(std::string_view name, Uuid arg, [[maybe_unused]] int offset) { +CsvBuilder& CsvBuilder::Put(std::string_view name, Uuid arg, [[maybe_unused]] int offset) { putName(name); ser_->PrintJsonUuid(arg); return *this; } -CsvBuilder &CsvBuilder::Raw(std::string_view name, std::string_view arg) { +CsvBuilder& CsvBuilder::Raw(std::string_view name, std::string_view arg) { putName(name); (*ser_) << arg; return *this; } -CsvBuilder &CsvBuilder::Null(std::string_view name) { +CsvBuilder& CsvBuilder::Null(std::string_view name) { putName(name); (*ser_) << "null"; return *this; } -CsvBuilder &CsvBuilder::Put(std::string_view name, const Variant &kv, int offset) { +CsvBuilder& CsvBuilder::Put(std::string_view name, const Variant& kv, int offset) { kv.Type().EvaluateOneOf( [&](KeyValueType::Int) { Put(name, int(kv)); }, [&](KeyValueType::Int64) { Put(name, int64_t(kv), offset); }, [&](KeyValueType::Double) { Put(name, double(kv)); }, [&](KeyValueType::String) { Put(name, std::string_view(kv), offset); }, [&](KeyValueType::Null) { Null(name); }, [&](KeyValueType::Bool) { Put(name, bool(kv), offset); }, [&](KeyValueType::Tuple) { auto arrNode = Array(name); - for (auto &val : kv.getCompositeValues()) { + for (auto& val : kv.getCompositeValues()) { arrNode.Put({nullptr, 0}, val, offset); } }, diff --git a/cpp_src/core/cjson/csvbuilder.h b/cpp_src/core/cjson/csvbuilder.h index 7ab394f2b..b51bab67d 100644 --- a/cpp_src/core/cjson/csvbuilder.h +++ b/cpp_src/core/cjson/csvbuilder.h @@ -33,13 +33,13 @@ struct CsvOrdering { class CsvBuilder { public: CsvBuilder() = default; - CsvBuilder(WrSerializer &ser, CsvOrdering &ordering); + CsvBuilder(WrSerializer& ser, CsvOrdering& ordering); ~CsvBuilder(); - CsvBuilder &operator=(const CsvBuilder &) = delete; - CsvBuilder &operator=(CsvBuilder &&) = delete; + CsvBuilder& operator=(const CsvBuilder&) = delete; + CsvBuilder& operator=(CsvBuilder&&) = delete; - void SetTagsMatcher(const TagsMatcher *tm) { tm_ = tm; } + void SetTagsMatcher(const TagsMatcher* tm) { tm_ = tm; } /// Start new object CsvBuilder Object(std::string_view name = {}, int size = KUnknownFieldSize); @@ -52,70 +52,78 @@ class CsvBuilder { template void Array(int tagName, span data, int /*offset*/ = 0) { CsvBuilder node = Array(tagName); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } template void Array(std::string_view n, span data, int /*offset*/ = 0) { CsvBuilder node = Array(n); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } template void Array(std::string_view n, std::initializer_list data, int /*offset*/ = 0) { CsvBuilder node = Array(n); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } - void Array(int tagName, Serializer &ser, TagType tagType, int count) { + void Array(int tagName, Serializer& ser, TagType tagType, int count) { CsvBuilder node = Array(tagName); - while (count--) node.Put({}, ser.GetRawVariant(KeyValueType{tagType})); + while (count--) { + node.Put({}, ser.GetRawVariant(KeyValueType{tagType})); + } } - CsvBuilder &Put(std::string_view name, const Variant &arg, int offset = 0); - CsvBuilder &Put(std::nullptr_t, const Variant &arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } - CsvBuilder &Put(std::string_view name, std::string_view arg, int offset = 0); - CsvBuilder &Put(std::string_view name, Uuid arg, int offset = 0); - CsvBuilder &Put(std::nullptr_t, std::string_view arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } - CsvBuilder &Put(std::string_view name, const char *arg, int offset = 0) { return Put(name, std::string_view(arg), offset); } - template ::value || std::is_floating_point::value>::type * = nullptr> - CsvBuilder &Put(std::string_view name, const T &arg, [[maybe_unused]] int offset = 0) { + CsvBuilder& Put(std::string_view name, const Variant& arg, int offset = 0); + CsvBuilder& Put(std::nullptr_t, const Variant& arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } + CsvBuilder& Put(std::string_view name, std::string_view arg, int offset = 0); + CsvBuilder& Put(std::string_view name, Uuid arg, int offset = 0); + CsvBuilder& Put(std::nullptr_t, std::string_view arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } + CsvBuilder& Put(std::string_view name, const char* arg, int offset = 0) { return Put(name, std::string_view(arg), offset); } + template ::value || std::is_floating_point::value>::type* = nullptr> + CsvBuilder& Put(std::string_view name, const T& arg, [[maybe_unused]] int offset = 0) { putName(name); (*ser_) << arg; return *this; } template - CsvBuilder &Put(int tagName, const T &arg, int offset = 0) { + CsvBuilder& Put(int tagName, const T& arg, int offset = 0) { return Put(getNameByTag(tagName), arg, offset); } - CsvBuilder &Raw(int tagName, std::string_view arg) { return Raw(getNameByTag(tagName), arg); } - CsvBuilder &Raw(std::string_view name, std::string_view arg); - CsvBuilder &Raw(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } - CsvBuilder &Json(std::string_view name, std::string_view arg) { return Raw(name, arg); } - CsvBuilder &Json(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } + CsvBuilder& Raw(int tagName, std::string_view arg) { return Raw(getNameByTag(tagName), arg); } + CsvBuilder& Raw(std::string_view name, std::string_view arg); + CsvBuilder& Raw(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } + CsvBuilder& Json(std::string_view name, std::string_view arg) { return Raw(name, arg); } + CsvBuilder& Json(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } - CsvBuilder &Null(int tagName) { return Null(getNameByTag(tagName)); } - CsvBuilder &Null(std::string_view name); + CsvBuilder& Null(int tagName) { return Null(getNameByTag(tagName)); } + CsvBuilder& Null(std::string_view name); - CsvBuilder &End(); + CsvBuilder& End(); protected: - CsvBuilder(ObjType type, const CsvBuilder &parent); + CsvBuilder(ObjType type, const CsvBuilder& parent); void putName(std::string_view name); std::string_view getNameByTag(int tagName); void tmProcessing(std::string_view name); void postProcessing(); - WrSerializer *ser_ = nullptr; - const TagsMatcher *tm_ = nullptr; + WrSerializer* ser_ = nullptr; + const TagsMatcher* tm_ = nullptr; ObjType type_ = ObjType::TypePlain; int count_ = 0; int level_ = 0; int startSerLen_ = 0; - const std::vector *ordering_ = nullptr; - WrSerializer *buf_ = nullptr; + const std::vector* ordering_ = nullptr; + WrSerializer* buf_ = nullptr; // idx - pos in ordering, {startTagPosInSer, endTagPosInSer(post culculated after received next tag)} std::vector> positions_; diff --git a/cpp_src/core/cjson/ctag.h b/cpp_src/core/cjson/ctag.h index 19567dd13..ffe6461ab 100644 --- a/cpp_src/core/cjson/ctag.h +++ b/cpp_src/core/cjson/ctag.h @@ -95,11 +95,13 @@ class carraytag { [[nodiscard]] RX_ALWAYS_INLINE constexpr bool operator!=(carraytag other) const noexcept { return !operator==(other); } private: - RX_ALWAYS_INLINE explicit constexpr carraytag(uint32_t atag) noexcept : carraytag{countImpl(atag), typeImpl(atag)} { assertrx_dbg(atag == atag_); } + RX_ALWAYS_INLINE explicit constexpr carraytag(uint32_t atag) noexcept : carraytag{countImpl(atag), typeImpl(atag)} { + assertrx_dbg(atag == atag_); + } [[nodiscard]] RX_ALWAYS_INLINE constexpr uint32_t asNumber() const noexcept { return atag_; } [[nodiscard]] RX_ALWAYS_INLINE static constexpr TagType typeImpl(uint32_t atag) noexcept { assertrx_dbg(((atag >> kCountBits) & kTypeMask) <= kMaxTagType); - return static_cast((atag >> kCountBits) & kTypeMask); // NOLINT(*EnumCastOutOfRange) + return static_cast((atag >> kCountBits) & kTypeMask); // NOLINT(*EnumCastOutOfRange) } [[nodiscard]] RX_ALWAYS_INLINE static constexpr uint32_t countImpl(uint32_t atag) noexcept { return atag & kCountMask; } diff --git a/cpp_src/core/cjson/defaultvaluecoder.cc b/cpp_src/core/cjson/defaultvaluecoder.cc index 6c6b5eb96..d33713150 100644 --- a/cpp_src/core/cjson/defaultvaluecoder.cc +++ b/cpp_src/core/cjson/defaultvaluecoder.cc @@ -2,7 +2,7 @@ namespace reindexer { -DefaultValueCoder::DefaultValueCoder(std::string_view ns, const PayloadFieldType &fld, std::vector &&tps, int16_t fieldIdx) +DefaultValueCoder::DefaultValueCoder(std::string_view ns, const PayloadFieldType& fld, std::vector&& tps, int16_t fieldIdx) : ns_(ns), field_(fld.Name()), tags_(std::move(tps)), @@ -19,31 +19,31 @@ bool DefaultValueCoder::Match(int field) noexcept { return false; // returned result is always same } -bool DefaultValueCoder::Match(TagType tt, const TagsPath &tp) { +bool DefaultValueCoder::Match(TagType tt, const TagsPath& tp) { static const bool result = false; // returned result is always same // nothing to look for (start tuple global object) if (tp.empty()) { state_ = State::wait; - inArray_ = false; - arrField_ = 0; + // inArray_ = false; + // arrField_ = 0; return result; } // found\recorded earlier - if ((state_ == State::found) || ((state_ == State::write) && !inArray_)) { + if ((state_ == State::found) || ((state_ == State::write) /* && !inArray_*/)) { return result; } // check if active array has been processed const bool arrayTag = (tt == TAG_ARRAY); - if (inArray_) { - inArray_ = ((tt == TAG_OBJECT) || arrayTag) ? (tp.back() == arrField_) : (tp[tp.size() - 2] == arrField_); // -2 pre-last item - // recorded earlier - stop it - if (!inArray_ && (state_ == State::write)) { - return result; - } - } + // if (inArray_) { + // inArray_ = ((tt == TAG_OBJECT) || arrayTag) ? (tp.back() == arrField_) : (tp[tp.size() - 2] == arrField_); // -2 pre-last item + // // recorded earlier - stop it + // if (!inArray_ && (state_ == State::write)) { + // return result; + // } + // } // try match nested field if (tt == TAG_OBJECT) { @@ -54,8 +54,13 @@ bool DefaultValueCoder::Match(TagType tt, const TagsPath &tp) { // may be end element of adjacent nested field if (arrayTag) { - inArray_ = (tp.front() == basePath_->front()); - arrField_ = tp.back(); + if (tp.size() <= basePath_->size() && std::equal(tp.begin(), tp.end(), basePath_->begin())) { + // Do not create anything inside objects arrays #1819 + state_ = State::found; + return result; + } + // inArray_ = (tp.front() == basePath_->front()); + // arrField_ = tp.back(); } // not nested @@ -73,7 +78,7 @@ bool DefaultValueCoder::Match(TagType tt, const TagsPath &tp) { return result; } -void DefaultValueCoder::Serialize(WrSerializer &wrser) { +void DefaultValueCoder::Serialize(WrSerializer& wrser) { if (blocked()) { return; // skip processing } @@ -89,9 +94,9 @@ void DefaultValueCoder::Serialize(WrSerializer &wrser) { } } - write(wrser); + const auto written = write(wrser); Reset(); - state_ = State::write; + state_ = written ? State::write : State::found; } bool DefaultValueCoder::Reset() noexcept { @@ -101,10 +106,10 @@ bool DefaultValueCoder::Reset() noexcept { return (state_ == State::write); } -void DefaultValueCoder::match(const TagsPath &tp) { +void DefaultValueCoder::match(const TagsPath& tp) { ++nestingLevel_; - for (auto &path : tags_) { + for (auto& path : tags_) { if (path.front() != tp.front()) { continue; } @@ -131,7 +136,11 @@ void DefaultValueCoder::match(const TagsPath &tp) { } } -void DefaultValueCoder::write(WrSerializer &wrser) const { +bool DefaultValueCoder::write(WrSerializer& wrser) const { + if (array_ && copyPos_ + 1 < basePath_->size()) { + // Do not create multiple levels for nested array indexes to avoid problems with decoding in Go/Java connectors. #1819 + return false; + } int32_t nestedObjects = 0; for (size_t idx = copyPos_, sz = basePath_->size(); idx < sz; ++idx) { auto tagName = (*basePath_)[idx]; @@ -156,6 +165,7 @@ void DefaultValueCoder::write(WrSerializer &wrser) const { while (nestedObjects-- > 0) { wrser.PutCTag(kCTagEnd); } + return true; } } // namespace reindexer diff --git a/cpp_src/core/cjson/defaultvaluecoder.h b/cpp_src/core/cjson/defaultvaluecoder.h index 3cf9a5dac..3f4276dc2 100644 --- a/cpp_src/core/cjson/defaultvaluecoder.h +++ b/cpp_src/core/cjson/defaultvaluecoder.h @@ -6,18 +6,18 @@ namespace reindexer { class DefaultValueCoder : public Recoder { public: - DefaultValueCoder(std::string_view ns, const PayloadFieldType &fld, std::vector &&tps, int16_t fieldIdx); + DefaultValueCoder(std::string_view ns, const PayloadFieldType& fld, std::vector&& tps, int16_t fieldIdx); RX_ALWAYS_INLINE TagType Type(TagType tt) noexcept override final { return tt; } [[nodiscard]] bool Match(int f) noexcept override final; - [[nodiscard]] bool Match(TagType tt, const TagsPath &tp) override final; - RX_ALWAYS_INLINE void Recode(Serializer &, WrSerializer &) const noexcept override final { assertrx(false); } - RX_ALWAYS_INLINE void Recode(Serializer &, Payload &, int, WrSerializer &) noexcept override final { assertrx(false); } - void Serialize(WrSerializer &wrser) override final; + [[nodiscard]] bool Match(TagType tt, const TagsPath& tp) override final; + RX_ALWAYS_INLINE void Recode(Serializer&, WrSerializer&) const noexcept override final { assertrx(false); } + RX_ALWAYS_INLINE void Recode(Serializer&, Payload&, int, WrSerializer&) noexcept override final { assertrx(false); } + void Serialize(WrSerializer& wrser) override final; bool Reset() noexcept override final; private: - void match(const TagsPath &tp); - void write(WrSerializer &wrser) const; + void match(const TagsPath& tp); + [[nodiscard]] bool write(WrSerializer& wrser) const; [[nodiscard]] RX_ALWAYS_INLINE bool blocked() const noexcept { return ((state_ == State::found) || (state_ == State::write)); } [[nodiscard]] RX_ALWAYS_INLINE bool ready() const noexcept { return ((state_ == State::wait) || (state_ == State::match)); } @@ -29,13 +29,13 @@ class DefaultValueCoder : public Recoder { const TagType type_; const bool array_{false}; - const TagsPath *basePath_{nullptr}; + const TagsPath* basePath_{nullptr}; enum class State { wait, found, match, write } state_{State::wait}; uint32_t nestingLevel_{1}; uint32_t copyPos_{0}; - bool inArray_{false}; - int16_t arrField_{0}; + // bool inArray_{false}; + // int16_t arrField_{0}; }; } // namespace reindexer diff --git a/cpp_src/core/cjson/fieldextractor.h b/cpp_src/core/cjson/fieldextractor.h index 79247070d..5112b3110 100644 --- a/cpp_src/core/cjson/fieldextractor.h +++ b/cpp_src/core/cjson/fieldextractor.h @@ -10,21 +10,21 @@ class FieldsExtractor { public: class FieldParams { public: - int &index; - int &length; + int& index; + int& length; int field; }; FieldsExtractor() = default; - FieldsExtractor(VariantArray *va, KeyValueType expectedType, int expectedPathDepth, const FieldsSet *filter, - FieldParams *params = nullptr) noexcept + FieldsExtractor(VariantArray* va, KeyValueType expectedType, int expectedPathDepth, const FieldsSet* filter, + FieldParams* params = nullptr) noexcept : values_(va), expectedType_(expectedType), expectedPathDepth_(expectedPathDepth), filter_(filter), params_(params) {} - FieldsExtractor(FieldsExtractor &&other) = default; - FieldsExtractor(const FieldsExtractor &) = delete; - FieldsExtractor &operator=(const FieldsExtractor &) = delete; - FieldsExtractor &operator=(FieldsExtractor &&) = delete; + FieldsExtractor(FieldsExtractor&& other) = default; + FieldsExtractor(const FieldsExtractor&) = delete; + FieldsExtractor& operator=(const FieldsExtractor&) = delete; + FieldsExtractor& operator=(FieldsExtractor&&) = delete; - void SetTagsMatcher(const TagsMatcher *) noexcept {} + void SetTagsMatcher(const TagsMatcher*) noexcept {} FieldsExtractor Object(int) noexcept { return FieldsExtractor(values_, expectedType_, expectedPathDepth_ - 1, filter_, params_); } FieldsExtractor Array(int) noexcept { @@ -41,7 +41,7 @@ class FieldsExtractor { template void Array(int, span data, int offset) { - const IndexedPathNode &pathNode = getArrayPathNode(); + const IndexedPathNode& pathNode = getArrayPathNode(); const PathType ptype = pathNotToType(pathNode); if (ptype == PathType::Other) { throw Error(errLogic, "Unable to extract array value without index value"); @@ -60,13 +60,13 @@ class FieldsExtractor { if (ptype == PathType::WithIndex) { int i = 0; - for (const auto &d : data) { + for (const auto& d : data) { if (i++ == pathNode.Index()) { put(0, Variant(d)); } } } else { - for (const auto &d : data) { + for (const auto& d : data) { put(0, Variant(d)); } } @@ -76,8 +76,8 @@ class FieldsExtractor { } } - void Array(int, Serializer &ser, TagType tagType, int count) { - const IndexedPathNode &pathNode = getArrayPathNode(); + void Array(int, Serializer& ser, TagType tagType, int count) { + const IndexedPathNode& pathNode = getArrayPathNode(); const PathType ptype = pathNotToType(pathNode); if (ptype == PathType::Other) { throw Error(errLogic, "Unable to extract array value without index value"); @@ -112,8 +112,10 @@ class FieldsExtractor { } } - FieldsExtractor &Put(int t, Variant arg, int offset) { - if (expectedPathDepth_ > 0) return *this; + FieldsExtractor& Put(int t, Variant arg, int offset) { + if (expectedPathDepth_ > 0) { + return *this; + } if (params_) { if (params_->index >= 0 && params_->length > 0 && offset == params_->index + params_->length) { // Concatenate fields from objects, nested in arrays @@ -127,11 +129,11 @@ class FieldsExtractor { } template - FieldsExtractor &Put(int tag, const T &arg, int offset) { + FieldsExtractor& Put(int tag, const T& arg, int offset) { return Put(tag, Variant{arg}, offset); } - FieldsExtractor &Null(int) noexcept { return *this; } + FieldsExtractor& Null(int) noexcept { return *this; } int TargetField() { return params_ ? params_->field : IndexValueType::NotSet; } bool IsHavingOffset() const noexcept { return params_ && (params_->length >= 0 || params_->index >= 0); } void OnScopeEnd(int offset) noexcept { @@ -144,41 +146,47 @@ class FieldsExtractor { private: enum class PathType { AllItems, WithIndex, Other }; - PathType pathNotToType(const IndexedPathNode &pathNode) noexcept { + PathType pathNotToType(const IndexedPathNode& pathNode) noexcept { return pathNode.IsForAllItems() ? PathType::AllItems : (pathNode.Index() == IndexValueType::NotSet) ? PathType::Other : PathType::WithIndex; } - FieldsExtractor &put(int, Variant arg) { - if (expectedPathDepth_ > 0) return *this; + FieldsExtractor& put(int, Variant arg) { + if (expectedPathDepth_ > 0) { + return *this; + } expectedType_.EvaluateOneOf( [&](OneOf) { arg.convert(expectedType_); }, [](OneOf) noexcept {}); assertrx_throw(values_); values_->emplace_back(std::move(arg)); - if (expectedPathDepth_ < 0) values_->MarkObject(); + if (expectedPathDepth_ < 0) { + values_->MarkObject(); + } return *this; } - const IndexedPathNode &getArrayPathNode() const { + const IndexedPathNode& getArrayPathNode() const { if (filter_ && filter_->getTagsPathsLength() > 0) { size_t lastItemIndex = filter_->getTagsPathsLength() - 1; if (filter_->isTagsPathIndexed(lastItemIndex)) { - const IndexedTagsPath &path = filter_->getIndexedTagsPath(lastItemIndex); + const IndexedTagsPath& path = filter_->getIndexedTagsPath(lastItemIndex); assertrx(path.size() > 0); - if (path.back().IsArrayNode()) return path.back(); + if (path.back().IsArrayNode()) { + return path.back(); + } } } static const IndexedPathNode commonNode{IndexedPathNode::AllItems}; return commonNode; } - VariantArray *values_ = nullptr; + VariantArray* values_ = nullptr; KeyValueType expectedType_{KeyValueType::Undefined{}}; int expectedPathDepth_ = 0; - const FieldsSet *filter_; - FieldParams *params_; + const FieldsSet* filter_; + FieldParams* params_; }; } // namespace reindexer diff --git a/cpp_src/core/cjson/jschemachecker.cc b/cpp_src/core/cjson/jschemachecker.cc index b36864211..46a904e6b 100644 --- a/cpp_src/core/cjson/jschemachecker.cc +++ b/cpp_src/core/cjson/jschemachecker.cc @@ -2,21 +2,25 @@ #include #include #include +#include "core/formatters/jsonstring_fmt.h" #include "estl/fast_hash_map.h" #include "estl/h_vector.h" -#include "gason/gason.h" #include "tools/errors.h" namespace reindexer { JsonSchemaChecker::JsonSchemaChecker(const std::string& json, std::string rootTypeName) : rootTypeName_(std::move(rootTypeName)) { Error err = createTypeTable(json); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } isInit = true; } Error JsonSchemaChecker::Init(const std::string& json, std::string rootTypeName) { - if (isInit) return Error(errLogic, "JsonSchemaChecker already initialized."); + if (isInit) { + return Error(errLogic, "JsonSchemaChecker already initialized."); + } rootTypeName_ = std::move(rootTypeName); return createTypeTable(json); } @@ -29,7 +33,9 @@ bool JsonSchemaChecker::isSimpleType(std::string_view tp) { std::string JsonSchemaChecker::createType(const PrefixTree::PrefixTreeNode* node, const std::string& typeName) { using namespace std::string_view_literals; JsonSchemaChecker::TypeDescr typeDescr; - if (indexes_.find(typeName) != indexes_.end()) return typeName; + if (indexes_.find(typeName) != indexes_.end()) { + return typeName; + } if (node->children.empty() && node->props.allowAdditionalProps == true) { return std::string("any"); } @@ -54,7 +60,9 @@ std::string JsonSchemaChecker::createType(const PrefixTree::PrefixTreeNode* node throw Error(errLogic, "Incorrect schema type [%s]", chProps.type); } auto typeIndexIt = indexes_.find(subElement.typeName); - if (typeIndexIt == indexes_.end()) throw Error(errLogic, "Incorrect type %s", subElement.typeName); + if (typeIndexIt == indexes_.end()) { + throw Error(errLogic, "Incorrect type %s", subElement.typeName); + } subElement.typeIndex = typeIndexIt->second; typeDescr.subElementsTable.emplace_back(ch.first, std::move(subElement)); } @@ -74,7 +82,9 @@ void JsonSchemaChecker::addSimpleType(std::string tpName) { Error JsonSchemaChecker::createTypeTable(const std::string& json) { auto err = schema_.FromJSON(std::string_view(json)); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } auto root = schema_.GetRoot(); addSimpleType("any"); @@ -107,7 +117,9 @@ Error JsonSchemaChecker::Check(gason::JsonNode node) { } auto indxIt = indexes_.find(rootTypeName_); - if (indxIt == indexes_.end()) return Error(errParseJson, "Type '%s' not found.", rootTypeName_); + if (indxIt == indexes_.end()) { + return Error(errParseJson, "Type '%s' not found.", rootTypeName_); + } int nType = indxIt->second; std::string path; path.reserve(512); @@ -133,18 +145,23 @@ Error JsonSchemaChecker::checkScheme(const gason::JsonNode& node, int typeIndex, for (const auto& elem : node) { auto subElemIndex = descr.subElementsIndex.find(std::string_view(elem.key)); if (subElemIndex == descr.subElementsIndex.end()) { - if (!descr.allowAdditionalProps) + if (!descr.allowAdditionalProps) { return Error(errParseJson, "Key [%s] not allowed in [%s] object.", elem.key, path); - else + } else { continue; + } } err = checkExists(elem.key, &mmVals[subElemIndex->second], path); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } if (elem.value.getTag() == gason::JSON_OBJECT) { if (descr.subElementsTable[subElemIndex->second].second.typeName != "any") { err = checkScheme(elem, descr.subElementsTable[subElemIndex->second].second.typeIndex, path, descr.subElementsTable[subElemIndex->second].first); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } } else if (elem.value.getTag() == gason::JSON_ARRAY) { if (descr.subElementsTable[subElemIndex->second].second.typeName != "any") { @@ -155,7 +172,9 @@ Error JsonSchemaChecker::checkScheme(const gason::JsonNode& node, int typeIndex, if (entry.value.getTag() == gason::JSON_ARRAY || entry.value.getTag() == gason::JSON_OBJECT) { err = checkScheme(entry, descr.subElementsTable[subElemIndex->second].second.typeIndex, path, descr.subElementsTable[subElemIndex->second].first); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } } } diff --git a/cpp_src/core/cjson/jschemachecker.h b/cpp_src/core/cjson/jschemachecker.h index a869453ee..f0c1abc19 100644 --- a/cpp_src/core/cjson/jschemachecker.h +++ b/cpp_src/core/cjson/jschemachecker.h @@ -12,7 +12,7 @@ namespace reindexer { class JsonSchemaChecker { public: explicit JsonSchemaChecker(const std::string& json, std::string rootTypeName); - JsonSchemaChecker(){}; + JsonSchemaChecker() {}; Error Init(const std::string& json, std::string rootTypeName); Error Check(gason::JsonNode node); diff --git a/cpp_src/core/cjson/jsonbuilder.cc b/cpp_src/core/cjson/jsonbuilder.cc index b772dd0db..e93c05d05 100644 --- a/cpp_src/core/cjson/jsonbuilder.cc +++ b/cpp_src/core/cjson/jsonbuilder.cc @@ -2,7 +2,7 @@ namespace reindexer { -JsonBuilder::JsonBuilder(WrSerializer &ser, ObjType type, const TagsMatcher *tm, bool emitTrailingForFloat) +JsonBuilder::JsonBuilder(WrSerializer& ser, ObjType type, const TagsMatcher* tm, bool emitTrailingForFloat) : ser_(&ser), tm_(tm), type_(type), emitTrailingForFloat_(emitTrailingForFloat) { switch (type_) { case ObjType::TypeArray: @@ -19,7 +19,7 @@ JsonBuilder::JsonBuilder(WrSerializer &ser, ObjType type, const TagsMatcher *tm, std::string_view JsonBuilder::getNameByTag(int tagName) { return tagName ? tm_->tag2name(tagName) : std::string_view(); } -JsonBuilder &JsonBuilder::End() { +JsonBuilder& JsonBuilder::End() { switch (type_) { case ObjType::TypeArray: (*ser_) << ']'; @@ -47,38 +47,40 @@ JsonBuilder JsonBuilder::Array(std::string_view name, int /*size*/) { } void JsonBuilder::putName(std::string_view name) { - if (count_++) (*ser_) << ','; + if (count_++) { + (*ser_) << ','; + } if (name.data()) { // -V547 ser_->PrintJsonString(name); (*ser_) << ':'; } } -JsonBuilder &JsonBuilder::Put(std::string_view name, std::string_view arg, int /*offset*/) { +JsonBuilder& JsonBuilder::Put(std::string_view name, std::string_view arg, int /*offset*/) { putName(name); ser_->PrintJsonString(arg); return *this; } -JsonBuilder &JsonBuilder::Put(std::string_view name, Uuid arg, int /*offset*/) { +JsonBuilder& JsonBuilder::Put(std::string_view name, Uuid arg, int /*offset*/) { putName(name); ser_->PrintJsonUuid(arg); return *this; } -JsonBuilder &JsonBuilder::Raw(std::string_view name, std::string_view arg) { +JsonBuilder& JsonBuilder::Raw(std::string_view name, std::string_view arg) { putName(name); (*ser_) << arg; return *this; } -JsonBuilder &JsonBuilder::Null(std::string_view name) { +JsonBuilder& JsonBuilder::Null(std::string_view name) { putName(name); (*ser_) << "null"; return *this; } -JsonBuilder &JsonBuilder::Put(std::string_view name, const Variant &kv, int offset) { +JsonBuilder& JsonBuilder::Put(std::string_view name, const Variant& kv, int offset) { kv.Type().EvaluateOneOf( [&](KeyValueType::Int) { Put(name, int(kv), offset); }, [&](KeyValueType::Int64) { Put(name, int64_t(kv), offset); }, [&](KeyValueType::Double) { Put(name, double(kv), offset); }, @@ -86,7 +88,7 @@ JsonBuilder &JsonBuilder::Put(std::string_view name, const Variant &kv, int offs [&](KeyValueType::Bool) { Put(name, bool(kv), offset); }, [&](KeyValueType::Tuple) { auto arrNode = Array(name); - for (auto &val : kv.getCompositeValues()) { + for (auto& val : kv.getCompositeValues()) { arrNode.Put({nullptr, 0}, val, offset); } }, diff --git a/cpp_src/core/cjson/jsonbuilder.h b/cpp_src/core/cjson/jsonbuilder.h index 813a2fd42..015ec978a 100644 --- a/cpp_src/core/cjson/jsonbuilder.h +++ b/cpp_src/core/cjson/jsonbuilder.h @@ -9,17 +9,17 @@ namespace reindexer { class JsonBuilder { public: JsonBuilder() noexcept : ser_(nullptr), tm_(nullptr) {} - JsonBuilder(WrSerializer &ser, ObjType type = ObjType::TypeObject, const TagsMatcher *tm = nullptr, bool emitTrailingForFloat = true); + JsonBuilder(WrSerializer& ser, ObjType type = ObjType::TypeObject, const TagsMatcher* tm = nullptr, bool emitTrailingForFloat = true); ~JsonBuilder() { End(); } - JsonBuilder(const JsonBuilder &) = delete; - JsonBuilder(JsonBuilder &&other) noexcept + JsonBuilder(const JsonBuilder&) = delete; + JsonBuilder(JsonBuilder&& other) noexcept : ser_(other.ser_), tm_(other.tm_), type_(other.type_), count_(other.count_), emitTrailingForFloat_(other.emitTrailingForFloat_) { other.type_ = ObjType::TypePlain; } - JsonBuilder &operator=(const JsonBuilder &) = delete; - JsonBuilder &operator=(JsonBuilder &&) = delete; + JsonBuilder& operator=(const JsonBuilder&) = delete; + JsonBuilder& operator=(JsonBuilder&&) = delete; - void SetTagsMatcher(const TagsMatcher *tm) noexcept { tm_ = tm; } + void SetTagsMatcher(const TagsMatcher* tm) noexcept { tm_ = tm; } void EmitTrailingForFloat(bool val) noexcept { emitTrailingForFloat_ = val; } /// Start new object @@ -33,39 +33,47 @@ class JsonBuilder { template void Array(int tagName, span data, int /*offset*/ = 0) { JsonBuilder node = Array(tagName); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } template void Array(std::string_view n, span data, int /*offset*/ = 0) { JsonBuilder node = Array(n); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } template void Array(std::string_view n, std::initializer_list data, int /*offset*/ = 0) { JsonBuilder node = Array(n); - for (const auto &d : data) node.Put({}, d); + for (const auto& d : data) { + node.Put({}, d); + } } - void Array(int tagName, Serializer &ser, TagType tagType, int count) { + void Array(int tagName, Serializer& ser, TagType tagType, int count) { JsonBuilder node = Array(tagName); const KeyValueType kvt{tagType}; - while (count--) node.Put({}, ser.GetRawVariant(kvt)); + while (count--) { + node.Put({}, ser.GetRawVariant(kvt)); + } } - JsonBuilder &Put(std::string_view name, const Variant &arg, int offset = 0); - JsonBuilder &Put(std::nullptr_t, const Variant &arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } - JsonBuilder &Put(std::string_view name, std::string_view arg, int offset = 0); - JsonBuilder &Put(std::string_view name, Uuid arg, int offset = 0); - JsonBuilder &Put(std::nullptr_t, std::string_view arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } - JsonBuilder &Put(std::string_view name, const char *arg, int offset = 0) { return Put(name, std::string_view(arg), offset); } - template ::value>::type * = nullptr> - JsonBuilder &Put(std::string_view name, const T &arg, int /*offset*/ = 0) { + JsonBuilder& Put(std::string_view name, const Variant& arg, int offset = 0); + JsonBuilder& Put(std::nullptr_t, const Variant& arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } + JsonBuilder& Put(std::string_view name, std::string_view arg, int offset = 0); + JsonBuilder& Put(std::string_view name, Uuid arg, int offset = 0); + JsonBuilder& Put(std::nullptr_t, std::string_view arg, int offset = 0) { return Put(std::string_view{}, arg, offset); } + JsonBuilder& Put(std::string_view name, const char* arg, int offset = 0) { return Put(name, std::string_view(arg), offset); } + template ::value>::type* = nullptr> + JsonBuilder& Put(std::string_view name, const T& arg, int /*offset*/ = 0) { putName(name); (*ser_) << arg; return *this; } - template ::value>::type * = nullptr> - JsonBuilder &Put(std::string_view name, const T &arg, int /*offset*/ = 0) { + template ::value>::type* = nullptr> + JsonBuilder& Put(std::string_view name, const T& arg, int /*offset*/ = 0) { putName(name); if (emitTrailingForFloat_) { (*ser_) << arg; @@ -75,27 +83,27 @@ class JsonBuilder { return *this; } template - JsonBuilder &Put(int tagName, const T &arg, int offset = 0) { + JsonBuilder& Put(int tagName, const T& arg, int offset = 0) { return Put(getNameByTag(tagName), arg, offset); } - JsonBuilder &Raw(int tagName, std::string_view arg) { return Raw(getNameByTag(tagName), arg); } - JsonBuilder &Raw(std::string_view name, std::string_view arg); - JsonBuilder &Raw(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } - JsonBuilder &Json(std::string_view name, std::string_view arg) { return Raw(name, arg); } - JsonBuilder &Json(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } + JsonBuilder& Raw(int tagName, std::string_view arg) { return Raw(getNameByTag(tagName), arg); } + JsonBuilder& Raw(std::string_view name, std::string_view arg); + JsonBuilder& Raw(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } + JsonBuilder& Json(std::string_view name, std::string_view arg) { return Raw(name, arg); } + JsonBuilder& Json(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } - JsonBuilder &Null(int tagName) { return Null(getNameByTag(tagName)); } - JsonBuilder &Null(std::string_view name); + JsonBuilder& Null(int tagName) { return Null(getNameByTag(tagName)); } + JsonBuilder& Null(std::string_view name); - JsonBuilder &End(); + JsonBuilder& End(); protected: void putName(std::string_view name); std::string_view getNameByTag(int tagName); - WrSerializer *ser_; - const TagsMatcher *tm_; + WrSerializer* ser_; + const TagsMatcher* tm_; ObjType type_ = ObjType::TypePlain; int count_ = 0; bool emitTrailingForFloat_ = true; diff --git a/cpp_src/core/cjson/jsondecoder.cc b/cpp_src/core/cjson/jsondecoder.cc index aa153a828..85d3ac79d 100644 --- a/cpp_src/core/cjson/jsondecoder.cc +++ b/cpp_src/core/cjson/jsondecoder.cc @@ -9,7 +9,7 @@ namespace reindexer { -Error JsonDecoder::Decode(Payload &pl, WrSerializer &wrser, const gason::JsonValue &v) { +Error JsonDecoder::Decode(Payload& pl, WrSerializer& wrser, const gason::JsonValue& v) { try { objectScalarIndexes_.reset(); tagsPath_.clear(); @@ -17,42 +17,43 @@ Error JsonDecoder::Decode(Payload &pl, WrSerializer &wrser, const gason::JsonVal decodeJson(&pl, builder, v, 0, true); } - catch (const Error &err) { + catch (const Error& err) { return err; } return {}; } -void JsonDecoder::decodeJsonObject(Payload &pl, CJsonBuilder &builder, const gason::JsonValue &v, bool match) { - for (const auto &elem : v) { +void JsonDecoder::decodeJsonObject(Payload& pl, CJsonBuilder& builder, const gason::JsonValue& v, bool match) { + for (const auto& elem : v) { int tagName = tagsMatcher_.name2tag(elem.key, true); assertrx(tagName); tagsPath_.emplace_back(tagName); int field = tagsMatcher_.tags2field(tagsPath_.data(), tagsPath_.size()); if (filter_) { - if (field >= 0) + if (field >= 0) { match = filter_->contains(field); - else + } else { match = match && filter_->match(tagsPath_); + } } if (field < 0) { decodeJson(&pl, builder, elem.value, tagName, match); } else if (match) { // Indexed field. extract it - const auto &f = pl.Type().Field(field); + const auto& f = pl.Type().Field(field); switch (elem.value.getTag()) { case gason::JSON_ARRAY: { if rx_unlikely (!f.IsArray()) { throw Error(errLogic, "Error parsing json field '%s' - got array, expected scalar %s", f.Name(), f.Type().Name()); } int count = 0; - for (auto &subelem : elem.value) { + for (auto& subelem : elem.value) { (void)subelem; ++count; } int pos = pl.ResizeArray(field, count, true); - for (auto &subelem : elem.value) { + for (auto& subelem : elem.value) { pl.Set(field, pos++, jsonValue2Variant(subelem.value, f.Type(), f.Name())); } builder.ArrayRef(tagName, field, count); @@ -87,9 +88,11 @@ void JsonDecoder::decodeJsonObject(Payload &pl, CJsonBuilder &builder, const gas // Split original JSON into 2 parts: // 1. PayloadFields - fields from json found by 'jsonPath' tags // 2. stripped binary packed JSON without fields values found by 'jsonPath' tags -void JsonDecoder::decodeJson(Payload *pl, CJsonBuilder &builder, const gason::JsonValue &v, int tagName, bool match) { +void JsonDecoder::decodeJson(Payload* pl, CJsonBuilder& builder, const gason::JsonValue& v, int tagName, bool match) { auto jsonTag = v.getTag(); - if (!match && jsonTag != gason::JSON_OBJECT) return; + if (!match && jsonTag != gason::JSON_OBJECT) { + return; + } switch (jsonTag) { case gason::JSON_NUMBER: { int64_t value = v.toNumber(); @@ -120,7 +123,7 @@ void JsonDecoder::decodeJson(Payload *pl, CJsonBuilder &builder, const gason::Js type = ObjType::TypeObjectArray; } auto arrNode = builder.Array(tagName, type); - for (const auto &elem : v) { + for (const auto& elem : v) { decodeJson(pl, arrNode, elem.value, 0, match); } break; @@ -141,29 +144,29 @@ void JsonDecoder::decodeJson(Payload *pl, CJsonBuilder &builder, const gason::Js class TagsPathGuard { public: - TagsPathGuard(TagsPath &tagsPath, int tagName) noexcept : tagsPath_(tagsPath) { tagsPath_.emplace_back(tagName); } + TagsPathGuard(TagsPath& tagsPath, int tagName) noexcept : tagsPath_(tagsPath) { tagsPath_.emplace_back(tagName); } ~TagsPathGuard() { tagsPath_.pop_back(); } public: - TagsPath &tagsPath_; + TagsPath& tagsPath_; }; -void JsonDecoder::decodeJsonObject(const gason::JsonValue &root, CJsonBuilder &builder) { - for (const auto &elem : root) { +void JsonDecoder::decodeJsonObject(const gason::JsonValue& root, CJsonBuilder& builder) { + for (const auto& elem : root) { int tagName = tagsMatcher_.name2tag(elem.key, true); TagsPathGuard tagsPathGuard(tagsPath_, tagName); decodeJson(nullptr, builder, elem.value, tagName, true); } } -void JsonDecoder::Decode(std::string_view json, CJsonBuilder &builder, const TagsPath &fieldPath) { +void JsonDecoder::Decode(std::string_view json, CJsonBuilder& builder, const TagsPath& fieldPath) { try { objectScalarIndexes_.reset(); tagsPath_ = fieldPath; gason::JsonParser jsonParser; gason::JsonNode root = jsonParser.Parse(json); decodeJsonObject(root.value, builder); - } catch (gason::Exception &e) { + } catch (gason::Exception& e) { throw Error(errParseJson, "JSONDecoder: %s", e.what()); } } diff --git a/cpp_src/core/cjson/jsondecoder.h b/cpp_src/core/cjson/jsondecoder.h index c44a1432c..73dad50f2 100644 --- a/cpp_src/core/cjson/jsondecoder.h +++ b/cpp_src/core/cjson/jsondecoder.h @@ -8,20 +8,20 @@ namespace reindexer { class JsonDecoder { public: - explicit JsonDecoder(TagsMatcher &tagsMatcher) noexcept : tagsMatcher_(tagsMatcher), filter_(nullptr) {} - JsonDecoder(TagsMatcher &tagsMatcher, const FieldsSet *filter) noexcept : tagsMatcher_(tagsMatcher), filter_(filter) {} - Error Decode(Payload &pl, WrSerializer &wrSer, const gason::JsonValue &v); - void Decode(std::string_view json, CJsonBuilder &builder, const TagsPath &fieldPath); + explicit JsonDecoder(TagsMatcher& tagsMatcher) noexcept : tagsMatcher_(tagsMatcher), filter_(nullptr) {} + JsonDecoder(TagsMatcher& tagsMatcher, const FieldsSet* filter) noexcept : tagsMatcher_(tagsMatcher), filter_(filter) {} + Error Decode(Payload& pl, WrSerializer& wrSer, const gason::JsonValue& v); + void Decode(std::string_view json, CJsonBuilder& builder, const TagsPath& fieldPath); private: - void decodeJsonObject(const gason::JsonValue &root, CJsonBuilder &builder); - void decodeJsonObject(Payload &pl, CJsonBuilder &builder, const gason::JsonValue &v, bool match); - void decodeJson(Payload *pl, CJsonBuilder &builder, const gason::JsonValue &v, int tag, bool match); + void decodeJsonObject(const gason::JsonValue& root, CJsonBuilder& builder); + void decodeJsonObject(Payload& pl, CJsonBuilder& builder, const gason::JsonValue& v, bool match); + void decodeJson(Payload* pl, CJsonBuilder& builder, const gason::JsonValue& v, int tag, bool match); bool isInArray() const noexcept { return arrayLevel_ > 0; } - TagsMatcher &tagsMatcher_; + TagsMatcher& tagsMatcher_; TagsPath tagsPath_; - const FieldsSet *filter_; + const FieldsSet* filter_; int32_t arrayLevel_ = 0; ScalarIndexesSetT objectScalarIndexes_; }; diff --git a/cpp_src/core/cjson/msgpackbuilder.cc b/cpp_src/core/cjson/msgpackbuilder.cc index f50ba39eb..16158de01 100644 --- a/cpp_src/core/cjson/msgpackbuilder.cc +++ b/cpp_src/core/cjson/msgpackbuilder.cc @@ -5,46 +5,48 @@ namespace reindexer { -MsgPackBuilder::MsgPackBuilder(WrSerializer &wrser, ObjType type, size_t size) +MsgPackBuilder::MsgPackBuilder(WrSerializer& wrser, ObjType type, size_t size) : tm_(nullptr), tagsLengths_(nullptr), type_(type), tagIndex_(nullptr) { - msgpack_packer_init(&packer_, reinterpret_cast(&wrser), msgpack_wrserializer_write); + msgpack_packer_init(&packer_, reinterpret_cast(&wrser), msgpack_wrserializer_write); init(size); } -MsgPackBuilder::MsgPackBuilder(msgpack_packer &packer, ObjType type, size_t size) +MsgPackBuilder::MsgPackBuilder(msgpack_packer& packer, ObjType type, size_t size) : tm_(nullptr), packer_(packer), tagsLengths_(nullptr), type_(type), tagIndex_(nullptr) { init(size); } -MsgPackBuilder::MsgPackBuilder(WrSerializer &wrser, const TagsLengths *tagsLengths, int *startTag, ObjType type, const TagsMatcher *tm) +MsgPackBuilder::MsgPackBuilder(WrSerializer& wrser, const TagsLengths* tagsLengths, int* startTag, ObjType type, const TagsMatcher* tm) : tm_(tm), tagsLengths_(tagsLengths), type_(type), tagIndex_(startTag) { assertrx(startTag); - msgpack_packer_init(&packer_, reinterpret_cast(&wrser), msgpack_wrserializer_write); + msgpack_packer_init(&packer_, reinterpret_cast(&wrser), msgpack_wrserializer_write); init(KUnknownFieldSize); } -MsgPackBuilder::MsgPackBuilder(msgpack_packer &packer, const TagsLengths *tagsLengths, int *startTag, ObjType type, const TagsMatcher *tm) +MsgPackBuilder::MsgPackBuilder(msgpack_packer& packer, const TagsLengths* tagsLengths, int* startTag, ObjType type, const TagsMatcher* tm) : tm_(tm), packer_(packer), tagsLengths_(tagsLengths), type_(type), tagIndex_(startTag) { assertrx(startTag); init(KUnknownFieldSize); } -void MsgPackBuilder::Array(int tagName, Serializer &ser, TagType tagType, int count) { +void MsgPackBuilder::Array(int tagName, Serializer& ser, TagType tagType, int count) { checkIfCorrectArray(tagName); skipTag(); packKeyName(tagName); packArray(count); - while (count--) packCJsonValue(tagType, ser); + while (count--) { + packCJsonValue(tagType, ser); + } } -MsgPackBuilder &MsgPackBuilder::Json(std::string_view name, std::string_view arg) { +MsgPackBuilder& MsgPackBuilder::Json(std::string_view name, std::string_view arg) { gason::JsonParser parser; auto root = parser.Parse(arg); appendJsonObject(name, root); return *this; } -MsgPackBuilder &MsgPackBuilder::End() { +MsgPackBuilder& MsgPackBuilder::End() { switch (type_) { case ObjType::TypeObjectArray: case ObjType::TypeArray: @@ -77,7 +79,7 @@ void MsgPackBuilder::init(int size) { } } -void MsgPackBuilder::packCJsonValue(TagType tagType, Serializer &rdser) { +void MsgPackBuilder::packCJsonValue(TagType tagType, Serializer& rdser) { switch (tagType) { case TAG_DOUBLE: packValue(rdser.GetDouble()); @@ -104,7 +106,7 @@ void MsgPackBuilder::packCJsonValue(TagType tagType, Serializer &rdser) { } } -void MsgPackBuilder::appendJsonObject(std::string_view name, const gason::JsonNode &obj) { +void MsgPackBuilder::appendJsonObject(std::string_view name, const gason::JsonNode& obj) { auto type = obj.value.getTag(); switch (type) { case gason::JSON_STRING: { @@ -122,18 +124,18 @@ void MsgPackBuilder::appendJsonObject(std::string_view name, const gason::JsonNo case gason::JSON_OBJECT: case gason::JSON_ARRAY: { int size = 0; - for (const auto &node : obj) { + for (const auto& node : obj) { (void)node; ++size; } if (type == gason::JSON_OBJECT) { auto pack = Object(name, size); - for (const auto &node : obj) { + for (const auto& node : obj) { pack.appendJsonObject(std::string_view(node.key), node); } } else { auto pack = Array(name, size); - for (const auto &node : obj) { + for (const auto& node : obj) { pack.appendJsonObject(std::string_view(), node); } } diff --git a/cpp_src/core/cjson/msgpackbuilder.h b/cpp_src/core/cjson/msgpackbuilder.h index a6e6e5bb6..fa6244d1e 100644 --- a/cpp_src/core/cjson/msgpackbuilder.h +++ b/cpp_src/core/cjson/msgpackbuilder.h @@ -16,22 +16,22 @@ namespace reindexer { class MsgPackBuilder { public: - MsgPackBuilder(WrSerializer &wrser, ObjType type, size_t size); - MsgPackBuilder(msgpack_packer &packer, ObjType type, size_t size); - MsgPackBuilder(WrSerializer &wrser, const TagsLengths *tagsLengths, int *startTag, ObjType = ObjType::TypeObject, - const TagsMatcher *tm = nullptr); - MsgPackBuilder(msgpack_packer &packer, const TagsLengths *tagsLengths, int *startTag, ObjType = ObjType::TypeObject, - const TagsMatcher *tm = nullptr); + MsgPackBuilder(WrSerializer& wrser, ObjType type, size_t size); + MsgPackBuilder(msgpack_packer& packer, ObjType type, size_t size); + MsgPackBuilder(WrSerializer& wrser, const TagsLengths* tagsLengths, int* startTag, ObjType = ObjType::TypeObject, + const TagsMatcher* tm = nullptr); + MsgPackBuilder(msgpack_packer& packer, const TagsLengths* tagsLengths, int* startTag, ObjType = ObjType::TypeObject, + const TagsMatcher* tm = nullptr); MsgPackBuilder() noexcept : tm_(nullptr), packer_(), tagsLengths_(nullptr), type_(ObjType::TypePlain), tagIndex_(nullptr) {} ~MsgPackBuilder() { End(); } - MsgPackBuilder(MsgPackBuilder &&other) noexcept + MsgPackBuilder(MsgPackBuilder&& other) noexcept : tm_(other.tm_), packer_(other.packer_), tagsLengths_(other.tagsLengths_), type_(other.type_), tagIndex_(other.tagIndex_) {} - MsgPackBuilder(const MsgPackBuilder &) = delete; - MsgPackBuilder &operator=(const MsgPackBuilder &) = delete; - MsgPackBuilder &operator=(MsgPackBuilder &&) = delete; + MsgPackBuilder(const MsgPackBuilder&) = delete; + MsgPackBuilder& operator=(const MsgPackBuilder&) = delete; + MsgPackBuilder& operator=(MsgPackBuilder&&) = delete; - void SetTagsMatcher(const TagsMatcher *tm) noexcept { tm_ = tm; } + void SetTagsMatcher(const TagsMatcher* tm) noexcept { tm_ = tm; } MsgPackBuilder Raw(std::string_view, std::string_view) noexcept { return MsgPackBuilder(); } MsgPackBuilder Raw(std::nullptr_t, std::string_view arg) { return Raw(std::string_view{}, arg); } @@ -41,7 +41,9 @@ class MsgPackBuilder { skipTag(); packKeyName(tagName); packArray(data.size()); - for (const T &v : data) packValue(v); + for (const T& v : data) { + packValue(v); + } } template void Array(N tagName, span data, int /*offset*/ = 0) { @@ -49,7 +51,9 @@ class MsgPackBuilder { skipTag(); packKeyName(tagName); packArray(data.size()); - for (Uuid v : data) packValue(v); + for (Uuid v : data) { + packValue(v); + } } template @@ -58,7 +62,9 @@ class MsgPackBuilder { skipTag(); packKeyName(tagName); packArray(data.size()); - for (const p_string &v : data) packValue(std::string_view(v)); + for (const p_string& v : data) { + packValue(std::string_view(v)); + } } template @@ -72,12 +78,14 @@ class MsgPackBuilder { return MsgPackBuilder(packer_, ObjType::TypeObjectArray, size); } } - void Array(int tagName, Serializer &ser, TagType, int count); + void Array(int tagName, Serializer& ser, TagType, int count); template MsgPackBuilder Object(T tagName, int size = KUnknownFieldSize) { packKeyName(tagName); - if (isArray()) skipTag(); + if (isArray()) { + skipTag(); + } if (size == KUnknownFieldSize) { assertrx(tagsLengths_ && tagIndex_); return MsgPackBuilder(packer_, tagsLengths_, tagIndex_, ObjType::TypeObject, tm_); @@ -87,7 +95,7 @@ class MsgPackBuilder { } template - MsgPackBuilder &Null(T tagName) { + MsgPackBuilder& Null(T tagName) { skipTag(); packKeyName(tagName); packNil(); @@ -95,28 +103,38 @@ class MsgPackBuilder { } template - MsgPackBuilder &Put(N tagName, const T &arg, int /*offset*/ = 0) { - if (isArray()) skipTag(); + MsgPackBuilder& Put(N tagName, const T& arg, int /*offset*/ = 0) { + if (isArray()) { + skipTag(); + } skipTag(); packKeyName(tagName); packValue(arg); - if (isArray()) skipTag(); + if (isArray()) { + skipTag(); + } return *this; } template - MsgPackBuilder &Put(N tagName, Uuid arg) { - if (isArray()) skipTag(); + MsgPackBuilder& Put(N tagName, Uuid arg) { + if (isArray()) { + skipTag(); + } skipTag(); packKeyName(tagName); packValue(arg); - if (isArray()) skipTag(); + if (isArray()) { + skipTag(); + } return *this; } template - MsgPackBuilder &Put(T tagName, const Variant &kv, int offset = 0) { - if (isArray()) skipTag(); + MsgPackBuilder& Put(T tagName, const Variant& kv, int offset = 0) { + if (isArray()) { + skipTag(); + } skipTag(); packKeyName(tagName); kv.Type().EvaluateOneOf( @@ -125,22 +143,24 @@ class MsgPackBuilder { [&](KeyValueType::Null) { packNil(); }, [&](KeyValueType::Bool) { packValue(bool(kv)); }, [&](KeyValueType::Tuple) { auto arrNode = Array(tagName); - for (auto &val : kv.getCompositeValues()) { + for (auto& val : kv.getCompositeValues()) { arrNode.Put(0, val, offset); } }, [&](KeyValueType::Uuid) { packValue(Uuid{kv}); }, [](OneOf) noexcept {}); - if (isArray()) skipTag(); + if (isArray()) { + skipTag(); + } return *this; } - MsgPackBuilder &Json(std::string_view name, std::string_view arg); + MsgPackBuilder& Json(std::string_view name, std::string_view arg); - MsgPackBuilder &End(); + MsgPackBuilder& End(); private: void init(int size); - void packCJsonValue(TagType, Serializer &); + void packCJsonValue(TagType, Serializer&); void packNil() { msgpack_pack_nil(&packer_); } void packMap(size_t size) { msgpack_pack_map(&packer_, size); } @@ -171,15 +191,21 @@ class MsgPackBuilder { void checkIfCorrectArray(std::string_view) const {} void checkIfCorrectArray(int tagName) const { - if (tagName == 0) throw Error(errLogic, "Arrays of arrays are not supported in cjson"); + if (tagName == 0) { + throw Error(errLogic, "Arrays of arrays are not supported in cjson"); + } } void packKeyName(std::nullptr_t) {} void packKeyName(std::string_view name) { - if (!name.empty() && !isArray()) packValue(name); + if (!name.empty() && !isArray()) { + packValue(name); + } } void packKeyName(int tagName) { - if (tagName != 0 && !isArray()) packValue(tm_->tag2name(tagName)); + if (tagName != 0 && !isArray()) { + packValue(tm_->tag2name(tagName)); + } } int getTagSize() { @@ -190,7 +216,9 @@ class MsgPackBuilder { } void skipTag() { - if (tagsLengths_) ++(*tagIndex_); + if (tagsLengths_) { + ++(*tagIndex_); + } } void skipTagIfEqual(TagValues tagVal) { @@ -199,13 +227,13 @@ class MsgPackBuilder { } } - void appendJsonObject(std::string_view name, const gason::JsonNode &obj); + void appendJsonObject(std::string_view name, const gason::JsonNode& obj); - const TagsMatcher *tm_; + const TagsMatcher* tm_; msgpack_packer packer_; - const TagsLengths *tagsLengths_; + const TagsLengths* tagsLengths_; ObjType type_; - int *tagIndex_; + int* tagIndex_; }; } // namespace reindexer diff --git a/cpp_src/core/cjson/msgpackdecoder.cc b/cpp_src/core/cjson/msgpackdecoder.cc index 965fd2694..e08e55ab5 100644 --- a/cpp_src/core/cjson/msgpackdecoder.cc +++ b/cpp_src/core/cjson/msgpackdecoder.cc @@ -47,11 +47,13 @@ int MsgPackDecoder::decodeKeyToTag(const msgpack_object_kv& obj) { case MSGPACK_OBJECT_EXT: break; } - throw Error(errParams, "Unsupported MsgPack map key type: %s(%d)", ToString(obj.key.type), obj.key.type); + throw Error(errParams, "Unsupported MsgPack map key type: %s(%d)", ToString(obj.key.type), int(obj.key.type)); } void MsgPackDecoder::decode(Payload& pl, CJsonBuilder& builder, const msgpack_object& obj, int tagName) { - if (tagName) tagsPath_.emplace_back(tagName); + if (tagName) { + tagsPath_.emplace_back(tagName); + } switch (obj.type) { case MSGPACK_OBJECT_NIL: builder.Null(tagName); @@ -116,9 +118,11 @@ void MsgPackDecoder::decode(Payload& pl, CJsonBuilder& builder, const msgpack_ob case MSGPACK_OBJECT_BIN: case MSGPACK_OBJECT_EXT: default: - throw Error(errParams, "Unsupported MsgPack type: %s(%d)", ToString(obj.type), obj.type); + throw Error(errParams, "Unsupported MsgPack type: %s(%d)", ToString(obj.type), int(obj.type)); + } + if (tagName) { + tagsPath_.pop_back(); } - if (tagName) tagsPath_.pop_back(); } Error MsgPackDecoder::Decode(std::string_view buf, Payload& pl, WrSerializer& wrser, size_t& offset) { @@ -127,11 +131,13 @@ Error MsgPackDecoder::Decode(std::string_view buf, Payload& pl, WrSerializer& wr tagsPath_.clear(); size_t baseOffset = offset; MsgPackValue data = parser_.Parse(buf, offset); - if rx_unlikely (!data.p) return Error(errLogic, "Error unpacking msgpack data"); + if rx_unlikely (!data.p) { + return Error(errLogic, "Error unpacking msgpack data"); + } if rx_unlikely (data.p->type != MSGPACK_OBJECT_MAP) { std::string_view slice = buf.substr(baseOffset, 16); return Error(errNotValid, "Unexpected MsgPack value. Expected %s, but got %s(%d) at %d(~>\"%s\"...)", - ToString(MSGPACK_OBJECT_MAP), ToString(data.p->type), data.p->type, baseOffset, slice); + ToString(MSGPACK_OBJECT_MAP), ToString(data.p->type), int(data.p->type), baseOffset, slice); } CJsonBuilder cjsonBuilder(wrser, ObjType::TypePlain, &tm_, 0); diff --git a/cpp_src/core/cjson/protobufbuilder.h b/cpp_src/core/cjson/protobufbuilder.h index 22ac1e7c0..513d7bf1c 100644 --- a/cpp_src/core/cjson/protobufbuilder.h +++ b/cpp_src/core/cjson/protobufbuilder.h @@ -107,10 +107,14 @@ class ProtobufBuilder { void Array(int fieldIdx, Serializer& rdser, TagType tagType, int count) { if (tagType == TAG_VARINT || tagType == TAG_DOUBLE || tagType == TAG_BOOL) { auto array = ArrayPacked(fieldIdx); - while (count--) packItem(fieldIdx, tagType, rdser, array); + while (count--) { + packItem(fieldIdx, tagType, rdser, array); + } } else { auto array = ArrayNotPacked(fieldIdx); - while (count--) packItem(fieldIdx, tagType, rdser, array); + while (count--) { + packItem(fieldIdx, tagType, rdser, array); + } } } diff --git a/cpp_src/core/cjson/protobufschemabuilder.cc b/cpp_src/core/cjson/protobufschemabuilder.cc index 068f0db29..c6ca06c31 100644 --- a/cpp_src/core/cjson/protobufschemabuilder.cc +++ b/cpp_src/core/cjson/protobufschemabuilder.cc @@ -13,12 +13,20 @@ ProtobufSchemaBuilder::ProtobufSchemaBuilder(WrSerializer* ser, SchemaFieldsType : ser_(ser), fieldsTypes_(fieldsTypes), pt_(pt), tm_(tm), type_(type) { switch (type_) { case ObjType::TypePlain: - if (ser_) ser_->Write("syntax = \"proto3\";\n\n"); + if (ser_) { + ser_->Write("syntax = \"proto3\";\n\n"); + } break; case ObjType::TypeObject: - if (ser_) ser_->Write("message "); - if (ser_) ser_->Write(name); - if (ser_) ser_->Write(" {\n"); + if (ser_) { + ser_->Write("message "); + } + if (ser_) { + ser_->Write(name); + } + if (ser_) { + ser_->Write(" {\n"); + } break; case ObjType::TypeObjectArray: case ObjType::TypeArray: @@ -62,7 +70,9 @@ void ProtobufSchemaBuilder::End() { if (fieldsTypes_->tagsPath_.size() > 0) { fieldsTypes_->tagsPath_.pop_back(); } - if (ser_) ser_->Write("}\n"); + if (ser_) { + ser_->Write("}\n"); + } } type_ = ObjType::TypePlain; } @@ -75,11 +85,15 @@ void ProtobufSchemaBuilder::Field(std::string_view name, int tagName, const Fiel } if (props.isArray) { assertrx(type_ != ObjType::TypeArray && type_ != ObjType::TypeObjectArray); - if (ser_) ser_->Write("repeated "); + if (ser_) { + ser_->Write("repeated "); + } writeField(name, typeName, tagName); type.EvaluateOneOf( [&](OneOf) { - if (ser_) ser_->Write(" [packed=true]"); + if (ser_) { + ser_->Write(" [packed=true]"); + } }, [](OneOf) noexcept {}); @@ -87,7 +101,9 @@ void ProtobufSchemaBuilder::Field(std::string_view name, int tagName, const Fiel writeField(name, typeName, tagName); } fieldsTypes_->AddField(type, props.isArray); - if (ser_) ser_->Write(";\n"); + if (ser_) { + ser_->Write(";\n"); + } } ProtobufSchemaBuilder ProtobufSchemaBuilder::Object(int tagName, std::string_view name, bool buildTypesOnly, diff --git a/cpp_src/core/cjson/tagslengths.cc b/cpp_src/core/cjson/tagslengths.cc index 0e59459de..7ed567376 100644 --- a/cpp_src/core/cjson/tagslengths.cc +++ b/cpp_src/core/cjson/tagslengths.cc @@ -10,7 +10,9 @@ int computeObjectLength(TagsLengths& tagsLengths, std::size_t startTag, std::siz if (tagsLengths[i] == TagValues::StartObject) { std::size_t pos; tagsLengths[i] = computeObjectLength(tagsLengths, i + 1, pos); - if (!arrayItem) ++objectLength; + if (!arrayItem) { + ++objectLength; + } i = pos; } else if (tagsLengths[i] == TagValues::EndObject) { ++i; @@ -22,7 +24,9 @@ int computeObjectLength(TagsLengths& tagsLengths, std::size_t startTag, std::siz arrayItem = false; ++i; } else { - if (!arrayItem) ++objectLength; + if (!arrayItem) { + ++objectLength; + } ++i; } } diff --git a/cpp_src/core/cjson/tagsmatcher.h b/cpp_src/core/cjson/tagsmatcher.h index a69a31e71..2b7355206 100644 --- a/cpp_src/core/cjson/tagsmatcher.h +++ b/cpp_src/core/cjson/tagsmatcher.h @@ -16,7 +16,9 @@ class TagsMatcher { int name2tag(std::string_view name) const { return impl_->name2tag(name); } int name2tag(std::string_view name, bool canAdd) { - if (!name.data()) return 0; // -V547 + if (!name.data()) { + return 0; // -V547 + } int res = impl_->name2tag(name); return res ? res : impl_.clone()->name2tag(name, canAdd, updated_); } @@ -24,7 +26,9 @@ class TagsMatcher { const std::string& tag2name(int tag) const { return impl_->tag2name(tag); } TagsPath path2tag(std::string_view jsonPath) const { return impl_->path2tag(jsonPath); } TagsPath path2tag(std::string_view jsonPath, bool canAdd) { - if (jsonPath.empty()) return TagsPath(); + if (jsonPath.empty()) { + return TagsPath(); + } auto res = path2tag(jsonPath); return res.empty() && canAdd ? impl_.clone()->path2tag(jsonPath, canAdd, updated_) : res; } @@ -34,7 +38,9 @@ class TagsMatcher { return tagsPath; } IndexedTagsPath path2indexedtag(std::string_view jsonPath, bool canAdd) { - if (jsonPath.empty()) return IndexedTagsPath(); + if (jsonPath.empty()) { + return IndexedTagsPath(); + } auto res = impl_->path2indexedtag(jsonPath); return res.empty() && canAdd ? impl_.clone()->path2indexedtag(jsonPath, canAdd, updated_) : res; } diff --git a/cpp_src/core/cjson/tagsmatcherimpl.h b/cpp_src/core/cjson/tagsmatcherimpl.h index c23c757e3..31c875b29 100644 --- a/cpp_src/core/cjson/tagsmatcherimpl.h +++ b/cpp_src/core/cjson/tagsmatcherimpl.h @@ -18,7 +18,7 @@ namespace reindexer { class TagsMatcherImpl { public: TagsMatcherImpl() : version_(0), stateToken_(tools::RandomGenerator::gets32()) {} - TagsMatcherImpl(PayloadType &&payloadType) : version_(0), stateToken_(tools::RandomGenerator::gets32()) { + TagsMatcherImpl(PayloadType&& payloadType) : version_(0), stateToken_(tools::RandomGenerator::gets32()) { bool updated = false; updatePayloadType(std::move(payloadType), updated, false); (void)updated; // No update check required @@ -26,10 +26,10 @@ class TagsMatcherImpl { TagsPath path2tag(std::string_view jsonPath) const { bool updated = false; - return const_cast(this)->path2tag(jsonPath, false, updated); + return const_cast(this)->path2tag(jsonPath, false, updated); } - TagsPath path2tag(std::string_view jsonPath, bool canAdd, bool &updated) { + TagsPath path2tag(std::string_view jsonPath, bool canAdd, bool& updated) { TagsPath fieldTags; for (size_t pos = 0, lastPos = 0; pos != jsonPath.length(); lastPos = pos + 1) { pos = jsonPath.find('.', lastPos); @@ -51,10 +51,10 @@ class TagsMatcherImpl { IndexedTagsPath path2indexedtag(std::string_view jsonPath) const { bool updated = false; - return const_cast(this)->path2indexedtag(jsonPath, false, updated); + return const_cast(this)->path2indexedtag(jsonPath, false, updated); } - IndexedTagsPath path2indexedtag(std::string_view jsonPath, bool canAdd, bool &updated) { + IndexedTagsPath path2indexedtag(std::string_view jsonPath, bool canAdd, bool& updated) { using namespace std::string_view_literals; IndexedTagsPath fieldTags; for (size_t pos = 0, lastPos = 0; pos != jsonPath.length(); lastPos = pos + 1) { @@ -105,9 +105,11 @@ class TagsMatcherImpl { return (res == names2tags_.end()) ? 0 : res->second + 1; } - int name2tag(std::string_view n, bool canAdd, bool &updated) { + int name2tag(std::string_view n, bool canAdd, bool& updated) { int tag = name2tag(n); - if (tag || !canAdd) return tag; + if (tag || !canAdd) { + return tag; + } std::string name(n); validateTagSize(tags2names_.size() + 1); @@ -120,10 +122,12 @@ class TagsMatcherImpl { return res.first->second + 1; } - const std::string &tag2name(uint32_t tag) const { + const std::string& tag2name(uint32_t tag) const { static std::string emptystr; tag &= ctag::kNameMask; - if (tag == 0) return emptystr; + if (tag == 0) { + return emptystr; + } if (tag - 1 >= tags2names_.size()) { throw Error(errTagsMissmatch, "Unknown tag %d in cjson", tag); @@ -132,27 +136,33 @@ class TagsMatcherImpl { return tags2names_[tag - 1]; } - int tags2field(const int16_t *path, size_t pathLen) const noexcept { - if (!pathLen) return -1; + int tags2field(const int16_t* path, size_t pathLen) const noexcept { + if (!pathLen) { + return -1; + } return pathCache_.lookup(path, pathLen); } - void buildTagsCache(bool &updated) { - if (!payloadType_) return; + void buildTagsCache(bool& updated) { + if (!payloadType_) { + return; + } pathCache_.clear(); std::vector pathParts; std::vector pathIdx; for (int i = 1; i < payloadType_->NumFields(); i++) { - for (auto &jsonPath : payloadType_->Field(i).JsonPaths()) { - if (!jsonPath.length()) continue; + for (auto& jsonPath : payloadType_->Field(i).JsonPaths()) { + if (!jsonPath.length()) { + continue; + } pathIdx.clear(); - for (auto &name : split(jsonPath, ".", true, pathParts)) { + for (auto& name : split(jsonPath, ".", true, pathParts)) { pathIdx.emplace_back(name2tag(name, true, updated)); } pathCache_.set(pathIdx.data(), pathIdx.size(), i); } } } - void updatePayloadType(PayloadType payloadType, bool &updated, bool incVersion) { + void updatePayloadType(PayloadType payloadType, bool& updated, bool incVersion) { if (!payloadType && !payloadType_) { return; } @@ -162,8 +172,8 @@ class TagsMatcherImpl { newType = newType || bool(payloadType) != bool(payloadType_) || (payloadType_.NumFields() != payloadType.NumFields()); if (!newType) { for (int field = 1, fields = payloadType_.NumFields(); field < fields; ++field) { - auto &lf = payloadType_.Field(field); - auto &rf = payloadType.Field(field); + auto& lf = payloadType_.Field(field); + auto& rf = payloadType.Field(field); if (!lf.Type().IsSame(rf.Type()) || lf.IsArray() != rf.IsArray() || lf.JsonPaths() != rf.JsonPaths()) { newType = true; break; @@ -174,12 +184,14 @@ class TagsMatcherImpl { version_ += int(newType && incVersion); } - void serialize(WrSerializer &ser) const { + void serialize(WrSerializer& ser) const { ser.PutVarUint(tags2names_.size()); - for (size_t tag = 0; tag < tags2names_.size(); ++tag) ser.PutVString(tags2names_[tag]); + for (size_t tag = 0; tag < tags2names_.size(); ++tag) { + ser.PutVString(tags2names_[tag]); + } } - void deserialize(Serializer &ser) { + void deserialize(Serializer& ser) { clear(); size_t cnt = ser.GetVarUint(); validateTagSize(cnt); @@ -191,13 +203,13 @@ class TagsMatcherImpl { } // assert(ser.Eof()); } - void deserialize(Serializer &ser, int version, int stateToken) { + void deserialize(Serializer& ser, int version, int stateToken) { deserialize(ser); version_ = version; stateToken_ = stateToken; } - bool merge(const TagsMatcherImpl &tm, bool &updated) { + bool merge(const TagsMatcherImpl& tm, bool& updated) { if (tm.contains(*this)) { auto oldSz = size(); auto newSz = tm.names2tags_.size(); @@ -222,7 +234,7 @@ class TagsMatcherImpl { } return contains(tm); } - bool contains(const TagsMatcherImpl &tm) const noexcept { + bool contains(const TagsMatcherImpl& tm) const noexcept { return tags2names_.size() >= tm.tags2names_.size() && std::equal(tm.tags2names_.begin(), tm.tags2names_.end(), tags2names_.begin()); } @@ -260,7 +272,9 @@ class TagsMatcherImpl { int16_t path[256]; pathCache_.walk(path, 0, [&path, &res, this](int depth, int field) { for (int i = 0; i < depth; i++) { - if (i) res += "."; + if (i) { + res += "."; + } res += tag2name(path[i]) + "(" + std::to_string(path[i]) + ")"; } res += ":" + payloadType_->Field(field).Name() + "(" + std::to_string(field) + ") "; diff --git a/cpp_src/core/cjson/tagspath.h b/cpp_src/core/cjson/tagspath.h index 390c2d9db..116a423bf 100644 --- a/cpp_src/core/cjson/tagspath.h +++ b/cpp_src/core/cjson/tagspath.h @@ -22,15 +22,21 @@ class IndexedPathNode { IndexedPathNode(AllItemsType) noexcept : index_{ForAllItems} {} IndexedPathNode(int16_t _nameTag) noexcept : nameTag_(_nameTag) {} IndexedPathNode(int16_t _nameTag, int32_t _index) noexcept : nameTag_(_nameTag), index_(_index) {} - bool operator==(const IndexedPathNode &obj) const noexcept { - if (nameTag_ != obj.nameTag_) return false; - if (IsForAllItems() || obj.IsForAllItems()) return true; + bool operator==(const IndexedPathNode& obj) const noexcept { + if (nameTag_ != obj.nameTag_) { + return false; + } + if (IsForAllItems() || obj.IsForAllItems()) { + return true; + } if (index_ != IndexValueType::NotSet && obj.index_ != IndexValueType::NotSet) { - if (index_ != obj.index_) return false; + if (index_ != obj.index_) { + return false; + } } return true; } - bool operator!=(const IndexedPathNode &obj) const noexcept { return !(operator==(obj)); } + bool operator!=(const IndexedPathNode& obj) const noexcept { return !(operator==(obj)); } bool operator==(int16_t _nameTag) const noexcept { return _nameTag == nameTag_; } bool operator!=(int16_t _nameTag) const noexcept { return _nameTag != nameTag_; } explicit operator int() const noexcept { return nameTag_; } @@ -80,48 +86,64 @@ class IndexedTagsPathImpl : public h_vector { public: using Base = h_vector; using Base::Base; - explicit IndexedTagsPathImpl(const TagsPath &tp) { + explicit IndexedTagsPathImpl(const TagsPath& tp) { this->reserve(tp.size()); - for (auto t : tp) this->emplace_back(t); + for (auto t : tp) { + this->emplace_back(t); + } } template - bool Compare(const IndexedTagsPathImpl &obj) const noexcept { + bool Compare(const IndexedTagsPathImpl& obj) const noexcept { const size_t ourSize = this->size(); - if (obj.size() != ourSize) return false; - if (this->back().IsArrayNode() != obj.back().IsArrayNode()) return false; + if (obj.size() != ourSize) { + return false; + } + if (this->back().IsArrayNode() != obj.back().IsArrayNode()) { + return false; + } for (size_t i = 0; i < ourSize; ++i) { - const auto &ourNode = this->operator[](i); + const auto& ourNode = this->operator[](i); if (i == ourSize - 1) { if (ourNode.IsArrayNode()) { - if (ourNode.NameTag() != obj[i].NameTag()) return false; - if (ourNode.IsForAllItems() || obj[i].IsForAllItems()) break; + if (ourNode.NameTag() != obj[i].NameTag()) { + return false; + } + if (ourNode.IsForAllItems() || obj[i].IsForAllItems()) { + break; + } return (ourNode.Index() == obj[i].Index()); } else { return (ourNode.NameTag() == obj[i].NameTag()); } } else { - if (ourNode != obj[i]) return false; + if (ourNode != obj[i]) { + return false; + } } } return true; } - bool Compare(const TagsPath &obj) const noexcept { + bool Compare(const TagsPath& obj) const noexcept { const auto sz = this->size(); if (obj.size() != sz) { return false; } for (size_t i = 0; i < sz; ++i) { - if ((*this)[i].NameTag() != obj[i]) return false; + if ((*this)[i].NameTag() != obj[i]) { + return false; + } } return true; } - bool IsNestedOrEqualTo(const TagsPath &obj) const noexcept { + bool IsNestedOrEqualTo(const TagsPath& obj) const noexcept { const auto sz = this->size(); if (sz > obj.size()) { return false; } for (size_t i = 0; i < sz; ++i) { - if ((*this)[i].NameTag() != obj[i]) return false; + if ((*this)[i].NameTag() != obj[i]) { + return false; + } } return true; } @@ -131,20 +153,26 @@ using IndexedTagsPath = IndexedTagsPathImpl<6>; template class TagsPathScope { public: - TagsPathScope(TagsPath &tagsPath, int16_t tagName) : tagsPath_(tagsPath), tagName_(tagName) { - if (tagName_) tagsPath_.emplace_back(tagName); + TagsPathScope(TagsPath& tagsPath, int16_t tagName) : tagsPath_(tagsPath), tagName_(tagName) { + if (tagName_) { + tagsPath_.emplace_back(tagName); + } } - TagsPathScope(TagsPath &tagsPath, int16_t tagName, int32_t index) : tagsPath_(tagsPath), tagName_(tagName) { - if (tagName_) tagsPath_.emplace_back(tagName, index); + TagsPathScope(TagsPath& tagsPath, int16_t tagName, int32_t index) : tagsPath_(tagsPath), tagName_(tagName) { + if (tagName_) { + tagsPath_.emplace_back(tagName, index); + } } ~TagsPathScope() { - if (tagName_ && !tagsPath_.empty()) tagsPath_.pop_back(); + if (tagName_ && !tagsPath_.empty()) { + tagsPath_.pop_back(); + } } - TagsPathScope(const TagsPathScope &) = delete; - TagsPathScope &operator=(const TagsPathScope &) = delete; + TagsPathScope(const TagsPathScope&) = delete; + TagsPathScope& operator=(const TagsPathScope&) = delete; private: - TagsPath &tagsPath_; + TagsPath& tagsPath_; const int16_t tagName_; }; @@ -154,7 +182,7 @@ namespace std { template <> struct hash { public: - size_t operator()(const reindexer::TagsPath &v) const noexcept { + size_t operator()(const reindexer::TagsPath& v) const noexcept { return reindexer::_Hash_bytes(v.data(), v.size() * sizeof(typename reindexer::TagsPath::value_type)); } }; diff --git a/cpp_src/core/cjson/tagspathcache.h b/cpp_src/core/cjson/tagspathcache.h index dd94eef35..e759f962b 100644 --- a/cpp_src/core/cjson/tagspathcache.h +++ b/cpp_src/core/cjson/tagspathcache.h @@ -10,7 +10,7 @@ namespace reindexer { class TagsPathCache { public: - void set(const int16_t *tagsPath, size_t len, int field) { + void set(const int16_t* tagsPath, size_t len, int field) { assertrx(len); auto cache = this; for (;;) { @@ -30,7 +30,7 @@ class TagsPathCache { len--; } } - int lookup(const int16_t *tagsPath, size_t len) const noexcept { + int lookup(const int16_t* tagsPath, size_t len) const noexcept { assertrx(len); auto cache = this; for (;;) { @@ -50,11 +50,15 @@ class TagsPathCache { } } - void walk(int16_t *path, int depth, const std::function &visitor) const { - int16_t &i = path[depth]; + void walk(int16_t* path, int depth, const std::function& visitor) const { + int16_t& i = path[depth]; for (i = 0; i < int(entries_.size()); i++) { - if (entries_[i].field_ > 0) visitor(depth + 1, entries_[i].field_); - if (entries_[i].subCache_) entries_[i].subCache_->walk(path, depth + 1, visitor); + if (entries_[i].field_ > 0) { + visitor(depth + 1, entries_[i].field_); + } + if (entries_[i].subCache_) { + entries_[i].subCache_->walk(path, depth + 1, visitor); + } } } diff --git a/cpp_src/core/cjson/uuid_recoders.h b/cpp_src/core/cjson/uuid_recoders.h index c74af8e48..cdc264ac3 100644 --- a/cpp_src/core/cjson/uuid_recoders.h +++ b/cpp_src/core/cjson/uuid_recoders.h @@ -17,11 +17,11 @@ class RecoderUuidToString : public Recoder { return TAG_STRING; } } - void Recode(Serializer &, WrSerializer &) const override final; - void Recode(Serializer &, Payload &, int, WrSerializer &) override final { assertrx(false); } + void Recode(Serializer&, WrSerializer&) const override final; + void Recode(Serializer&, Payload&, int, WrSerializer&) override final { assertrx(false); } [[nodiscard]] bool Match(int) noexcept override final { return false; } - [[nodiscard]] bool Match(TagType, const TagsPath &tp) noexcept override final { return tagsPath_ == tp; } - void Serialize(WrSerializer &) override final {} + [[nodiscard]] bool Match(TagType, const TagsPath& tp) noexcept override final { return tagsPath_ == tp; } + void Serialize(WrSerializer&) override final {} bool Reset() override final { return false; } private: @@ -29,12 +29,12 @@ class RecoderUuidToString : public Recoder { }; template <> -inline void RecoderUuidToString::Recode(Serializer &rdser, WrSerializer &wrser) const { +inline void RecoderUuidToString::Recode(Serializer& rdser, WrSerializer& wrser) const { wrser.PutStrUuid(rdser.GetUuid()); } template <> -inline void RecoderUuidToString::Recode(Serializer &rdser, WrSerializer &wrser) const { +inline void RecoderUuidToString::Recode(Serializer& rdser, WrSerializer& wrser) const { const carraytag atag = rdser.GetCArrayTag(); const auto count = atag.Count(); assertrx(atag.Type() == TAG_UUID); @@ -55,9 +55,9 @@ class RecoderStringToUuidArray : public Recoder { return TAG_ARRAY; } [[nodiscard]] bool Match(int f) noexcept override final { return f == field_; } - [[nodiscard]] bool Match(TagType, const TagsPath &) noexcept override final { return false; } - void Recode(Serializer &, WrSerializer &) const override final { assertrx(false); } - void Recode(Serializer &rdser, Payload &pl, int tagName, WrSerializer &wrser) override final { + [[nodiscard]] bool Match(TagType, const TagsPath&) noexcept override final { return false; } + void Recode(Serializer&, WrSerializer&) const override final { assertrx(false); } + void Recode(Serializer& rdser, Payload& pl, int tagName, WrSerializer& wrser) override final { if (fromNotArrayField_) { pl.Set(field_, Variant{rdser.GetStrUuid()}, true); wrser.PutCTag(ctag{TAG_ARRAY, tagName, field_}); @@ -78,7 +78,7 @@ class RecoderStringToUuidArray : public Recoder { wrser.PutVarUint(count); } } - void Serialize(WrSerializer &) override final {} + void Serialize(WrSerializer&) override final {} bool Reset() override final { return false; } private: @@ -99,13 +99,13 @@ class RecoderStringToUuid : public Recoder { return TAG_UUID; } [[nodiscard]] bool Match(int f) noexcept override final { return f == field_; } - [[nodiscard]] bool Match(TagType, const TagsPath &) noexcept override final { return false; } - void Recode(Serializer &, WrSerializer &) const override final { assertrx(false); } - void Recode(Serializer &rdser, Payload &pl, int tagName, WrSerializer &wrser) override final { + [[nodiscard]] bool Match(TagType, const TagsPath&) noexcept override final { return false; } + void Recode(Serializer&, WrSerializer&) const override final { assertrx(false); } + void Recode(Serializer& rdser, Payload& pl, int tagName, WrSerializer& wrser) override final { pl.Set(field_, Variant{rdser.GetStrUuid()}, true); wrser.PutCTag(ctag{TAG_UUID, tagName, field_}); } - void Serialize(WrSerializer &) override final {} + void Serialize(WrSerializer&) override final {} bool Reset() override final { return false; } private: diff --git a/cpp_src/core/dbconfig.cc b/cpp_src/core/dbconfig.cc index 447412b78..38dbdad5d 100644 --- a/cpp_src/core/dbconfig.cc +++ b/cpp_src/core/dbconfig.cc @@ -12,18 +12,24 @@ namespace reindexer { static CacheMode str2cacheMode(std::string_view mode) { using namespace std::string_view_literals; - if (mode == "on"sv) return CacheModeOn; - if (mode == "off"sv || mode == ""sv) return CacheModeOff; - if (mode == "aggressive"sv) return CacheModeAggressive; + if (mode == "on"sv) { + return CacheModeOn; + } + if (mode == "off"sv || mode == ""sv) { + return CacheModeOff; + } + if (mode == "aggressive"sv) { + return CacheModeAggressive; + } throw Error(errParams, "Unknown cache mode %s", mode); } -Error DBConfigProvider::FromJSON(const gason::JsonNode &root) { +Error DBConfigProvider::FromJSON(const gason::JsonNode& root) { try { smart_lock lk(mtx_, true); - auto &profilingNode = root["profiling"]; + auto& profilingNode = root["profiling"]; if (!profilingNode.empty()) { profilingData_ = ProfilingConfigData{}; profilingData_.queriesPerfStats = profilingNode["queriesperfstats"].As(); @@ -45,13 +51,15 @@ Error DBConfigProvider::FromJSON(const gason::JsonNode &root) { transactionNode["avg_step_threshold_us"].As()}); } } - if (handlers_[ProfilingConf]) (handlers_[ProfilingConf])(); + if (handlers_[ProfilingConf]) { + (handlers_[ProfilingConf])(); + } } - auto &namespacesNode = root["namespaces"]; + auto& namespacesNode = root["namespaces"]; if (!namespacesNode.empty()) { namespacesData_.clear(); - for (auto &nsNode : namespacesNode) { + for (auto& nsNode : namespacesNode) { NamespaceConfigData data; data.lazyLoad = nsNode["lazyload"].As(); data.noQueryIdleThreshold = nsNode["unload_idle_threshold"].As(); @@ -96,20 +104,26 @@ Error DBConfigProvider::FromJSON(const gason::JsonNode &root) { namespacesData_.emplace(nsNode["namespace"].As(), std::move(data)); // NOLINT(performance-move-const-arg) } - if (handlers_[NamespaceDataConf]) (handlers_[NamespaceDataConf])(); + if (handlers_[NamespaceDataConf]) { + (handlers_[NamespaceDataConf])(); + } } - auto &replicationNode = root["replication"]; + auto& replicationNode = root["replication"]; if (!replicationNode.empty()) { auto err = replicationData_.FromJSON(replicationNode); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } - if (handlers_[ReplicationConf]) (handlers_[ReplicationConf])(); + if (handlers_[ReplicationConf]) { + (handlers_[ReplicationConf])(); + } } return errOK; - } catch (const Error &err) { + } catch (const Error& err) { return err; - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "DBConfigProvider: %s", ex.what()); } } @@ -124,7 +138,7 @@ ReplicationConfigData DBConfigProvider::GetReplicationConfig() { return replicationData_; } -bool DBConfigProvider::GetNamespaceConfig(std::string_view nsName, NamespaceConfigData &data) { +bool DBConfigProvider::GetNamespaceConfig(std::string_view nsName, NamespaceConfigData& data) { shared_lock lk(mtx_); auto it = namespacesData_.find(nsName); if (it == namespacesData_.end()) { @@ -138,7 +152,7 @@ bool DBConfigProvider::GetNamespaceConfig(std::string_view nsName, NamespaceConf return true; } -Error ReplicationConfigData::FromYML(const std::string &yaml) { +Error ReplicationConfigData::FromYML(const std::string& yaml) { try { YAML::Node root = YAML::Load(yaml); masterDSN = root["master_dsn"].as(masterDSN); @@ -156,18 +170,18 @@ Error ReplicationConfigData::FromYML(const std::string &yaml) { serverId = root["server_id"].as(serverId); auto node = root["namespaces"]; namespaces.clear(); - for (const auto &it : node) { + for (const auto& it : node) { namespaces.insert(it.as()); } return errOK; - } catch (const YAML::Exception &ex) { + } catch (const YAML::Exception& ex) { return Error(errParams, "yaml parsing error: '%s'", ex.what()); - } catch (const Error &err) { + } catch (const Error& err) { return err; } } -Error ReplicationConfigData::FromJSON(const gason::JsonNode &root) { +Error ReplicationConfigData::FromJSON(const gason::JsonNode& root) { try { masterDSN = root["master_dsn"].As(); appName = root["app_name"].As(std::move(appName)); @@ -183,21 +197,27 @@ Error ReplicationConfigData::FromJSON(const gason::JsonNode &root) { enableCompression = root["enable_compression"].As(enableCompression); serverId = root["server_id"].As(serverId); namespaces.clear(); - for (auto &objNode : root["namespaces"]) { + for (auto& objNode : root["namespaces"]) { namespaces.insert(objNode.As()); } - } catch (const Error &err) { + } catch (const Error& err) { return err; - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "ReplicationConfigData: %s", ex.what()); } return errOK; } -ReplicationRole ReplicationConfigData::str2role(const std::string &role) { - if (role == "master") return ReplicationMaster; - if (role == "slave") return ReplicationSlave; - if (role == "none") return ReplicationNone; +ReplicationRole ReplicationConfigData::str2role(const std::string& role) { + if (role == "master") { + return ReplicationMaster; + } + if (role == "slave") { + return ReplicationSlave; + } + if (role == "none") { + return ReplicationNone; + } throw Error(errParams, "Unknown replication role %s", role); } @@ -216,7 +236,7 @@ std::string ReplicationConfigData::role2str(ReplicationRole role) noexcept { } } -void ReplicationConfigData::GetJSON(JsonBuilder &jb) const { +void ReplicationConfigData::GetJSON(JsonBuilder& jb) const { jb.Put("role", role2str(role)); jb.Put("master_dsn", masterDSN); jb.Put("app_name", appName); @@ -230,14 +250,16 @@ void ReplicationConfigData::GetJSON(JsonBuilder &jb) const { jb.Put("server_id", serverId); { auto arrNode = jb.Array("namespaces"); - for (const auto &ns : namespaces) arrNode.Put(nullptr, ns); + for (const auto& ns : namespaces) { + arrNode.Put(nullptr, ns); + } } } -void ReplicationConfigData::GetYAML(WrSerializer &ser) const { +void ReplicationConfigData::GetYAML(WrSerializer& ser) const { YAML::Node nssYaml; nssYaml["namespaces"] = YAML::Node(YAML::NodeType::Sequence); - for (const auto &ns : namespaces) { + for (const auto& ns : namespaces) { nssYaml["namespaces"].push_back(ns); } // clang-format off diff --git a/cpp_src/core/dbconfig.h b/cpp_src/core/dbconfig.h index 643786014..903591342 100644 --- a/cpp_src/core/dbconfig.h +++ b/cpp_src/core/dbconfig.h @@ -48,7 +48,7 @@ class LongTxLoggingParams { class ProfilingConfigData { public: - ProfilingConfigData &operator=(const ProfilingConfigData &d) noexcept { + ProfilingConfigData& operator=(const ProfilingConfigData& d) noexcept { queriesThresholdUS.store(d.queriesThresholdUS, std::memory_order_relaxed); queriesPerfStats.store(d.queriesPerfStats, std::memory_order_relaxed); perfStats.store(d.perfStats, std::memory_order_relaxed); @@ -74,14 +74,14 @@ constexpr size_t kDefaultCacheSizeLimit = 1024 * 1024 * 128; constexpr uint32_t kDefaultHitCountToCache = 2; struct NamespaceCacheConfigData { - bool IsIndexesCacheEqual(const NamespaceCacheConfigData &o) noexcept { + bool IsIndexesCacheEqual(const NamespaceCacheConfigData& o) noexcept { return idxIdsetCacheSize == o.idxIdsetCacheSize && idxIdsetHitsToCache == o.idxIdsetHitsToCache && ftIdxCacheSize == o.ftIdxCacheSize && ftIdxHitsToCache == o.ftIdxHitsToCache; } - bool IsJoinCacheEqual(const NamespaceCacheConfigData &o) noexcept { + bool IsJoinCacheEqual(const NamespaceCacheConfigData& o) noexcept { return joinCacheSize == o.joinCacheSize && joinHitsToCache == o.joinHitsToCache; } - bool IsQueryCountCacheEqual(const NamespaceCacheConfigData &o) noexcept { + bool IsQueryCountCacheEqual(const NamespaceCacheConfigData& o) noexcept { return queryCountCacheSize == o.queryCountCacheSize && queryCountHitsToCache == o.queryCountHitsToCache; } @@ -117,12 +117,13 @@ struct NamespaceConfigData { }; enum ReplicationRole { ReplicationNone, ReplicationMaster, ReplicationSlave, ReplicationReadOnly }; +inline constexpr int format_as(ReplicationRole v) noexcept { return int(v); } struct ReplicationConfigData { - Error FromYML(const std::string &yml); - Error FromJSON(const gason::JsonNode &v); - void GetJSON(JsonBuilder &jb) const; - void GetYAML(WrSerializer &ser) const; + Error FromYML(const std::string& yml); + Error FromJSON(const gason::JsonNode& v); + void GetJSON(JsonBuilder& jb) const; + void GetYAML(WrSerializer& ser) const; ReplicationRole role = ReplicationNone; std::string masterDSN; @@ -139,7 +140,7 @@ struct ReplicationConfigData { bool enableCompression = true; int serverId = 0; - bool operator==(const ReplicationConfigData &rdata) const noexcept { + bool operator==(const ReplicationConfigData& rdata) const noexcept { return (role == rdata.role) && (connPoolSize == rdata.connPoolSize) && (workerThreads == rdata.workerThreads) && (clusterID == rdata.clusterID) && (forceSyncOnLogicError == rdata.forceSyncOnLogicError) && (forceSyncOnWrongDataHash == rdata.forceSyncOnWrongDataHash) && (masterDSN == rdata.masterDSN) && @@ -147,10 +148,10 @@ struct ReplicationConfigData { (timeoutSec == rdata.timeoutSec) && (namespaces == rdata.namespaces) && (enableCompression == rdata.enableCompression) && (serverId == rdata.serverId) && (appName == rdata.appName); } - bool operator!=(const ReplicationConfigData &rdata) const noexcept { return !operator==(rdata); } + bool operator!=(const ReplicationConfigData& rdata) const noexcept { return !operator==(rdata); } protected: - static ReplicationRole str2role(const std::string &); + static ReplicationRole str2role(const std::string&); static std::string role2str(ReplicationRole) noexcept; }; @@ -158,14 +159,14 @@ class DBConfigProvider { public: DBConfigProvider() = default; ~DBConfigProvider() = default; - DBConfigProvider(DBConfigProvider &obj) = delete; - DBConfigProvider &operator=(DBConfigProvider &obj) = delete; + DBConfigProvider(DBConfigProvider& obj) = delete; + DBConfigProvider& operator=(DBConfigProvider& obj) = delete; - Error FromJSON(const gason::JsonNode &root); + Error FromJSON(const gason::JsonNode& root); void setHandler(ConfigType cfgType, std::function handler); ReplicationConfigData GetReplicationConfig(); - bool GetNamespaceConfig(std::string_view nsName, NamespaceConfigData &data); + bool GetNamespaceConfig(std::string_view nsName, NamespaceConfigData& data); LongQueriesLoggingParams GetSelectLoggingParams() const noexcept { return profilingData_.longSelectLoggingParams.load(std::memory_order_relaxed); } diff --git a/cpp_src/core/expressiontree.h b/cpp_src/core/expressiontree.h index 8f578111c..5e3229a73 100644 --- a/cpp_src/core/expressiontree.h +++ b/cpp_src/core/expressiontree.h @@ -81,7 +81,7 @@ class ExpressionTree { } }; template - struct GetVisitor { + struct GetVisitor { RX_ALWAYS_INLINE const T& operator()(const T& v) const noexcept { return v; } template RX_ALWAYS_INLINE const T& operator()(const U&) const noexcept { @@ -560,20 +560,30 @@ class ExpressionTree { ExpressionTree& operator=(ExpressionTree&&) = default; ExpressionTree(const ExpressionTree& other) : activeBrackets_{other.activeBrackets_} { container_.reserve(other.container_.size()); - for (const Node& n : other.container_) container_.emplace_back(n.Copy()); + for (const Node& n : other.container_) { + container_.emplace_back(n.Copy()); + } } ExpressionTree& operator=(const ExpressionTree& other) { - if rx_unlikely (this == &other) return *this; + if rx_unlikely (this == &other) { + return *this; + } container_.clear(); container_.reserve(other.container_.size()); - for (const Node& n : other.container_) container_.emplace_back(n.Copy()); + for (const Node& n : other.container_) { + container_.emplace_back(n.Copy()); + } activeBrackets_ = other.activeBrackets_; return *this; } RX_ALWAYS_INLINE bool operator==(const ExpressionTree& other) const noexcept { - if (container_.size() != other.container_.size()) return false; + if (container_.size() != other.container_.size()) { + return false; + } for (size_t i = 0; i < container_.size(); ++i) { - if (container_[i] != other.container_[i]) return false; + if (container_[i] != other.container_[i]) { + return false; + } } return true; } @@ -589,10 +599,14 @@ class ExpressionTree { assertrx_dbg(pos < container_.size()); for (unsigned& b : activeBrackets_) { assertrx_dbg(b < container_.size()); - if (b >= pos) ++b; + if (b >= pos) { + ++b; + } } for (size_t i = 0; i < pos; ++i) { - if (container_[i].IsSubTree() && Next(i) > pos) container_[i].Append(); + if (container_[i].IsSubTree() && Next(i) > pos) { + container_[i].Append(); + } } container_.emplace(container_.begin() + pos, op, std::forward(v)); } @@ -605,10 +619,14 @@ class ExpressionTree { assertrx_throw(pos < container_.size()); for (unsigned& b : activeBrackets_) { assertrx_throw(b < container_.size()); - if (b >= pos) ++b; + if (b >= pos) { + ++b; + } } for (size_t i = 0; i < pos; ++i) { - if (container_[i].IsSubTree() && Next(i) > pos) container_[i].Append(); + if (container_[i].IsSubTree() && Next(i) > pos) { + container_[i].Append(); + } } container_.emplace(container_.begin() + pos, op, T(std::forward(args)...)); } @@ -618,10 +636,14 @@ class ExpressionTree { assertrx_dbg(pos < container_.size()); for (unsigned& b : activeBrackets_) { assertrx_dbg(b < container_.size()); - if (b > pos) ++b; + if (b > pos) { + ++b; + } } for (size_t i = 0; i < pos; ++i) { - if (container_[i].IsSubTree() && Next(i) > pos) container_[i].Append(); + if (container_[i].IsSubTree() && Next(i) > pos) { + container_[i].Append(); + } } container_.emplace(container_.begin() + pos + 1, op, std::forward(v)); } @@ -662,12 +684,16 @@ class ExpressionTree { /// Appends value as first child of the root template RX_ALWAYS_INLINE void AppendFront(OperationType op, T&& v) { - for (unsigned& i : activeBrackets_) ++i; + for (unsigned& i : activeBrackets_) { + ++i; + } container_.emplace(container_.begin(), op, std::forward(v)); } template RX_ALWAYS_INLINE void AppendFront(OperationType op, Args&&... args) { - for (unsigned& i : activeBrackets_) ++i; + for (unsigned& i : activeBrackets_) { + ++i; + } container_.emplace(container_.begin(), op, T{std::forward(args)...}); } void PopBack() { @@ -688,7 +714,9 @@ class ExpressionTree { assertrx_dbg(to <= container_.size()); for (unsigned& b : activeBrackets_) { assertrx_dbg(b < container_.size()); - if (b >= from) ++b; + if (b >= from) { + ++b; + } } for (size_t i = 0; i < from; ++i) { if (container_[i].IsSubTree()) { @@ -790,7 +818,9 @@ class ExpressionTree { std::remove_if(activeBrackets_.begin(), activeBrackets_.end(), [from, to](size_t b) { return b >= from && b < to; }), activeBrackets_.end()); for (auto& b : activeBrackets_) { - if (b >= to) b -= count; + if (b >= to) { + b -= count; + } } } template @@ -815,21 +845,29 @@ class ExpressionTree { } template RX_ALWAYS_INLINE void VisitForEach(const Visitor& visitor) const { - for (const Node& node : container_) node.visit(visitor); + for (const Node& node : container_) { + node.visit(visitor); + } } template RX_ALWAYS_INLINE void VisitForEach(const Visitor& visitor) { - for (Node& node : container_) node.visit(visitor); + for (Node& node : container_) { + node.visit(visitor); + } } template RX_ALWAYS_INLINE void VisitForEach(Fs&&... fs) const { overloaded visitor{std::forward(fs)...}; - for (const Node& node : container_) node.visit(visitor); + for (const Node& node : container_) { + node.visit(visitor); + } } template RX_ALWAYS_INLINE void VisitForEach(Fs&&... fs) { overloaded visitor{std::forward(fs)...}; - for (Node& node : container_) node.visit(visitor); + for (Node& node : container_) { + node.visit(visitor); + } } /// @class const_iterator @@ -906,16 +944,22 @@ class ExpressionTree { RX_ALWAYS_INLINE const_iterator cend() const noexcept { return {container_.end()}; } /// @return iterator to first entry of current bracket RX_ALWAYS_INLINE const_iterator begin_of_current_bracket() const noexcept { - if (activeBrackets_.empty()) return container_.cbegin(); + if (activeBrackets_.empty()) { + return container_.cbegin(); + } return container_.cbegin() + activeBrackets_.back() + 1; } RX_ALWAYS_INLINE const SubTree* LastOpenBracket() const { - if (activeBrackets_.empty()) return nullptr; + if (activeBrackets_.empty()) { + return nullptr; + } return &container_[activeBrackets_.back()].template Value(); } RX_ALWAYS_INLINE SubTree* LastOpenBracket() { - if (activeBrackets_.empty()) return nullptr; + if (activeBrackets_.empty()) { + return nullptr; + } return &container_[activeBrackets_.back()].template Value(); } /// @return the last appended leaf or last closed subtree or last openned subtree if it is empty @@ -924,9 +968,13 @@ class ExpressionTree { size_t start = 0; // start of last openned subtree; if (!activeBrackets_.empty()) { start = activeBrackets_.back() + 1; - if (start == container_.size()) return start - 1; // last oppened subtree is empty + if (start == container_.size()) { + return start - 1; // last oppened subtree is empty + } + } + while (Next(start) != container_.size()) { + start = Next(start); } - while (Next(start) != container_.size()) start = Next(start); return start; } diff --git a/cpp_src/core/formatters/jsonstring_fmt.h b/cpp_src/core/formatters/jsonstring_fmt.h new file mode 100644 index 000000000..29fba5d90 --- /dev/null +++ b/cpp_src/core/formatters/jsonstring_fmt.h @@ -0,0 +1,16 @@ +#pragma once + +#include "fmt/format.h" +#include "gason/gason.h" + +template <> +struct fmt::printf_formatter { + template + constexpr auto parse(ContextT& ctx) { + return ctx.begin(); + } + template + auto format(const gason::JsonString& s, ContextT& ctx) const { + return fmt::format_to(ctx.out(), "{}", std::string_view(s)); + } +}; diff --git a/cpp_src/core/formatters/key_string_fmt.h b/cpp_src/core/formatters/key_string_fmt.h new file mode 100644 index 000000000..37869b917 --- /dev/null +++ b/cpp_src/core/formatters/key_string_fmt.h @@ -0,0 +1,24 @@ +#pragma once + +#include "fmt/format.h" +#include "core/keyvalue/key_string.h" + +template <> +struct fmt::printf_formatter { + template + constexpr auto parse(ContextT& ctx) { + return ctx.begin(); + } + template + auto format(const reindexer::key_string& s, ContextT& ctx) const { + return s ? fmt::format_to(ctx.out(), "{}", std::string_view(*s)) : fmt::format_to(ctx.out(), ""); + } +}; + +template <> +struct fmt::formatter : public fmt::formatter { + template + auto format(const reindexer::key_string& s, ContextT& ctx) const { + return s ? fmt::formatter::format(std::string_view(*s), ctx) : fmt::format_to(ctx.out(), ""); + } +}; diff --git a/cpp_src/core/formatters/lsn_fmt.h b/cpp_src/core/formatters/lsn_fmt.h new file mode 100644 index 000000000..b7ec34a9a --- /dev/null +++ b/cpp_src/core/formatters/lsn_fmt.h @@ -0,0 +1,19 @@ +#pragma once + +#include "core/lsn.h" +#include "fmt/format.h" + +template <> +struct fmt::printf_formatter { + template + constexpr auto parse(ContextT& ctx) { + return ctx.begin(); + } + template + auto format(const reindexer::lsn_t& lsn, ContextT& ctx) const { + return fmt::format_to(ctx.out(), "{}:{}", lsn.Server(), lsn.Counter()); + } +}; + +template <> +struct fmt::formatter : public fmt::printf_formatter {}; diff --git a/cpp_src/core/formatters/uuid_fmt.h b/cpp_src/core/formatters/uuid_fmt.h new file mode 100644 index 000000000..e77ec886b --- /dev/null +++ b/cpp_src/core/formatters/uuid_fmt.h @@ -0,0 +1,24 @@ +#pragma once + +#include "fmt/format.h" +#include "core/keyvalue/uuid.h" + +template <> +struct fmt::printf_formatter { + template + constexpr auto parse(ContextT& ctx) { + return ctx.begin(); + } + template + auto format(const reindexer::Uuid& uuid, ContextT& ctx) const { + return fmt::format_to(ctx.out(), "'{}'", std::string(uuid)); + } +}; + +template <> +struct fmt::formatter : public fmt::formatter { + template + auto format(const reindexer::Uuid& uuid, ContextT& ctx) const { + return fmt::formatter::format(std::string(uuid), ctx); + } +}; diff --git a/cpp_src/core/ft/areaholder.h b/cpp_src/core/ft/areaholder.h index adbd06444..53bac35b1 100644 --- a/cpp_src/core/ft/areaholder.h +++ b/cpp_src/core/ft/areaholder.h @@ -16,10 +16,14 @@ struct Area { [[nodiscard]] bool inline IsIn(int pos) noexcept { return pos <= end && pos >= start; } - [[nodiscard]] bool inline Concat(const Area &rhs) noexcept { + [[nodiscard]] bool inline Concat(const Area& rhs) noexcept { if (IsIn(rhs.start) || IsIn(rhs.end) || (start > rhs.start && end < rhs.end)) { - if (start > rhs.start) start = rhs.start; - if (end < rhs.end) end = rhs.end; + if (start > rhs.start) { + start = rhs.start; + } + if (end < rhs.end) { + end = rhs.end; + } return true; } return false; @@ -39,7 +43,7 @@ class AreaBuffer { void Commit() { if (!data_.empty()) { boost::sort::pdqsort_branchless(data_.begin(), data_.end(), - [](const Area &rhs, const Area &lhs) noexcept { return rhs.start < lhs.start; }); + [](const Area& rhs, const Area& lhs) noexcept { return rhs.start < lhs.start; }); for (auto vit = data_.begin() + 1; vit != data_.end(); ++vit) { auto prev = vit - 1; if (vit->Concat(*prev)) { @@ -48,7 +52,7 @@ class AreaBuffer { } } } - [[nodiscard]] bool Insert(Area &&area, float termRank, int maxAreasInDoc, float maxTermRank) { + [[nodiscard]] bool Insert(Area&& area, float termRank, int maxAreasInDoc, float maxTermRank) { if (!data_.empty() && data_.back().Concat(area)) { return true; } else { @@ -67,8 +71,8 @@ class AreaBuffer { return false; } - [[nodiscard]] const RVector &GetData() const noexcept { return data_; } - void MoveAreas(AreaHolder &to, int field, int32_t rank, int maxAreasInDoc); + [[nodiscard]] const RVector& GetData() const noexcept { return data_; } + void MoveAreas(AreaHolder& to, int field, int32_t rank, int maxAreasInDoc); private: RVector data_; @@ -82,12 +86,12 @@ class AreaHolder { AreaHolder() = default; ~AreaHolder() = default; - AreaHolder(AreaHolder &&) = default; + AreaHolder(AreaHolder&&) = default; void Reserve(int size) { areas_.reserve(size); } void ReserveField(int size) { areas_.resize(size); } void Commit() { commited_ = true; - for (auto &area : areas_) { + for (auto& area : areas_) { area.Commit(); } } @@ -99,23 +103,27 @@ class AreaHolder { maxTermRank_ = rank; } } - [[nodiscard]] AreaBuffer *GetAreas(int field) { - if (!commited_) Commit(); + [[nodiscard]] AreaBuffer* GetAreas(int field) { + if (!commited_) { + Commit(); + } return (areas_.size() <= size_t(field)) ? nullptr : &areas_[field]; } - [[nodiscard]] AreaBuffer *GetAreasRaw(int field) noexcept { return (areas_.size() <= size_t(field)) ? nullptr : &areas_[field]; } + [[nodiscard]] AreaBuffer* GetAreasRaw(int field) noexcept { return (areas_.size() <= size_t(field)) ? nullptr : &areas_[field]; } [[nodiscard]] bool IsCommited() const noexcept { return commited_; } [[nodiscard]] size_t GetAreasCount() const noexcept { size_t size = 0; - for (const auto &aVec : areas_) { + for (const auto& aVec : areas_) { size += aVec.Size(); } return size; } - [[nodiscard]] bool InsertArea(Area &&area, int field, int32_t rank, int maxAreasInDoc) { + [[nodiscard]] bool InsertArea(Area&& area, int field, int32_t rank, int maxAreasInDoc) { commited_ = false; - if (areas_.size() <= size_t(field)) areas_.resize(field + 1); - auto &fieldAreas = areas_[field]; + if (areas_.size() <= size_t(field)) { + areas_.resize(field + 1); + } + auto& fieldAreas = areas_[field]; return fieldAreas.Insert(std::move(area), rank, maxAreasInDoc, maxTermRank_); } @@ -125,8 +133,8 @@ class AreaHolder { int32_t maxTermRank_ = 0; }; -inline void AreaBuffer::MoveAreas(AreaHolder &to, int field, int32_t rank, int maxAreasInDoc) { - for (auto &v : data_) { +inline void AreaBuffer::MoveAreas(AreaHolder& to, int field, int32_t rank, int maxAreasInDoc) { + for (auto& v : data_) { [[maybe_unused]] bool r = to.InsertArea(std::move(v), field, rank, maxAreasInDoc); } to.UpdateRank(rank); diff --git a/cpp_src/core/ft/bm25.h b/cpp_src/core/ft/bm25.h index b20e5521d..3cd0122b9 100644 --- a/cpp_src/core/ft/bm25.h +++ b/cpp_src/core/ft/bm25.h @@ -19,7 +19,9 @@ class Bm25Rx { static RX_ALWAYS_INLINE double IDF(double totalDocCount, double matchedDocCount) noexcept { double f = log((totalDocCount - matchedDocCount + 1) / matchedDocCount) / log(1 + totalDocCount); // saturate min to 0.2 - if (f < 0.2) f = 0.2; + if (f < 0.2) { + f = 0.2; + } return f; } static RX_ALWAYS_INLINE double TF(double termCountInDoc, double wordsInDoc) noexcept { diff --git a/cpp_src/core/ft/config/baseftconfig.cc b/cpp_src/core/ft/config/baseftconfig.cc index 1a1046b91..4a46c1522 100644 --- a/cpp_src/core/ft/config/baseftconfig.cc +++ b/cpp_src/core/ft/config/baseftconfig.cc @@ -7,11 +7,15 @@ namespace reindexer { BaseFTConfig::BaseFTConfig() { - for (const char **p = stop_words_en; *p != nullptr; p++) stopWords.insert({*p, StopWord::Type::Morpheme}); - for (const char **p = stop_words_ru; *p != nullptr; p++) stopWords.insert({*p, StopWord::Type::Morpheme}); + for (const char** p = stop_words_en; *p != nullptr; p++) { + stopWords.insert({*p, StopWord::Type::Morpheme}); + } + for (const char** p = stop_words_ru; *p != nullptr; p++) { + stopWords.insert({*p, StopWord::Type::Morpheme}); + } } -void BaseFTConfig::parseBase(const gason::JsonNode &root) { +void BaseFTConfig::parseBase(const gason::JsonNode& root) { enableTranslit = root["enable_translit"].As<>(enableTranslit); enableNumbersSearch = root["enable_numbers_search"].As<>(enableNumbersSearch); enableKbLayout = root["enable_kb_layout"].As<>(enableKbLayout); @@ -19,10 +23,10 @@ void BaseFTConfig::parseBase(const gason::JsonNode &root) { logLevel = root["log_level"].As<>(logLevel, 0, 5); extraWordSymbols = root["extra_word_symbols"].As<>(extraWordSymbols); - auto &stopWordsNode = root["stop_words"]; + auto& stopWordsNode = root["stop_words"]; if (!stopWordsNode.empty()) { stopWords.clear(); - for (auto &sw : stopWordsNode) { + for (auto& sw : stopWordsNode) { std::string word; StopWord::Type type = StopWord::Type::Stop; if (sw.value.getTag() == gason::JsonTag::JSON_STRING) { @@ -32,7 +36,7 @@ void BaseFTConfig::parseBase(const gason::JsonNode &root) { type = sw["is_morpheme"].As() ? StopWord::Type::Morpheme : StopWord::Type::Stop; } - if (std::find_if(word.begin(), word.end(), [](const auto &symbol) { return std::isspace(symbol); }) != word.end()) { + if (std::find_if(word.begin(), word.end(), [](const auto& symbol) { return std::isspace(symbol); }) != word.end()) { throw Error(errParams, "Stop words can't contain spaces: %s", word); } @@ -43,19 +47,25 @@ void BaseFTConfig::parseBase(const gason::JsonNode &root) { } } - auto &stemmersNode = root["stemmers"]; + auto& stemmersNode = root["stemmers"]; if (!stemmersNode.empty()) { stemmers.clear(); - for (auto &st : stemmersNode) stemmers.emplace_back(st.As()); + for (auto& st : stemmersNode) { + stemmers.emplace_back(st.As()); + } } synonyms.clear(); - for (auto &se : root["synonyms"]) { + for (auto& se : root["synonyms"]) { Synonym synonym; - for (auto &ae : se["alternatives"]) synonym.alternatives.emplace_back(ae.As()); - for (auto &te : se["tokens"]) synonym.tokens.emplace_back(te.As()); + for (auto& ae : se["alternatives"]) { + synonym.alternatives.emplace_back(ae.As()); + } + for (auto& te : se["tokens"]) { + synonym.tokens.emplace_back(te.As()); + } synonyms.emplace_back(std::move(synonym)); } - const auto &baseRankingConfigNode = root["base_ranking"]; + const auto& baseRankingConfigNode = root["base_ranking"]; if (!baseRankingConfigNode.empty()) { rankingConfig.fullMatch = baseRankingConfigNode["full_match_proc"].As<>(rankingConfig.fullMatch, 0, 500); rankingConfig.prefixMin = baseRankingConfigNode["prefix_min_proc"].As<>(rankingConfig.prefixMin, 0, 500); @@ -69,7 +79,7 @@ void BaseFTConfig::parseBase(const gason::JsonNode &root) { } } -void BaseFTConfig::getJson(JsonBuilder &jsonBuilder) const { +void BaseFTConfig::getJson(JsonBuilder& jsonBuilder) const { jsonBuilder.Put("enable_translit", enableTranslit); jsonBuilder.Put("enable_numbers_search", enableNumbersSearch); jsonBuilder.Put("enable_kb_layout", enableKbLayout); @@ -79,21 +89,25 @@ void BaseFTConfig::getJson(JsonBuilder &jsonBuilder) const { jsonBuilder.Array("stemmers", stemmers); { auto synonymsNode = jsonBuilder.Array("synonyms"); - for (const auto &synonym : synonyms) { + for (const auto& synonym : synonyms) { auto synonymObj = synonymsNode.Object(); { auto tokensNode = synonymObj.Array("tokens"); - for (const auto &token : synonym.tokens) tokensNode.Put(nullptr, token); + for (const auto& token : synonym.tokens) { + tokensNode.Put(nullptr, token); + } } { auto alternativesNode = synonymObj.Array("alternatives"); - for (const auto &token : synonym.alternatives) alternativesNode.Put(nullptr, token); + for (const auto& token : synonym.alternatives) { + alternativesNode.Put(nullptr, token); + } } } } { auto stopWordsNode = jsonBuilder.Array("stop_words"); - for (const auto &sw : stopWords) { + for (const auto& sw : stopWords) { auto wordNode = stopWordsNode.Object(nullptr); wordNode.Put("word", sw); wordNode.Put("is_morpheme", sw.type == StopWord::Type::Morpheme); diff --git a/cpp_src/core/ft/config/ftfastconfig.cc b/cpp_src/core/ft/config/ftfastconfig.cc index 46ecb1c11..e7a55de9e 100644 --- a/cpp_src/core/ft/config/ftfastconfig.cc +++ b/cpp_src/core/ft/config/ftfastconfig.cc @@ -12,7 +12,9 @@ namespace { template static bool isAllEqual(const C& c) { for (size_t i = 1, size = c.size(); i < size; ++i) { - if (!(c[0] == c[i])) return false; + if (!(c[0] == c[i])) { + return false; + } } return true; } diff --git a/cpp_src/core/ft/config/ftfuzzyconfig.cc b/cpp_src/core/ft/config/ftfuzzyconfig.cc index 15a2c2fec..29666f551 100644 --- a/cpp_src/core/ft/config/ftfuzzyconfig.cc +++ b/cpp_src/core/ft/config/ftfuzzyconfig.cc @@ -6,8 +6,10 @@ namespace reindexer { -void FtFuzzyConfig::parse(std::string_view json, const RHashMap &) { - if (json.empty()) return; +void FtFuzzyConfig::parse(std::string_view json, const RHashMap&) { + if (json.empty()) { + return; + } try { gason::JsonParser parser; @@ -26,12 +28,12 @@ void FtFuzzyConfig::parse(std::string_view json, const RHashMap &) const { +std::string FtFuzzyConfig::GetJson(const fast_hash_map&) const { WrSerializer wrser; JsonBuilder jsonBuilder(wrser); BaseFTConfig::getJson(jsonBuilder); diff --git a/cpp_src/core/ft/filters/synonyms.cc b/cpp_src/core/ft/filters/synonyms.cc index 64b2afe59..6c5413bb6 100644 --- a/cpp_src/core/ft/filters/synonyms.cc +++ b/cpp_src/core/ft/filters/synonyms.cc @@ -6,7 +6,9 @@ namespace reindexer { void Synonyms::GetVariants(const std::wstring& data, std::vector& result, int proc) { - if (one2one_.empty()) return; + if (one2one_.empty()) { + return; + } auto it = one2one_.find(data); if (it == one2one_.end()) { @@ -54,7 +56,9 @@ static void divOptsForAlternatives(FtDslOpts& opts, size_t size) { assertrx(size != 0); opts.boost /= size; opts.termLenBoost /= size; - for (auto& fOpts : opts.fieldsOpts) fOpts.boost /= size; + for (auto& fOpts : opts.fieldsOpts) { + fOpts.boost /= size; + } opts.qpos /= size; } diff --git a/cpp_src/core/ft/filters/translit.cc b/cpp_src/core/ft/filters/translit.cc index 114db5807..c8a5a0e38 100644 --- a/cpp_src/core/ft/filters/translit.cc +++ b/cpp_src/core/ft/filters/translit.cc @@ -10,7 +10,7 @@ Translit::Translit() { PrepareEnglish(); } -void Translit::GetVariants(const std::wstring &data, std::vector &result, int proc) { +void Translit::GetVariants(const std::wstring& data, std::vector& result, int proc) { std::wstring strings[maxTranslitVariants]; Context ctx; if (data.length()) { @@ -33,7 +33,7 @@ void Translit::GetVariants(const std::wstring &data, std::vector & for (int j = 0; j < maxTranslitVariants; ++j) { auto sym = GetEnglish(symbol, j, ctx); if (sym.second) { - auto &str = strings[j]; + auto& str = strings[j]; if (sym.first) { str.erase(str.end() - sym.first, str.end()); } @@ -51,7 +51,7 @@ void Translit::GetVariants(const std::wstring &data, std::vector & } int64_t lastResultIdx = -1; for (int i = 0; i < maxTranslitVariants; ++i) { - auto ¤t = strings[i]; + auto& current = strings[i]; for (int j = i + 1; j < maxTranslitVariants; ++j) { if (current == strings[j]) { current.clear(); @@ -65,16 +65,20 @@ void Translit::GetVariants(const std::wstring &data, std::vector & } } -std::pair Translit::GetEnglish(wchar_t symbol, size_t variant, Context &ctx) { +std::pair Translit::GetEnglish(wchar_t symbol, size_t variant, Context& ctx) { assertrx(symbol != 0 && symbol >= enLettersStartUTF16 && symbol - enLettersStartUTF16 < enAlfavitSize); if (variant == 1 && ctx.GetCount() > 0) { auto sym = en_d_buf_[ctx.GetLast()][symbol - enLettersStartUTF16]; - if (sym) return {1, sym}; + if (sym) { + return {1, sym}; + } } else if (variant == 2 && ctx.GetCount() > 1) { auto sym = en_t_buf_[ctx.GetPrevios()][ctx.GetLast()][symbol - enLettersStartUTF16]; ctx.Set(symbol - enLettersStartUTF16); - if (sym) return {2, sym}; + if (sym) { + return {2, sym}; + } } if (variant == 2) { diff --git a/cpp_src/core/ft/filters/translit.h b/cpp_src/core/ft/filters/translit.h index 4e05845bb..f9577a042 100644 --- a/cpp_src/core/ft/filters/translit.h +++ b/cpp_src/core/ft/filters/translit.h @@ -8,7 +8,7 @@ class Translit : public ITokenFilter { public: Translit(); - virtual void GetVariants(const std::wstring &data, std::vector &result, int proc) override final; + virtual void GetVariants(const std::wstring& data, std::vector& result, int proc) override final; private: void PrepareRussian(); @@ -29,7 +29,7 @@ class Translit : public ITokenFilter { size_t total_count_; unsigned short num_[2]; }; - std::pair GetEnglish(wchar_t, size_t, Context &ctx); + std::pair GetEnglish(wchar_t, size_t, Context& ctx); bool CheckIsEn(wchar_t symbol); static const int ruLettersStartUTF16 = 1072; diff --git a/cpp_src/core/ft/ft_fast/dataholder.cc b/cpp_src/core/ft/ft_fast/dataholder.cc index 607dd675d..4dc826ce9 100644 --- a/cpp_src/core/ft/ft_fast/dataholder.cc +++ b/cpp_src/core/ft/ft_fast/dataholder.cc @@ -50,7 +50,9 @@ std::string IDataHolder::Dump() { size_t counter = 0; for (auto& step : steps) { ss << "Step : " << std::to_string(counter); - if (!step.suffixes_.word_size()) ss << " - empty step"; + if (!step.suffixes_.word_size()) { + ss << " - empty step"; + } ss << std::endl; for (size_t i = 0; i < step.suffixes_.word_size(); i++) { ss << step.suffixes_.word_at(i) << std::endl; @@ -72,7 +74,9 @@ void IDataHolder::throwStepsOverflow() const { WordIdType IDataHolder::findWord(std::string_view word) { WordIdType id; id.SetEmpty(); - if (steps.size() <= 1) return id; + if (steps.size() <= 1) { + return id; + } for (auto step = steps.begin(); step != steps.end() - 1; ++step) { auto it = step->suffixes_.lower_bound(word); diff --git a/cpp_src/core/ft/ft_fast/dataholder.h b/cpp_src/core/ft/ft_fast/dataholder.h index e6aea4846..5926fc491 100644 --- a/cpp_src/core/ft/ft_fast/dataholder.h +++ b/cpp_src/core/ft/ft_fast/dataholder.h @@ -126,7 +126,9 @@ class IDataHolder { bool NeedRecomitLast() const noexcept { return steps.back().suffixes_.word_size() < size_t(cfg_->maxStepSize); } void SetWordsOffset(uint32_t word_offset) noexcept { assertrx(!steps.empty()); - if (status_ == CreateNew) steps.back().wordOffset_ = word_offset; + if (status_ == CreateNew) { + steps.back().wordOffset_ = word_offset; + } } bool NeedClear(bool complte_updated) const noexcept { return NeedRebuild(complte_updated) || !NeedRecomitLast(); } suffix_map& GetSuffix() noexcept { return steps.back().suffixes_; } diff --git a/cpp_src/core/ft/ft_fast/dataprocessor.cc b/cpp_src/core/ft/ft_fast/dataprocessor.cc index 8fab82b6e..fc0279362 100644 --- a/cpp_src/core/ft/ft_fast/dataprocessor.cc +++ b/cpp_src/core/ft/ft_fast/dataprocessor.cc @@ -22,14 +22,14 @@ void DataProcessor::Process(bool multithread) { const auto tm0 = system_clock_w::now(); size_t szCnt = buildWordsMap(words_um, multithread); const auto tm1 = system_clock_w::now(); - auto &words = holder_.GetWords(); + auto& words = holder_.GetWords(); const size_t wrdOffset = words.size(); holder_.SetWordsOffset(wrdOffset); const auto preprocWords = insertIntoSuffix(words_um, holder_); const auto tm2 = system_clock_w::now(); // Step 4: Commit suffixes array. It runs in parallel with next step - auto &suffixes = holder_.GetSuffix(); + auto& suffixes = holder_.GetSuffix(); auto tm3 = tm2, tm4 = tm2; std::thread sufBuildThread = runInThread(exwr, [&suffixes, &tm3] { suffixes.build(); @@ -71,9 +71,9 @@ void DataProcessor::Process(bool multithread) { } template -typename DataProcessor::WordsVector DataProcessor::insertIntoSuffix(words_map &words_um, DataHolder &holder) { - auto &words = holder.GetWords(); - auto &suffix = holder.GetSuffix(); +typename DataProcessor::WordsVector DataProcessor::insertIntoSuffix(words_map& words_um, DataHolder& holder) { + auto& words = holder.GetWords(); + auto& suffix = holder.GetSuffix(); suffix.reserve(words_um.size() * 20, words_um.size()); const bool enableNumbersSearch = holder.cfg_->enableNumbersSearch; @@ -81,7 +81,7 @@ typename DataProcessor::WordsVector DataProcessor::insertIntoSuf WordsVector found; found.reserve(words_um.size()); - for (auto &keyIt : words_um) { + for (auto& keyIt : words_um) { // if we still haven't whis word we add it to new suffix tree else we will only add info to current word auto id = words.size(); @@ -105,7 +105,7 @@ typename DataProcessor::WordsVector DataProcessor::insertIntoSuf } template -size_t DataProcessor::commitIdRelSets(const WordsVector &preprocWords, words_map &words_um, DataHolder &holder, +size_t DataProcessor::commitIdRelSets(const WordsVector& preprocWords, words_map& words_um, DataHolder& holder, size_t wrdOffset) { size_t idsetcnt = 0; auto wIt = holder.GetWords().begin() + wrdOffset; @@ -113,7 +113,7 @@ size_t DataProcessor::commitIdRelSets(const WordsVector &preprocWords, w auto preprocWordsSize = preprocWords.size(); for (auto keyIt = words_um.begin(), endIt = words_um.end(); keyIt != endIt; ++keyIt, ++i) { // Pack idrelset - PackedWordEntry *word = nullptr; + PackedWordEntry* word = nullptr; if (preprocWordsSize > i) { if (auto widPtr = std::get_if(&preprocWords[i]); widPtr) { assertrx_dbg(!widPtr->IsEmpty()); @@ -153,7 +153,7 @@ static uint32_t getMaxBuildWorkers(bool multithread) noexcept { } template -void makeDocsDistribution(ContextT *ctxs, size_t ctxsCount, size_t docs) { +void makeDocsDistribution(ContextT* ctxs, size_t ctxsCount, size_t docs) { if (ctxsCount == 1) { ctxs[0].from = 0; ctxs[0].to = docs; @@ -188,11 +188,11 @@ void makeDocsDistribution(ContextT *ctxs, size_t ctxsCount, size_t docs) { } template -size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithread) { +size_t DataProcessor::buildWordsMap(words_map& words_um, bool multithread) { ExceptionPtrWrapper exwr; uint32_t maxIndexWorkers = getMaxBuildWorkers(multithread); size_t szCnt = 0; - auto &vdocsTexts = holder_.vdocsTexts; + auto& vdocsTexts = holder_.vdocsTexts; struct context { words_map words_um; std::thread thread; @@ -232,8 +232,8 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea #endif // RX_WITH_STDLIB_DEBUG ThreadsContainer bgThreads; - auto &cfg = holder_.cfg_; - auto &vdocs = holder_.vdocs_; + auto& cfg = holder_.cfg_; + auto& vdocs = holder_.vdocs_; const int fieldscount = fieldSize_; size_t offset = holder_.vdocsOffset_; // build words map parallel in maxIndexWorkers threads @@ -249,11 +249,11 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea const word_hash h; for (VDocIdType j = start; j < fin; ++j) { const size_t vdocId = offset + j; - auto &vdoc = vdocs[vdocId]; + auto& vdoc = vdocs[vdocId]; vdoc.wordsCount.resize(fieldscount, 0.0); vdoc.mostFreqWordCount.resize(fieldscount, 0.0); - auto &vdocsText = vdocsTexts[j]; + auto& vdocsText = vdocsTexts[j]; for (size_t field = 0, sz = vdocsText.size(); field < sz; ++field) { split(vdocsText[field].first, str, wrds, extraWordSymbols); const int rfield = vdocsText[field].second; @@ -265,7 +265,9 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea for (auto word : wrds) { ++insertPos; const auto whash = h(word); - if (!word.length() || cfg->stopWords.find(word, whash) != cfg->stopWords.end()) continue; + if (!word.length() || cfg->stopWords.find(word, whash) != cfg->stopWords.end()) { + continue; + } auto [idxIt, emplaced] = ctx->words_um.try_emplace_prehashed(whash, word); (void)emplaced; @@ -290,13 +292,13 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea words_um = std::move(ctxs[0].words_um); // Merge results into single map for (uint32_t i = 1; i < maxIndexWorkers; ++i) { - auto &ctx = ctxs[i]; + auto& ctx = ctxs[i]; ctx.thread.join(); if (exwr.HasException()) { continue; } - for (auto &it : ctx.words_um) { + for (auto& it : ctx.words_um) { #if defined(RX_WITH_STDLIB_DEBUG) || defined(REINDEX_WITH_ASAN) const auto fBeforeMove = it.first; const auto sBeforeMove = it.second.MakeCopy(); @@ -311,8 +313,8 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea assertrx(it.second.vids.size() == sBeforeMove.vids.size()); assertrx(it.second.vids.capacity() == sCapacityBeforeMove); #endif // defined(RX_WITH_STDLIB_DEBUG) || defined(REINDEX_WITH_ASAN) - auto &resultVids = idxIt->second.vids; - auto &newVids = it.second.vids; + auto& resultVids = idxIt->second.vids; + auto& newVids = it.second.vids; resultVids.insert(resultVids.end(), std::make_move_iterator(newVids.begin()), std::make_move_iterator(newVids.end())); } } @@ -334,15 +336,17 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea if (vdocs.size()) { holder_.avgWordsCount_.resize(fieldscount, 0); for (int i = 0; i < fieldscount; i++) { - auto &avgRef = holder_.avgWordsCount_[i]; - for (auto &vdoc : vdocs) avgRef += vdoc.wordsCount[i]; + auto& avgRef = holder_.avgWordsCount_[i]; + for (auto& vdoc : vdocs) { + avgRef += vdoc.wordsCount[i]; + } avgRef /= vdocs.size(); } } // Check and print potential stop words if (holder_.cfg_->logLevel >= LogInfo) { WrSerializer out; - for (auto &w : words_um) { + for (auto& w : words_um) { if (w.second.vids.size() > vdocs.size() / 5 || int64_t(w.second.vids.size()) > holder_.cfg_->mergeLimit) { out << w.first << "(" << w.second.vids.size() << ") "; } @@ -354,11 +358,11 @@ size_t DataProcessor::buildWordsMap(words_map &words_um, bool multithrea } template -void DataProcessor::buildVirtualWord(std::string_view word, words_map &words_um, VDocIdType docType, int rfield, size_t insertPos, - std::vector &container) { - auto &vdoc(holder_.vdocs_[docType]); +void DataProcessor::buildVirtualWord(std::string_view word, words_map& words_um, VDocIdType docType, int rfield, size_t insertPos, + std::vector& container) { + auto& vdoc(holder_.vdocs_[docType]); NumToText::convert(word, container); - for (std::string &numberWord : container) { + for (std::string& numberWord : container) { WordEntry wentry; wentry.virtualWord = true; auto idxIt = words_um.emplace(std::move(numberWord), std::move(wentry)).first; @@ -372,7 +376,7 @@ void DataProcessor::buildVirtualWord(std::string_view word, words_map &w } template -void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector &preprocWords) { +void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector& preprocWords) { if (!holder_.cfg_->maxTypos) { return; } @@ -380,8 +384,8 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & return; } - auto &typosHalf = holder_.GetTyposHalf(); - auto &typosMax = holder_.GetTyposMax(); + auto& typosHalf = holder_.GetTyposHalf(); + auto& typosMax = holder_.GetTyposMax(); const auto wordsSize = preprocWords.size(); const auto maxTypoLen = holder_.cfg_->maxTypoLen; const auto maxTyposInWord = holder_.cfg_->MaxTyposInWord(); @@ -393,14 +397,14 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & typosHalf.reserve(multiplicator / 2, multiplicator * 5); auto wordPos = startPos; - for (auto &word : preprocWords) { + for (auto& word : preprocWords) { const auto wordString = std::get_if(&word); if (!wordString) { continue; } const auto wordId = holder_.BuildWordId(wordPos++); mktypos(tctx, *wordString, maxTyposInWord, maxTypoLen, - typos_context::CallBack{[&typosHalf, wordId](std::string_view typo, int, const typos_context::TyposVec &positions) { + typos_context::CallBack{[&typosHalf, wordId](std::string_view typo, int, const typos_context::TyposVec& positions) { typosHalf.emplace(typo, WordTypo{wordId, positions}); }}); } @@ -416,7 +420,7 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & auto wordPos = startPos; mult = wordsSize * (10 << (maxTyposInWord - 1)) - mult; typosMax.reserve(multiplicator / 2, multiplicator * 5); - for (auto &word : preprocWords) { + for (auto& word : preprocWords) { const auto wordString = std::get_if(&word); if (!wordString) { continue; @@ -424,7 +428,7 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & const auto wordId = holder_.BuildWordId(wordPos++); mktypos(tctx, *wordString, maxTyposInWord, maxTypoLen, typos_context::CallBack{[wordId, &typosMax, wordString](std::string_view typo, int level, - const typos_context::TyposVec &positions) { + const typos_context::TyposVec& positions) { if (level <= 1 && typo.size() != wordString->size()) { typosMax.emplace(typo, WordTypo{wordId, positions}); } @@ -438,7 +442,7 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & auto wordPos = startPos; typos_context tctx[kMaxTyposInWord]; typosHalf.reserve(multiplicator / 2, multiplicator * 5); - for (auto &word : preprocWords) { + for (auto& word : preprocWords) { const auto wordString = std::get_if(&word); if (!wordString) { continue; @@ -446,7 +450,7 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & const auto wordId = holder_.BuildWordId(wordPos++); mktypos(tctx, *wordString, maxTyposInWord, maxTypoLen, typos_context::CallBack{ - [wordId, &typosHalf, wordString](std::string_view typo, int level, const typos_context::TyposVec &positions) { + [wordId, &typosHalf, wordString](std::string_view typo, int level, const typos_context::TyposVec& positions) { if (level > 1 || typo.size() == wordString->size()) { typosHalf.emplace(typo, WordTypo{wordId, positions}); } @@ -463,9 +467,9 @@ void DataProcessor::buildTyposMap(uint32_t startPos, const WordsVector & template template -std::thread DataProcessor::runInThread(ExceptionPtrWrapper &ew, F &&f, Args &&...args) noexcept { +std::thread DataProcessor::runInThread(ExceptionPtrWrapper& ew, F&& f, Args&&... args) noexcept { return std::thread( - [fw = std::forward(f), &ew](auto &&...largs) noexcept { + [fw = std::forward(f), &ew](auto&&... largs) noexcept { try { fw(largs...); } catch (...) { diff --git a/cpp_src/core/ft/ft_fast/selecter.cc b/cpp_src/core/ft/ft_fast/selecter.cc index 56ba3787e..c02d82ed7 100644 --- a/cpp_src/core/ft/ft_fast/selecter.cc +++ b/cpp_src/core/ft/ft_fast/selecter.cc @@ -9,11 +9,21 @@ namespace { RX_ALWAYS_INLINE double pos2rank(int pos) { - if (pos <= 10) return 1.0 - (pos / 100.0); - if (pos <= 100) return 0.9 - (pos / 1000.0); - if (pos <= 1000) return 0.8 - (pos / 10000.0); - if (pos <= 10000) return 0.7 - (pos / 100000.0); - if (pos <= 100000) return 0.6 - (pos / 1000000.0); + if (pos <= 10) { + return 1.0 - (pos / 100.0); + } + if (pos <= 100) { + return 0.9 - (pos / 1000.0); + } + if (pos <= 1000) { + return 0.8 - (pos / 10000.0); + } + if (pos <= 10000) { + return 0.7 - (pos / 100000.0); + } + if (pos <= 100000) { + return 0.6 - (pos / 1000000.0); + } return 0.5; } } // namespace @@ -85,7 +95,9 @@ void Selecter::prepareVariants(std::vector& variants, RV FtDslOpts opts = term.opts; opts.pref = true; - if (&v != &variantsUtf16[0]) opts.suff = false; + if (&v != &variantsUtf16[0]) { + opts.suff = false; + } const auto charCount = getUTF8StringCharactersCount(stemstr); if (charCount >= kMinStemRellevantLen || !lowRelVariants) { @@ -115,7 +127,9 @@ RX_NO_INLINE MergeData Selecter::Process(FtDSLQuery&& dsl, bool inTransa // STEP 2: Search dsl terms for each variant std::vector synonymsDsl; holder_.synonyms_->PreProcess(dsl, synonymsDsl, holder_.cfg_->rankingConfig.synonyms); - if (!inTransaction) ThrowOnCancel(rdxCtx); + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } for (size_t i = 0; i < dsl.size(); ++i) { const auto irrVariantsCount = ctx.lowRelVariants.size(); @@ -149,11 +163,15 @@ RX_NO_INLINE MergeData Selecter::Process(FtDSLQuery&& dsl, bool inTransa std::vector results; size_t reserveSize = ctx.rawResults.size(); - for (const SynonymsDsl& synDsl : synonymsDsl) reserveSize += synDsl.dsl.size(); + for (const SynonymsDsl& synDsl : synonymsDsl) { + reserveSize += synDsl.dsl.size(); + } results.reserve(reserveSize); std::vector synonymsBounds; synonymsBounds.reserve(synonymsDsl.size()); - if (!inTransaction) ThrowOnCancel(rdxCtx); + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } for (SynonymsDsl& synDsl : synonymsDsl) { FtSelectContext synCtx; synCtx.rawResults.reserve(synDsl.dsl.size()); @@ -162,7 +180,9 @@ RX_NO_INLINE MergeData Selecter::Process(FtDSLQuery&& dsl, bool inTransa if rx_unlikely (holder_.cfg_->logLevel >= LogInfo) { WrSerializer wrSer; for (auto& variant : synCtx.variants) { - if (&variant != &*synCtx.variants.begin()) wrSer << ", "; + if (&variant != &*synCtx.variants.begin()) { + wrSer << ", "; + } wrSer << variant.pattern; } logPrintf(LogInfo, "Multiword synonyms variants: [%s]", wrSer.Slice()); @@ -245,7 +265,9 @@ void Selecter::processStepVariants(FtSelectContext& ctx, typename DataHo // Walk current variant in suffixes array and fill results do { - if (keyIt == suffixes.end()) break; + if (keyIt == suffixes.end()) { + break; + } if (vidsLimit <= vids) { if rx_unlikely (holder_.cfg_->logLevel >= LogInfo) { logPrintf(LogInfo, "Terminating suffix loop on limit (%d). Current variant is '%s%s%s'", initialLimit, @@ -279,8 +301,12 @@ void Selecter::processStepVariants(FtSelectContext& ctx, typename DataHo const ptrdiff_t suffixLen = keyIt->first - word; const int matchLen = tmpstr.length(); - if (!withSuffixes && suffixLen) continue; - if (!withPrefixes && wordLength != matchLen + suffixLen) break; + if (!withSuffixes && suffixLen) { + continue; + } + if (!withPrefixes && wordLength != matchLen + suffixLen) { + break; + } const int matchDif = std::abs(long(wordLength - matchLen + suffixLen)); const int proc = std::max(variant.proc - holder_.cfg_->partialMatchDecrease * matchDif / std::max(matchLen, 3), @@ -302,8 +328,9 @@ void Selecter::processStepVariants(FtSelectContext& ctx, typename DataHo ++matched; vids += vidsSize; } else { - if (ctx.rawResults[it->second.first][it->second.second].proc < proc) + if (ctx.rawResults[it->second.first][it->second.second].proc < proc) { ctx.rawResults[it->second.first][it->second.second].proc = proc; + } ++skipped; } } while ((keyIt++).lcp() >= int(tmpstr.length())); @@ -404,7 +431,9 @@ template RX_ALWAYS_INLINE void Selecter::debugMergeStep(const char* msg, int vid, float normBm25, float normDist, int finalRank, int prevRank) { #ifdef REINDEX_FT_EXTRA_DEBUG - if (holder_.cfg_->logLevel < LogTrace) return; + if (holder_.cfg_->logLevel < LogTrace) { + return; + } logPrintf(LogInfo, "%s - '%s' (vid %d), bm25 %f, dist %f, rank %d (prev rank %d)", msg, holder_.vdocs_[vid].keyDoc, vid, normBm25, normDist, finalRank, prevRank); @@ -633,7 +662,7 @@ void Selecter::addNewTerm(FtMergeStatuses::Statuses& mergeStatuses, Merg curExists[vid] = true; idoffsets[vid] = merged.size() - 1; } -}; +} template void Selecter::addAreas(MergeData& merged, int32_t areaIndex, const IdRelType& relid, int32_t termRank) { @@ -646,7 +675,7 @@ void Selecter::addAreas(MergeData& merged, int32_t areaIndex, const IdRe } area.UpdateRank(termRank); } -}; +} // idf=max(0.2, log((N-M+1)/M)/log(1+N)) // N - document count @@ -691,7 +720,9 @@ void Selecter::mergeIteration(TextSearchResults& rawRes, index_t rawResI // loop on subterm (word, translit, stemmmer,...) for (auto& r : rawRes) { - if (!inTransaction) ThrowOnCancel(rdxCtx); + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } Bm25Calculator bm25{double(totalDocsCount), double(r.vids->size()), holder_.cfg_->bm25Config.bm25k1, holder_.cfg_->bm25Config.bm25b}; static_assert(sizeof(bm25) <= 32, "Bm25Calculator size is greater than 32 bytes"); @@ -800,7 +831,9 @@ std::pair Selecter::calcTermRank(const TextSearchResults& r } } - if (!termRank) return std::make_pair(termRank, field); + if (!termRank) { + return std::make_pair(termRank, field); + } if (holder_.cfg_->summationRanksByFieldsRatio > 0) { boost::sort::pdqsort_branchless(ranksInFields.begin(), ranksInFields.end()); @@ -828,7 +861,9 @@ void Selecter::mergeIterationGroup(TextSearchResults& rawRes, index_t ra // loop on subterm (word, translit, stemmmer,...) for (auto& r : rawRes) { - if (!inTransaction) ThrowOnCancel(rdxCtx); + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } Bm25Calculator bm25(totalDocsCount, r.vids->size(), holder_.cfg_->bm25Config.bm25k1, holder_.cfg_->bm25Config.bm25b); static_assert(sizeof(bm25) <= 32, "Bm25Calculator size is greater than 32 bytes"); int vid = -1; @@ -846,11 +881,15 @@ void Selecter::mergeIterationGroup(TextSearchResults& rawRes, index_t ra continue; } // keyEntry can be assigned nullptr when removed - if (!vdocs[vid].keyEntry) continue; + if (!vdocs[vid].keyEntry) { + continue; + } // Find field with max rank auto [termRank, field] = calcTermRank(rawRes, bm25, relid, r.proc); - if (!termRank) continue; + if (!termRank) { + continue; + } if rx_unlikely (holder_.cfg_->logLevel >= LogTrace) { logPrintf(LogInfo, "Pattern %s, idf %f, termLenBoost %f", r.pattern, bm25.GetIDF(), rawRes.term.opts.termLenBoost); @@ -1065,7 +1104,9 @@ size_t Selecter::TyposHandler::Process(std::vector& r ++skiped; } } - if (dontUseMaxTyposForBoth_ && level == 1 && typo.size() != patternSize) return; + if (dontUseMaxTyposForBoth_ && level == 1 && typo.size() != patternSize) { + return; + } } }); if rx_unlikely (holder.cfg_->logLevel >= LogInfo) { @@ -1248,7 +1289,9 @@ MergeData Selecter::mergeResults(std::vector&& rawRes const auto& vdocs = holder_.vdocs_; MergeData merged; - if (!rawResults.size() || !vdocs.size()) return merged; + if (!rawResults.size() || !vdocs.size()) { + return merged; + } assertrx_throw(FtMergeStatuses::kExcluded > rawResults.size()); assertrx_throw(mergeStatuses.size() == vdocs.size()); @@ -1323,7 +1366,9 @@ MergeData Selecter::mergeResults(std::vector&& rawRes break; } } - if (matchSyn) continue; + if (matchSyn) { + continue; + } info.proc = 0; mergeStatuses[vid] = 0; } @@ -1354,12 +1399,16 @@ void Selecter::printVariants(const FtSelectContext& ctx, const TextSearc WrSerializer wrSer; wrSer << "variants: ["; for (auto& variant : ctx.variants) { - if (&variant != &*ctx.variants.begin()) wrSer << ", "; + if (&variant != &*ctx.variants.begin()) { + wrSer << ", "; + } wrSer << variant.pattern; } wrSer << "], variants_with_low_relevancy: ["; for (auto& variant : ctx.lowRelVariants) { - if (&variant != &*ctx.lowRelVariants.begin()) wrSer << ", "; + if (&variant != &*ctx.lowRelVariants.begin()) { + wrSer << ", "; + } wrSer << variant.pattern; } wrSer << "], typos: ["; diff --git a/cpp_src/core/ft/ft_fuzzy/advacedpackedvec.h b/cpp_src/core/ft/ft_fuzzy/advacedpackedvec.h index 696fd78af..5ff49b949 100644 --- a/cpp_src/core/ft/ft_fuzzy/advacedpackedvec.h +++ b/cpp_src/core/ft/ft_fuzzy/advacedpackedvec.h @@ -7,7 +7,7 @@ class IdRelType; class AdvacedPackedVec : public packed_vector { public: - AdvacedPackedVec(IdRelSet &&data); + AdvacedPackedVec(IdRelSet&& data); int max_id_; int min_id_; diff --git a/cpp_src/core/ft/ft_fuzzy/baseseacher.cc b/cpp_src/core/ft/ft_fuzzy/baseseacher.cc index 169367607..9b1789dd4 100644 --- a/cpp_src/core/ft/ft_fuzzy/baseseacher.cc +++ b/cpp_src/core/ft/ft_fuzzy/baseseacher.cc @@ -10,9 +10,9 @@ namespace search_engine { using namespace reindexer; -void BaseSearcher::AddSeacher(ITokenFilter::Ptr &&seacher) { searchers_.push_back(std::move(seacher)); } +void BaseSearcher::AddSeacher(ITokenFilter::Ptr&& seacher) { searchers_.push_back(std::move(seacher)); } -std::pair BaseSearcher::GetData(const BaseHolder::Ptr &holder, unsigned int i, wchar_t *buf, const wchar_t *src_data, +std::pair BaseSearcher::GetData(const BaseHolder::Ptr& holder, unsigned int i, wchar_t* buf, const wchar_t* src_data, size_t data_size) { size_t counter = 0; size_t final_counter = 0; @@ -43,8 +43,8 @@ std::pair BaseSearcher::GetData(const BaseHolder::Ptr &holder, uns return std::make_pair(cont, counter + final_counter); } -size_t BaseSearcher::ParseData(const BaseHolder::Ptr &holder, const std::wstring &src_data, int &max_id, int &min_id, - std::vector &rusults, const FtDslOpts &opts, double proc) { +size_t BaseSearcher::ParseData(const BaseHolder::Ptr& holder, const std::wstring& src_data, int& max_id, int& min_id, + std::vector& rusults, const FtDslOpts& opts, double proc) { wchar_t res_buf[maxFuzzyFTBufferSize]; size_t total_size = 0; size_t size = src_data.size(); @@ -56,8 +56,12 @@ size_t BaseSearcher::ParseData(const BaseHolder::Ptr &holder, const std::wstring auto it = holder->GetData(res_buf); if (it != holder->end()) { - if (it->second.max_id_ > max_id) max_id = it->second.max_id_; - if (it->second.min_id_ < min_id) min_id = it->second.min_id_; + if (it->second.max_id_ > max_id) { + max_id = it->second.max_id_; + } + if (it->second.min_id_ < min_id) { + min_id = it->second.min_id_; + } double final_proc = double(holder->cfg_.bufferSize * holder->cfg_.startDecreeseBoost - cont.second) / double(holder->cfg_.bufferSize * holder->cfg_.startDecreeseBoost); rusults.push_back(FirstResult{&it->second, &opts, static_cast(i), proc * final_proc}); @@ -67,8 +71,8 @@ size_t BaseSearcher::ParseData(const BaseHolder::Ptr &holder, const std::wstring return total_size; } -SearchResult BaseSearcher::Compare(const BaseHolder::Ptr &holder, const FtDSLQuery &dsl, bool inTransaction, - const reindexer::RdxContext &rdxCtx) { +SearchResult BaseSearcher::Compare(const BaseHolder::Ptr& holder, const FtDSLQuery& dsl, bool inTransaction, + const reindexer::RdxContext& rdxCtx) { size_t data_size = 0; std::vector data; @@ -79,8 +83,10 @@ SearchResult BaseSearcher::Compare(const BaseHolder::Ptr &holder, const FtDSLQue int max_id = 0; int min_id = INT32_MAX; - if (!inTransaction) ThrowOnCancel(rdxCtx); - for (auto &term : dsl) { + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } + for (auto& term : dsl) { data_size += ParseData(holder, term.pattern, max_id, min_id, results, term.opts, 1); if (holder->cfg_.enableTranslit) { @@ -117,12 +123,14 @@ SearchResult BaseSearcher::Compare(const BaseHolder::Ptr &holder, const FtDSLQue return res; } -void BaseSearcher::AddIndex(BaseHolder::Ptr &holder, std::string_view src_data, const IdType id, int field, - const std::string &extraWordSymbols) { +void BaseSearcher::AddIndex(BaseHolder::Ptr& holder, std::string_view src_data, const IdType id, int field, + const std::string& extraWordSymbols) { #ifdef FULL_LOG_FT words.push_back(std::make_pair(id, *src_data)); #endif - if (!src_data.length()) return; + if (!src_data.length()) { + return; + } std::pair pos; pos.first = 0; std::wstring utf16str; @@ -130,7 +138,7 @@ void BaseSearcher::AddIndex(BaseHolder::Ptr &holder, std::string_view src_data, split(src_data, utf16str, wrds, extraWordSymbols); wchar_t res_buf[maxFuzzyFTBufferSize]; size_t total_size = 0; - for (auto &term : wrds) { + for (auto& term : wrds) { unsigned int i = 0; std::pair cont; do { @@ -144,5 +152,5 @@ void BaseSearcher::AddIndex(BaseHolder::Ptr &holder, std::string_view src_data, holder->SetSize(total_size, id, field); } -void BaseSearcher::Commit(BaseHolder::Ptr &holder) { holder->Commit(); } +void BaseSearcher::Commit(BaseHolder::Ptr& holder) { holder->Commit(); } } // namespace search_engine diff --git a/cpp_src/core/ft/ft_fuzzy/baseseacher.h b/cpp_src/core/ft/ft_fuzzy/baseseacher.h index 6772a995a..eec4bc078 100644 --- a/cpp_src/core/ft/ft_fuzzy/baseseacher.h +++ b/cpp_src/core/ft/ft_fuzzy/baseseacher.h @@ -16,25 +16,24 @@ namespace search_engine { class BaseSearcher { public: - void AddSeacher(ITokenFilter::Ptr &&seacher); - void AddIndex(BaseHolder::Ptr &holder, std::string_view src_data, const IdType id, int field, const std::string &extraWordSymbols); - SearchResult Compare(const BaseHolder::Ptr &holder, const reindexer::FtDSLQuery &dsl, bool inTransaction, - const reindexer::RdxContext &); + void AddSeacher(ITokenFilter::Ptr&& seacher); + void AddIndex(BaseHolder::Ptr& holder, std::string_view src_data, const IdType id, int field, const std::string& extraWordSymbols); + SearchResult Compare(const BaseHolder::Ptr& holder, const reindexer::FtDSLQuery& dsl, bool inTransaction, const reindexer::RdxContext&); - void Commit(BaseHolder::Ptr &holder); + void Commit(BaseHolder::Ptr& holder); private: #ifdef FULL_LOG_FT std::vector> words; #endif - std::pair GetData(const BaseHolder::Ptr &holder, unsigned int i, wchar_t *buf, const wchar_t *src_data, size_t data_size); + std::pair GetData(const BaseHolder::Ptr& holder, unsigned int i, wchar_t* buf, const wchar_t* src_data, size_t data_size); - size_t ParseData(const BaseHolder::Ptr &holder, const std::wstring &src_data, int &max_id, int &min_id, - std::vector &rusults, const FtDslOpts &opts, double proc); + size_t ParseData(const BaseHolder::Ptr& holder, const std::wstring& src_data, int& max_id, int& min_id, + std::vector& rusults, const FtDslOpts& opts, double proc); - void AddIdToInfo(Info *info, const IdType id, std::pair pos, uint32_t total_size); - uint32_t FindHash(const std::wstring &data); + void AddIdToInfo(Info* info, const IdType id, std::pair pos, uint32_t total_size); + uint32_t FindHash(const std::wstring& data); std::vector> searchers_; }; } // namespace search_engine diff --git a/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.cc b/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.cc index d218341de..936f81c98 100644 --- a/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.cc +++ b/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.cc @@ -2,7 +2,7 @@ namespace search_engine { -DIt BaseHolder::GetData(const wchar_t *key) { +DIt BaseHolder::GetData(const wchar_t* key) { #ifndef DEBUG_FT return data_.find(std::wstring(key, cfg_.bufferSize)); #else @@ -10,7 +10,7 @@ DIt BaseHolder::GetData(const wchar_t *key) { #endif } void BaseHolder::SetSize(uint32_t size, VDocIdType id, int field) { words_[id][field] += size; } -void BaseHolder::AddDada(const wchar_t *key, VDocIdType id, int pos, int field) { +void BaseHolder::AddDada(const wchar_t* key, VDocIdType id, int pos, int field) { #ifndef DEBUG_FT std::wstring wkey(key, cfg_.bufferSize); auto it = tmp_data_.find(wkey); @@ -35,7 +35,7 @@ void BaseHolder::AddDada(const wchar_t *key, VDocIdType id, int pos, int field) void BaseHolder::Commit() { data_.reserve(tmp_data_.size()); data_.clear(); - for (auto &val : tmp_data_) { + for (auto& val : tmp_data_) { data_.insert(std::make_pair(val.first, AdvacedPackedVec(std::move(val.second)))); } diff --git a/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.h b/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.h index 5f04f4719..febe60736 100644 --- a/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.h +++ b/cpp_src/core/ft/ft_fuzzy/dataholder/basebuildedholder.h @@ -18,13 +18,13 @@ using namespace reindexer; #ifndef DEBUG_FT struct DataStructHash { - inline size_t operator()(const std::wstring &ent) const noexcept { return Hash(ent); } + inline size_t operator()(const std::wstring& ent) const noexcept { return Hash(ent); } }; struct DataStructEQ { - inline bool operator()(const std::wstring &ent, const std::wstring &ent1) const noexcept { return ent == ent1; } + inline bool operator()(const std::wstring& ent, const std::wstring& ent1) const noexcept { return ent == ent1; } }; struct DataStructLess { - inline bool operator()(const std::wstring &ent, const std::wstring &ent1) const noexcept { return ent < ent1; } + inline bool operator()(const std::wstring& ent, const std::wstring& ent1) const noexcept { return ent < ent1; } }; template using data_map = tsl::hopscotch_map; @@ -47,10 +47,10 @@ class BaseHolder { typedef shared_ptr Ptr; BaseHolder() {} - BaseHolder(BaseHolder &rhs) = delete; - BaseHolder(BaseHolder &&) noexcept = delete; - BaseHolder &operator=(const BaseHolder &) = delete; - BaseHolder &operator=(BaseHolder &&) noexcept = delete; + BaseHolder(BaseHolder& rhs) = delete; + BaseHolder(BaseHolder&&) noexcept = delete; + BaseHolder& operator=(const BaseHolder&) = delete; + BaseHolder& operator=(BaseHolder&&) noexcept = delete; void ClearTemp() { data_map tmp_data; @@ -62,10 +62,10 @@ class BaseHolder { ClearTemp(); data_.clear(); } - void SetConfig(const std::unique_ptr &cfg) { cfg_ = *cfg.get(); } - DIt GetData(const wchar_t *key); + void SetConfig(const std::unique_ptr& cfg) { cfg_ = *cfg.get(); } + DIt GetData(const wchar_t* key); void SetSize(uint32_t size, VDocIdType id, int filed); - void AddDada(const wchar_t *key, VDocIdType id, int pos, int field); + void AddDada(const wchar_t* key, VDocIdType id, int pos, int field); void Commit(); public: diff --git a/cpp_src/core/ft/ft_fuzzy/dataholder/smardeque.cc b/cpp_src/core/ft/ft_fuzzy/dataholder/smardeque.cc index d327a5e34..b309cf038 100644 --- a/cpp_src/core/ft/ft_fuzzy/dataholder/smardeque.cc +++ b/cpp_src/core/ft/ft_fuzzy/dataholder/smardeque.cc @@ -39,8 +39,12 @@ template typename SmartDeque::pointer SmartDeque::operator[](size_t num) const { size_t size = (num / block_size); size_t offset = (num % block_size); - if (!data_ || size >= size_ || !data_[size]) return nullptr; - if (data_[size][offset].proc_ == 0) return nullptr; + if (!data_ || size >= size_ || !data_[size]) { + return nullptr; + } + if (data_[size][offset].proc_ == 0) { + return nullptr; + } return &data_[size][offset]; } template @@ -163,7 +167,9 @@ SmartDeque& SmartDeque::operator=(SmartDeque&& rhs template SmartDeque::~SmartDeque() { - if (!data_) return; + if (!data_) { + return; + } for (size_t i = 0; i < size_; ++i) { delete[] data_[i]; } @@ -172,14 +178,18 @@ SmartDeque::~SmartDeque() { template void SmartDeque::allocSection(size_t num) { - if (!data_) return; + if (!data_) { + return; + } data_[num] = new T[block_size]; memset(data_[num], 0, block_size * sizeof(T)); } template typename SmartDeque::iterator& SmartDeque::iterator::operator++() { - if (parent_ == nullptr) return *this; + if (parent_ == nullptr) { + return *this; + } for (; size_ < parent_->size_; ++size_, offset_ = 0) { if (parent_->data_[size_]) { @@ -199,7 +209,7 @@ typename SmartDeque::iterator& SmartDeque::iterato template SmartDeque::iterator::iterator() : size_(0), offset_(0), parent_(nullptr), current_(nullptr) { - if constexpr(std::is_trivial::value) { + if constexpr (std::is_trivial::value) { memset(&default_data, 0, sizeof(default_data)); } else { static_assert(std::is_default_constructible::value, "Expecting default contractible type"); @@ -207,7 +217,7 @@ SmartDeque::iterator::iterator() : size_(0), offset_(0), parent_( } template SmartDeque::iterator::iterator(SmartDeque* parent) : size_(0), offset_(0), parent_(parent), current_(nullptr) { - if constexpr(std::is_trivial::value) { + if constexpr (std::is_trivial::value) { memset(&default_data, 0, sizeof(default_data)); } else { static_assert(std::is_default_constructible::value, "Expecting default contractible type"); diff --git a/cpp_src/core/ft/ft_fuzzy/dumper/fulltextdumper.cc b/cpp_src/core/ft/ft_fuzzy/dumper/fulltextdumper.cc index a80bff951..c7c74f949 100644 --- a/cpp_src/core/ft/ft_fuzzy/dumper/fulltextdumper.cc +++ b/cpp_src/core/ft/ft_fuzzy/dumper/fulltextdumper.cc @@ -13,7 +13,9 @@ FullTextDumper& FullTextDumper::Init() { } void FullTextDumper::LogFinalData(const reindexer::QueryResults& result) { - if (!std::getenv(env.c_str())) return; + if (!std::getenv(env.c_str())) { + return; + } startThread(); std::vector tmp_buffer; @@ -29,7 +31,9 @@ void FullTextDumper::LogFinalData(const reindexer::QueryResults& result) { new_info_ = true; } void FullTextDumper::Log(const std::string& data) { - if (!std::getenv(env.c_str())) return; + if (!std::getenv(env.c_str())) { + return; + } startThread(); std::lock_guard lk(cv_m); @@ -38,7 +42,9 @@ void FullTextDumper::Log(const std::string& data) { } void FullTextDumper::AddResultData(const std::string& reqest) { - if (!std::getenv(env.c_str())) return; + if (!std::getenv(env.c_str())) { + return; + } startThread(); std::vector tmp_buffer; @@ -95,7 +101,9 @@ void FullTextDumper::writeToFile() { } file.close(); } - if (stoped_ || !std::getenv(env.c_str())) return; + if (stoped_ || !std::getenv(env.c_str())) { + return; + } std::unique_lock lk(cv_m); if (cv.wait_for(lk, seconds(write_timeout_seconds), [this] { return stoped_.load(); })) { @@ -112,10 +120,14 @@ FullTextDumper::~FullTextDumper() { } // static class destructor - nothing conflicrts here - if (buffer_.empty()) return; + if (buffer_.empty()) { + return; + } std::ofstream file(file_path, std::ios::app); - if (!file.is_open()) return; + if (!file.is_open()) { + return; + } for (const auto& data : buffer_) { file << data << "\n"; } diff --git a/cpp_src/core/ft/ft_fuzzy/merger/basemerger.cc b/cpp_src/core/ft/ft_fuzzy/merger/basemerger.cc index d28bbfaab..1c6538c49 100644 --- a/cpp_src/core/ft/ft_fuzzy/merger/basemerger.cc +++ b/cpp_src/core/ft/ft_fuzzy/merger/basemerger.cc @@ -32,10 +32,11 @@ void MergedData::Add(const IDCtx& ctx) { if (!first_) { coof = ctx.pos - prev_.src_pos; - if (src_dst < 0) + if (src_dst < 0) { coof = ctx.cfg.posSourceDistMin; - else + } else { coof = (ctx.total_size * ctx.cfg.posSourceDistBoost - (coof - 1)) / double(ctx.total_size * ctx.cfg.posSourceDistBoost); + } } src_dst *= coof; src_dst = (src_dst * max_src_dist) / ctx.total_size; @@ -50,7 +51,9 @@ void MergedData::Add(const IDCtx& ctx) { dst = (dst * max_dst_dist) / size; double fboost = ctx.opts->fieldsOpts[ctx.data->at(i).field()].boost; - if (!fboost) fboost = 1; + if (!fboost) { + fboost = 1; + } src_dst = src_dst + dst; src_dst *= fboost; @@ -86,7 +89,9 @@ SearchResult BaseMerger::Merge(MergeCtx& ctx, bool inTransaction, const reindexe DataSet data_set(min_id_, max_id_); double max_proc = 0; for (auto& res : *ctx.results) { - if (!inTransaction) ThrowOnCancel(rdxCtx); + if (!inTransaction) { + ThrowOnCancel(rdxCtx); + } for (auto it = res.data->begin(); it != res.data->end(); ++it) { IDCtx id_ctx{&it->Pos(), res.pos, &max_proc, ctx.total_size, res.opts, *ctx.cfg, res.proc, ctx.sizes}; diff --git a/cpp_src/core/ft/ft_fuzzy/merger/basemerger.h b/cpp_src/core/ft/ft_fuzzy/merger/basemerger.h index cfc8f4cad..c86300b04 100644 --- a/cpp_src/core/ft/ft_fuzzy/merger/basemerger.h +++ b/cpp_src/core/ft/ft_fuzzy/merger/basemerger.h @@ -14,14 +14,14 @@ class RdxContext; namespace search_engine { struct IDCtx { - const RVector *data; + const RVector* data; int pos; - double *max_proc; + double* max_proc; size_t total_size; - const FtDslOpts *opts; - const FtFuzzyConfig &cfg; + const FtDslOpts* opts; + const FtFuzzyConfig& cfg; double proc; - word_size_map *sizes; + word_size_map* sizes; }; struct ResultMerger { int src_pos; @@ -32,7 +32,7 @@ struct ResultMerger { class MergedData { public: - MergedData(size_t id, const IDCtx &ctx) : id_(id) { + MergedData(size_t id, const IDCtx& ctx) : id_(id) { size_it_ = ctx.sizes->find(id_); if (size_it_ == ctx.sizes->end()) { abort(); @@ -40,7 +40,7 @@ class MergedData { Add(ctx); } - void Add(const IDCtx &ctx); + void Add(const IDCtx& ctx); double proc_ = 0; size_t id_; size_t count_ = 0; @@ -58,24 +58,24 @@ struct SearchResult { using namespace reindexer; struct FirstResult { - const AdvacedPackedVec *data; - const FtDslOpts *opts; + const AdvacedPackedVec* data; + const FtDslOpts* opts; int pos; double proc; }; struct MergeCtx { - std::vector *results; - const FtFuzzyConfig *cfg; + std::vector* results; + const FtFuzzyConfig* cfg; size_t total_size; - word_size_map *sizes; + word_size_map* sizes; }; class BaseMerger { public: BaseMerger(int max_id, int min_id); - SearchResult Merge(MergeCtx &ctx, bool inTransaction, const RdxContext &); + SearchResult Merge(MergeCtx& ctx, bool inTransaction, const RdxContext&); private: int max_id_; diff --git a/cpp_src/core/ft/ft_fuzzy/prefilter/prefilter.cc b/cpp_src/core/ft/ft_fuzzy/prefilter/prefilter.cc index feae2c86a..6c1f47321 100644 --- a/cpp_src/core/ft/ft_fuzzy/prefilter/prefilter.cc +++ b/cpp_src/core/ft/ft_fuzzy/prefilter/prefilter.cc @@ -50,7 +50,9 @@ std::vector Prefilter::findMin(const std::wstring& data) { for (size_t i = 0; i < data.size() - 1; ++i) { uint32_t hash[2]; MurmurHash3_x64_128(data.substr(i, 2).c_str(), data.size() * sizeof(wchar_t), seeds_[g], &hash); - if (hash[0] < min_hash) min_hash = hash[0]; + if (hash[0] < min_hash) { + min_hash = hash[0]; + } } sig[g] = min_hash; } @@ -64,7 +66,9 @@ double Prefilter::CalcMinDistance(const std::wstring& first, const std::wstring& double Prefilter::GetMinDistance(const std::vector& first, const std::vector& second) { size_t dist = 0; for (size_t i = 0; i < first.size(); ++i) { - if (first[i] == second[i]) dist++; + if (first[i] == second[i]) { + dist++; + } } return dist / static_cast(seeds_.size()); } diff --git a/cpp_src/core/ft/ft_fuzzy/searchengine.h b/cpp_src/core/ft/ft_fuzzy/searchengine.h index 2ec703572..5a0a4eca3 100644 --- a/cpp_src/core/ft/ft_fuzzy/searchengine.h +++ b/cpp_src/core/ft/ft_fuzzy/searchengine.h @@ -18,14 +18,14 @@ class SearchEngine { typedef std::shared_ptr Ptr; SearchEngine(); - void SetConfig(const std::unique_ptr &cfg); - SearchEngine(const SearchEngine &rhs) = delete; + void SetConfig(const std::unique_ptr& cfg); + SearchEngine(const SearchEngine& rhs) = delete; - SearchEngine &operator=(const SearchEngine &) = delete; + SearchEngine& operator=(const SearchEngine&) = delete; - SearchResult Search(const FtDSLQuery &dsl, bool inTransaction, const reindexer::RdxContext &); + SearchResult Search(const FtDSLQuery& dsl, bool inTransaction, const reindexer::RdxContext&); void Rebuild(); - void AddData(std::string_view src_data, const IdType id, int field, const std::string &extraWordSymbols); + void AddData(std::string_view src_data, const IdType id, int field, const std::string& extraWordSymbols); void Commit(); private: diff --git a/cpp_src/core/ft/ftdsl.cc b/cpp_src/core/ft/ftdsl.cc index c14246bcd..5fc5614ce 100644 --- a/cpp_src/core/ft/ftdsl.cc +++ b/cpp_src/core/ft/ftdsl.cc @@ -9,14 +9,14 @@ namespace reindexer { // Format: see fulltext.md -static bool is_term(int ch, const std::string &extraWordSymbols) noexcept { +static bool is_term(int ch, const std::string& extraWordSymbols) noexcept { return IsAlpha(ch) || IsDigit(ch) || extraWordSymbols.find(ch) != std::string::npos // wrong kb layout || ch == '[' || ch == ';' || ch == ',' || ch == '.'; } -static bool is_dslbegin(int ch, const std::string &extraWordSymbols) noexcept { +static bool is_dslbegin(int ch, const std::string& extraWordSymbols) noexcept { return is_term(ch, extraWordSymbols) || ch == '+' || ch == '-' || ch == '*' || ch == '\'' || ch == '\"' || ch == '@' || ch == '=' || ch == '\\'; } @@ -26,7 +26,7 @@ void FtDSLQuery::parse(std::string_view q) { utf8_to_utf16(q, utf16str); parse(utf16str); } -void FtDSLQuery::parse(std::wstring &utf16str) { +void FtDSLQuery::parse(std::wstring& utf16str) { int groupTermCounter = 0; bool inGroup = false; bool hasAnythingExceptNot = false; @@ -157,7 +157,9 @@ void FtDSLQuery::parse(std::wstring &utf16str) { maxPatternLen = (fte.pattern.length() > maxPatternLen) ? fte.pattern.length() : maxPatternLen; emplace_back(std::move(fte)); - if (inGroup) ++groupTermCounter; + if (inGroup) { + ++groupTermCounter; + } } } if (inGroup) { @@ -168,19 +170,25 @@ void FtDSLQuery::parse(std::wstring &utf16str) { } int cnt = 0; - for (auto &e : *this) { + for (auto& e : *this) { e.opts.termLenBoost = float(e.pattern.length()) / maxPatternLen; e.opts.qpos = cnt++; } } -void FtDSLQuery::parseFields(std::wstring &utf16str, std::wstring::iterator &it, h_vector &fieldsOpts) { +void FtDSLQuery::parseFields(std::wstring& utf16str, std::wstring::iterator& it, h_vector& fieldsOpts) { FtDslFieldOpts defFieldOpts{0.0, false}; - for (auto &fo : fieldsOpts) fo = defFieldOpts; + for (auto& fo : fieldsOpts) { + fo = defFieldOpts; + } while (it != utf16str.end()) { - while (it != utf16str.end() && !(IsAlpha(*it) || IsDigit(*it) || *it == '*' || *it == '_' || *it == '+')) ++it; - if (it == utf16str.end()) break; + while (it != utf16str.end() && !(IsAlpha(*it) || IsDigit(*it) || *it == '*' || *it == '_' || *it == '+')) { + ++it; + } + if (it == utf16str.end()) { + break; + } bool needSumRank = false; if (*it == '+') { @@ -190,7 +198,9 @@ void FtDSLQuery::parseFields(std::wstring &utf16str, std::wstring::iterator &it, } } auto begIt = it; - while (it != utf16str.end() && (IsAlpha(*it) || IsDigit(*it) || *it == '*' || *it == '_' || *it == '+' || *it == '.')) ++it; + while (it != utf16str.end() && (IsAlpha(*it) || IsDigit(*it) || *it == '*' || *it == '_' || *it == '+' || *it == '.')) { + ++it; + } auto endIt = it; float boost = 1.0; @@ -218,10 +228,15 @@ void FtDSLQuery::parseFields(std::wstring &utf16str, std::wstring::iterator &it, assertf(f->second < int(fieldsOpts.size()), "f=%d,fieldsOpts.size()=%d", f->second, fieldsOpts.size()); fieldsOpts[f->second] = {boost, needSumRank}; } - if (it == utf16str.end() || *it++ != ',') break; + if (it == utf16str.end() || *it++ != ',') { + break; + } + } + for (auto& fo : fieldsOpts) { + if (fo.boost == 0.0) { + fo = defFieldOpts; + } } - for (auto &fo : fieldsOpts) - if (fo.boost == 0.0) fo = defFieldOpts; } } // namespace reindexer diff --git a/cpp_src/core/ft/ftdsl.h b/cpp_src/core/ft/ftdsl.h index 3f39f3c65..3ef26922e 100644 --- a/cpp_src/core/ft/ftdsl.h +++ b/cpp_src/core/ft/ftdsl.h @@ -32,8 +32,8 @@ struct FtDslOpts { struct FtDSLEntry { FtDSLEntry() = default; - FtDSLEntry(std::wstring &&p, FtDslOpts &&o) : pattern{std::move(p)}, opts{std::move(o)} {} - FtDSLEntry(const std::wstring &p, const FtDslOpts &o) : pattern{p}, opts{o} {} + FtDSLEntry(std::wstring&& p, FtDslOpts&& o) : pattern{std::move(p)}, opts{std::move(o)} {} + FtDSLEntry(const std::wstring& p, const FtDslOpts& o) : pattern{p}, opts{o} {} std::wstring pattern; FtDslOpts opts; }; @@ -50,20 +50,20 @@ struct StopWord; class FtDSLQuery : public RVector { public: - FtDSLQuery(const RHashMap &fields, const StopWordsSetT &stopWords, const std::string &extraWordSymbols) noexcept + FtDSLQuery(const RHashMap& fields, const StopWordsSetT& stopWords, const std::string& extraWordSymbols) noexcept : fields_(fields), stopWords_(stopWords), extraWordSymbols_(extraWordSymbols) {} - void parse(std::wstring &utf16str); + void parse(std::wstring& utf16str); void parse(std::string_view q); FtDSLQuery CopyCtx() const noexcept { return {fields_, stopWords_, extraWordSymbols_}; } protected: - void parseFields(std::wstring &utf16str, std::wstring::iterator &it, h_vector &fieldsOpts); + void parseFields(std::wstring& utf16str, std::wstring::iterator& it, h_vector& fieldsOpts); - std::function resolver_; + std::function resolver_; - const RHashMap &fields_; - const StopWordsSetT &stopWords_; - const std::string &extraWordSymbols_; + const RHashMap& fields_; + const StopWordsSetT& stopWords_; + const std::string& extraWordSymbols_; }; } // namespace reindexer diff --git a/cpp_src/core/ft/idrelset.cc b/cpp_src/core/ft/idrelset.cc index 73aeb76eb..c1aeaf9e8 100644 --- a/cpp_src/core/ft/idrelset.cc +++ b/cpp_src/core/ft/idrelset.cc @@ -52,7 +52,9 @@ int IdRelType::Distance(const IdRelType& other, int max) const { int cur = sign ? i->fpos - j->fpos : j->fpos - i->fpos; if (cur < max && cur < (1 << PosType::posBits)) { max = cur; - if (max <= 1) break; + if (max <= 1) { + break; + } } (sign) ? j++ : i++; } @@ -67,7 +69,9 @@ int IdRelType::MinPositionInField(int field) const noexcept { assertrx(lower != pos_.cend() && lower->field() == field); int res = lower->pos(); while (++lower != pos_.cend() && lower->field() == field) { - if (lower->pos() < res) res = lower->pos(); + if (lower->pos() < res) { + res = lower->pos(); + } } return res; } diff --git a/cpp_src/core/ft/idrelset.h b/cpp_src/core/ft/idrelset.h index 3fa22d264..05ed10950 100644 --- a/cpp_src/core/ft/idrelset.h +++ b/cpp_src/core/ft/idrelset.h @@ -144,15 +144,21 @@ class IdRelType { class IdRelSet : public std::vector { public: int Add(VDocIdType id, int pos, int field) { - if (id > max_id_) max_id_ = id; - if (id < min_id_) min_id_ = id; + if (id > max_id_) { + max_id_ = id; + } + if (id < min_id_) { + min_id_ = id; + } auto& last = (empty() || back().Id() != id) ? emplace_back(id) : back(); last.Add(pos, field); return last.size(); } void SimpleCommit() noexcept { - for (auto& val : *this) val.SimpleCommit(); + for (auto& val : *this) { + val.SimpleCommit(); + } } VDocIdType max_id_ = 0; @@ -165,7 +171,9 @@ class IdRelVec : public std::vector { public: size_t heap_size() const noexcept { size_t res = capacity() * sizeof(IdRelType); - for (const auto& id : *this) res += id.HeapSize(); + for (const auto& id : *this) { + res += id.HeapSize(); + } return res; } void erase_back(size_t pos) noexcept { erase(begin() + pos, end()); } diff --git a/cpp_src/core/ft/stemmer.h b/cpp_src/core/ft/stemmer.h index dc2b61aa4..3f7344fb2 100644 --- a/cpp_src/core/ft/stemmer.h +++ b/cpp_src/core/ft/stemmer.h @@ -8,13 +8,13 @@ namespace reindexer { using std::mutex; class stemmer { public: - stemmer(const char *lang = "en") { stemmer_ = sb_stemmer_new(lang, "UTF_8"); } - stemmer(const stemmer &) = delete; - stemmer(stemmer &&other) noexcept { + stemmer(const char* lang = "en") { stemmer_ = sb_stemmer_new(lang, "UTF_8"); } + stemmer(const stemmer&) = delete; + stemmer(stemmer&& other) noexcept { stemmer_ = other.stemmer_; other.stemmer_ = nullptr; } - stemmer &operator=(stemmer &&other) noexcept { + stemmer& operator=(stemmer&& other) noexcept { if (this != &other) { stemmer_ = other.stemmer_; other.stemmer_ = nullptr; @@ -23,14 +23,14 @@ class stemmer { } ~stemmer() { sb_stemmer_delete(stemmer_); } - void stem(const std::string &src, std::string &dst) { + void stem(const std::string& src, std::string& dst) { std::lock_guard lock(lock_); - auto res = sb_stemmer_stem(stemmer_, reinterpret_cast(src.data()), src.length()); - dst.assign(reinterpret_cast(res)); + auto res = sb_stemmer_stem(stemmer_, reinterpret_cast(src.data()), src.length()); + dst.assign(reinterpret_cast(res)); } - sb_stemmer *stemmer_ = nullptr; + sb_stemmer* stemmer_ = nullptr; std::mutex lock_; }; diff --git a/cpp_src/core/ft/stopwords/stop.h b/cpp_src/core/ft/stopwords/stop.h index bda361eae..8860c32c4 100644 --- a/cpp_src/core/ft/stopwords/stop.h +++ b/cpp_src/core/ft/stopwords/stop.h @@ -1,6 +1,6 @@ #pragma once namespace reindexer { -extern const char *stop_words_ru[]; -extern const char *stop_words_en[]; +extern const char* stop_words_ru[]; +extern const char* stop_words_en[]; } // namespace reindexer \ No newline at end of file diff --git a/cpp_src/core/ft/stopwords/stop_en.cc b/cpp_src/core/ft/stopwords/stop_en.cc index 604f64701..8caf56a90 100644 --- a/cpp_src/core/ft/stopwords/stop_en.cc +++ b/cpp_src/core/ft/stopwords/stop_en.cc @@ -1,15 +1,15 @@ namespace reindexer { -const char *stop_words_en[] = { - "a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", - "aren", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", - "by", "can", "cannot", "could", "couldn", "did", "didn", "do", "does", "doesn", "doing", "dont", - "down", "during", "each", "few", "for", "from", "further", "had", "hadnt", "has", "hasnt", "have", - "havent", "having", "he", "hed", "hell", "hes", "her", "here", "hers", "herself", "him", "himself", - "his", "how", "hows", "i", "id", "im", "if", "in", "into", "is", "it", "its", - "itself", "me", "more", "most", "must", "my", "myself", "no", "nor", "not", "of", "off", - "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", - "same", "she", "should", "so", "some", "such", "than", "that", "the", "their", "theirs", "them", - "themselves", "then", "there", "these", "they", "this", "those", "through", "to", "too", "under", "until", - "up", "very", "was", "we", "were", "what", "when", "where", "which", "while", "who", "whom", - "why", "with", "would", "you", "your", "yours", "yourself", "yourselves", nullptr}; +const char* stop_words_en[] = { + "a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", + "aren", "as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", + "by", "can", "cannot", "could", "couldn", "did", "didn", "do", "does", "doesn", "doing", "dont", + "down", "during", "each", "few", "for", "from", "further", "had", "hadnt", "has", "hasnt", "have", + "havent", "having", "he", "hed", "hell", "hes", "her", "here", "hers", "herself", "him", "himself", + "his", "how", "hows", "i", "id", "im", "if", "in", "into", "is", "it", "its", + "itself", "me", "more", "most", "must", "my", "myself", "no", "nor", "not", "of", "off", + "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over", "own", + "same", "she", "should", "so", "some", "such", "than", "that", "the", "their", "theirs", "them", + "themselves", "then", "there", "these", "they", "this", "those", "through", "to", "too", "under", "until", + "up", "very", "was", "we", "were", "what", "when", "where", "which", "while", "who", "whom", + "why", "with", "would", "you", "your", "yours", "yourself", "yourselves", nullptr}; } diff --git a/cpp_src/core/ft/stopwords/stop_ru.cc b/cpp_src/core/ft/stopwords/stop_ru.cc index 5b1b26d98..659bfd905 100644 --- a/cpp_src/core/ft/stopwords/stop_ru.cc +++ b/cpp_src/core/ft/stopwords/stop_ru.cc @@ -1,5 +1,5 @@ namespace reindexer { -const char *stop_words_ru[] = { +const char* stop_words_ru[] = { // clang-format off "а", "е", diff --git a/cpp_src/core/ft/typos.cc b/cpp_src/core/ft/typos.cc index 75e412897..65593d860 100644 --- a/cpp_src/core/ft/typos.cc +++ b/cpp_src/core/ft/typos.cc @@ -5,8 +5,8 @@ namespace reindexer { template -static void mktyposInternal(typos_context *ctx, const std::wstring &word, int maxTyposLen, const typos_context::CallBack &callback, - typos_context::TyposVec &positions) { +static void mktyposInternal(typos_context* ctx, const std::wstring& word, int maxTyposLen, const typos_context::CallBack& callback, + typos_context::TyposVec& positions) { static_assert(level <= typos_context::TyposVec::capacity(), "Positions array must be able to store all the typos"); if constexpr (level == 0) { return; @@ -45,7 +45,7 @@ static void mktyposInternal(typos_context *ctx, const std::wstring &word, int ma } } -void mktypos(typos_context *ctx, const std::wstring &word, int level, int maxTyposLen, const typos_context::CallBack &callback) { +void mktypos(typos_context* ctx, const std::wstring& word, int level, int maxTyposLen, const typos_context::CallBack& callback) { utf16_to_utf8(word, ctx->typo); typos_context::TyposVec positions; callback(ctx->typo, level, positions); @@ -64,7 +64,7 @@ void mktypos(typos_context *ctx, const std::wstring &word, int level, int maxTyp } } -void mktypos(typos_context *ctx, std::string_view word, int level, int maxTyposLen, const typos_context::CallBack &callback) { +void mktypos(typos_context* ctx, std::string_view word, int level, int maxTyposLen, const typos_context::CallBack& callback) { ctx->typo.assign(word.begin(), word.end()); utf8_to_utf16(ctx->typo, ctx->utf16Word); typos_context::TyposVec positions; diff --git a/cpp_src/core/ft/typos.h b/cpp_src/core/ft/typos.h index 7f0059ac7..50f045566 100644 --- a/cpp_src/core/ft/typos.h +++ b/cpp_src/core/ft/typos.h @@ -13,13 +13,13 @@ struct typos_context { public: using value_type = int8_t; using size_type = uint8_t; - using const_iterator = const value_type *; + using const_iterator = const value_type*; static_assert(std::numeric_limits::max() >= kMaxTypoLenLimit, "'Positions' array must be able to store any available typos postions"); TyposVec() noexcept = default; - TyposVec(const TyposVec &o) noexcept = default; + TyposVec(const TyposVec& o) noexcept = default; void emplace_back(value_type v) { if (size_ >= kMaxTyposInWord) { @@ -38,19 +38,19 @@ struct typos_context { const_iterator begin() const noexcept { return arr_; } const_iterator end() const noexcept { return arr_ + size_; } value_type operator[](size_type pos) const { return arr_[pos]; } - TyposVec &operator=(const TyposVec &o) noexcept = default; + TyposVec& operator=(const TyposVec& o) noexcept = default; private: value_type arr_[kMaxTyposInWord]; size_type size_ = 0; }; - using CallBack = std::function; + using CallBack = std::function; std::wstring utf16Word, utf16Typo; std::string typo; }; -void mktypos(typos_context *ctx, const std::wstring &word, int level, int maxTyposLen, const typos_context::CallBack &callback); -void mktypos(typos_context *ctx, std::string_view word, int level, int maxTyposLen, const typos_context::CallBack &callback); +void mktypos(typos_context* ctx, const std::wstring& word, int level, int maxTyposLen, const typos_context::CallBack& callback); +void mktypos(typos_context* ctx, std::string_view word, int level, int maxTyposLen, const typos_context::CallBack& callback); } // namespace reindexer diff --git a/cpp_src/core/idset.cc b/cpp_src/core/idset.cc index 501c692f5..fd2c05ad4 100644 --- a/cpp_src/core/idset.cc +++ b/cpp_src/core/idset.cc @@ -5,7 +5,9 @@ namespace reindexer { std::string IdSetPlain::Dump() const { std::string buf = "["; - for (int i = 0; i < static_cast(size()); i++) buf += std::to_string((*this)[i]) + " "; + for (int i = 0; i < static_cast(size()); i++) { + buf += std::to_string((*this)[i]) + " "; + } buf += "]"; @@ -15,7 +17,9 @@ std::string IdSetPlain::Dump() const { std::ostream& operator<<(std::ostream& os, const IdSetPlain& idset) { os << '['; for (auto b = idset.begin(), it = b, e = idset.end(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << *it; } return os << ']'; diff --git a/cpp_src/core/idset.h b/cpp_src/core/idset.h index df16e24d3..af1b7d44b 100644 --- a/cpp_src/core/idset.h +++ b/cpp_src/core/idset.h @@ -69,15 +69,15 @@ class IdSetPlain : protected base_idset { bool IsEmpty() const noexcept { return empty(); } size_t Size() const noexcept { return size(); } size_t BTreeSize() const noexcept { return 0; } - const base_idsetset *BTree() const noexcept { return nullptr; } + const base_idsetset* BTree() const noexcept { return nullptr; } void ReserveForSorted(int sortedIdxCount) { reserve(size() * (sortedIdxCount + 1)); } std::string Dump() const; protected: - IdSetPlain(base_idset &&idset) noexcept : base_idset(std::move(idset)) {} + IdSetPlain(base_idset&& idset) noexcept : base_idset(std::move(idset)) {} }; -std::ostream &operator<<(std::ostream &, const IdSetPlain &); +std::ostream& operator<<(std::ostream&, const IdSetPlain&); // maxmimum size of idset without building btree const int kMaxPlainIdsetSize = 16; @@ -88,10 +88,10 @@ class IdSet : public IdSetPlain { public: using Ptr = intrusive_ptr>; IdSet() noexcept : usingBtree_(false) {} - IdSet(const IdSet &other) + IdSet(const IdSet& other) : IdSetPlain(other), set_(!other.set_ ? nullptr : new base_idsetset(*other.set_)), usingBtree_(other.usingBtree_.load()) {} - IdSet(IdSet &&other) noexcept : IdSetPlain(std::move(other)), set_(std::move(other.set_)), usingBtree_(other.usingBtree_.load()) {} - IdSet &operator=(IdSet &&other) noexcept { + IdSet(IdSet&& other) noexcept : IdSetPlain(std::move(other)), set_(std::move(other.set_)), usingBtree_(other.usingBtree_.load()) {} + IdSet& operator=(IdSet&& other) noexcept { if (&other != this) { IdSetPlain::operator=(std::move(other)); set_ = std::move(other.set_); @@ -99,7 +99,7 @@ class IdSet : public IdSetPlain { } return *this; } - IdSet &operator=(const IdSet &other) { + IdSet& operator=(const IdSet& other) { if (&other != this) { IdSetPlain::operator=(other); set_.reset(!other.set_ ? nullptr : new base_idsetset(*other.set_)); @@ -107,7 +107,7 @@ class IdSet : public IdSetPlain { } return *this; } - static Ptr BuildFromUnsorted(base_idset &&ids) { + static Ptr BuildFromUnsorted(base_idset&& ids) { boost::sort::pdqsort_branchless(ids.begin(), ids.end()); ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); // TODO: It would be better to integrate unique into sort return make_intrusive>(std::move(ids)); @@ -166,11 +166,13 @@ class IdSet : public IdSetPlain { } template - void Append(InputIt first, InputIt last, const std::vector &mask, EditMode editMode = Auto) { + void Append(InputIt first, InputIt last, const std::vector& mask, EditMode editMode = Auto) { if (editMode == Unordered) { assertrx(!set_); for (; first != last; ++first) { - if (mask[*first]) push_back(*first); + if (mask[*first]) { + push_back(*first); + } } } else if (editMode == Auto) { if (!set_) { @@ -180,7 +182,9 @@ class IdSet : public IdSetPlain { } assertrx(!size()); for (; first != last; ++first) { - if (mask[*first]) set_->insert(*first); + if (mask[*first]) { + set_->insert(*first); + } } usingBtree_.store(true, std::memory_order_release); } else { @@ -202,7 +206,9 @@ class IdSet : public IdSetPlain { void Commit() { if (!size() && set_) { reserve(set_->size()); - for (auto id : *set_) push_back(id); + for (auto id : *set_) { + push_back(id); + } } usingBtree_.store(false, std::memory_order_release); @@ -211,7 +217,7 @@ class IdSet : public IdSetPlain { bool IsEmpty() const noexcept { return empty() && (!set_ || set_->empty()); } size_t Size() const noexcept { return usingBtree_.load(std::memory_order_acquire) ? set_->size() : size(); } size_t BTreeSize() const noexcept { return set_ ? sizeof(*set_.get()) + set_->size() * sizeof(int) : 0; } - const base_idsetset *BTree() const noexcept { return set_.get(); } + const base_idsetset* BTree() const noexcept { return set_.get(); } void ReserveForSorted(int sortedIdxCount) { reserve(((set_ ? set_->size() : size())) * (sortedIdxCount + 1)); } protected: @@ -220,7 +226,7 @@ class IdSet : public IdSetPlain { template friend class BtreeIndexReverseIteratorImpl; - IdSet(base_idset &&idset) noexcept : IdSetPlain(std::move(idset)), usingBtree_(false) {} + IdSet(base_idset&& idset) noexcept : IdSetPlain(std::move(idset)), usingBtree_(false) {} std::unique_ptr set_; std::atomic usingBtree_; diff --git a/cpp_src/core/idsetcache.h b/cpp_src/core/idsetcache.h index 6acdb92b5..d70d7f266 100644 --- a/cpp_src/core/idsetcache.h +++ b/cpp_src/core/idsetcache.h @@ -10,16 +10,16 @@ namespace reindexer { struct IdSetCacheKey { - IdSetCacheKey(const VariantArray &keys, CondType cond, SortType sort) noexcept : keys(&keys), cond(cond), sort(sort) {} - IdSetCacheKey(const IdSetCacheKey &other) : keys(&hkeys), cond(other.cond), sort(other.sort), hkeys(*other.keys) {} - IdSetCacheKey(IdSetCacheKey &&other) noexcept : keys(&hkeys), cond(other.cond), sort(other.sort) { + IdSetCacheKey(const VariantArray& keys, CondType cond, SortType sort) noexcept : keys(&keys), cond(cond), sort(sort) {} + IdSetCacheKey(const IdSetCacheKey& other) : keys(&hkeys), cond(other.cond), sort(other.sort), hkeys(*other.keys) {} + IdSetCacheKey(IdSetCacheKey&& other) noexcept : keys(&hkeys), cond(other.cond), sort(other.sort) { if (&other.hkeys == other.keys) { hkeys = std::move(other.hkeys); } else { hkeys = *other.keys; } } - IdSetCacheKey &operator=(const IdSetCacheKey &other) { + IdSetCacheKey& operator=(const IdSetCacheKey& other) { if (&other != this) { hkeys = *other.keys; keys = &hkeys; @@ -28,7 +28,7 @@ struct IdSetCacheKey { } return *this; } - IdSetCacheKey &operator=(IdSetCacheKey &&other) noexcept { + IdSetCacheKey& operator=(IdSetCacheKey&& other) noexcept { if (&other != this) { if (&other.hkeys == other.keys) { hkeys = std::move(other.hkeys); @@ -44,14 +44,14 @@ struct IdSetCacheKey { size_t Size() const noexcept { return sizeof(IdSetCacheKey) + keys->size() * sizeof(VariantArray::value_type); } - const VariantArray *keys; + const VariantArray* keys; CondType cond; SortType sort; VariantArray hkeys; }; template -T &operator<<(T &os, const IdSetCacheKey &k) { +T& operator<<(T& os, const IdSetCacheKey& k) { os << "{cond: " << CondTypeToStr(k.cond) << ", sort: " << k.sort << ", keys: "; k.hkeys.Dump(os); return os << '}'; @@ -59,14 +59,14 @@ T &operator<<(T &os, const IdSetCacheKey &k) { struct IdSetCacheVal { IdSetCacheVal() = default; - IdSetCacheVal(IdSet::Ptr &&i) noexcept : ids(std::move(i)) {} + IdSetCacheVal(IdSet::Ptr&& i) noexcept : ids(std::move(i)) {} size_t Size() const noexcept { return ids ? (sizeof(*ids.get()) + ids->heap_size()) : 0; } IdSet::Ptr ids; }; template -T &operator<<(T &os, const IdSetCacheVal &v) { +T& operator<<(T& os, const IdSetCacheVal& v) { if (v.ids) { return os << *v.ids; } else { @@ -75,12 +75,12 @@ T &operator<<(T &os, const IdSetCacheVal &v) { } struct equal_idset_cache_key { - bool operator()(const IdSetCacheKey &lhs, const IdSetCacheKey &rhs) const noexcept { + bool operator()(const IdSetCacheKey& lhs, const IdSetCacheKey& rhs) const noexcept { return lhs.cond == rhs.cond && lhs.sort == rhs.sort && *lhs.keys == *rhs.keys; } }; struct hash_idset_cache_key { - size_t operator()(const IdSetCacheKey &s) const noexcept { return (size_t(s.cond) << 8) ^ (size_t(s.sort) << 16) ^ s.keys->Hash(); } + size_t operator()(const IdSetCacheKey& s) const noexcept { return (size_t(s.cond) << 8) ^ (size_t(s.sort) << 16) ^ s.keys->Hash(); } }; using IdSetCacheBase = LRUCache; @@ -88,9 +88,9 @@ using IdSetCacheBase = LRUCache &s) { + void ClearSorted(const std::bitset& s) { if (s.any()) { - Clear([&s](const IdSetCacheKey &k) { return s.test(k.sort); }); + Clear([&s](const IdSetCacheKey& k) { return s.test(k.sort); }); } } }; diff --git a/cpp_src/core/index/index.cc b/cpp_src/core/index/index.cc index cd3ba6d3c..c7b8a6151 100644 --- a/cpp_src/core/index/index.cc +++ b/cpp_src/core/index/index.cc @@ -75,7 +75,9 @@ void Index::dump(S& os, std::string_view step, std::string_view offset) const { << newOffset << "selectKeyType: " << selectKeyType_.Name() << ",\n" << newOffset << "sortOrders: ["; for (size_t i = 0; i < sortOrders_.size(); ++i) { - if (i != 0) os << ", "; + if (i != 0) { + os << ", "; + } os << sortOrders_[i]; } os << "],\n" << newOffset << "sortId: " << sortId_ << ",\n" << newOffset << "opts: "; diff --git a/cpp_src/core/index/indexordered.cc b/cpp_src/core/index/indexordered.cc index fb416eba9..ba30c2c73 100644 --- a/cpp_src/core/index/indexordered.cc +++ b/cpp_src/core/index/indexordered.cc @@ -8,7 +8,7 @@ namespace reindexer { template -Variant IndexOrdered::Upsert(const Variant &key, IdType id, bool &clearCache) { +Variant IndexOrdered::Upsert(const Variant& key, IdType id, bool& clearCache) { if (key.Type().Is()) { if (this->empty_ids_.Unsorted().Add(id, IdSet::Auto, this->sortedIdxCount_)) { this->cache_.reset(); @@ -21,10 +21,11 @@ Variant IndexOrdered::Upsert(const Variant &key, IdType id, bool &clearCache) auto keyIt = this->idx_map.lower_bound(static_cast(key)); - if (keyIt == this->idx_map.end() || this->idx_map.key_comp()(static_cast(key), keyIt->first)) + if (keyIt == this->idx_map.end() || this->idx_map.key_comp()(static_cast(key), keyIt->first)) { keyIt = this->idx_map.insert(keyIt, {static_cast(key), typename T::mapped_type()}); - else + } else { this->delMemStat(keyIt); + } if (keyIt->second.Unsorted().Add(id, this->opts_.IsPK() ? IdSet::Ordered : IdSet::Auto, this->sortedIdxCount_)) { this->isBuilt_ = false; @@ -38,10 +39,12 @@ Variant IndexOrdered::Upsert(const Variant &key, IdType id, bool &clearCache) } template -SelectKeyResults IndexOrdered::SelectKey(const VariantArray &keys, CondType condition, SortType sortId, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &ctx, const RdxContext &rdxCtx) { +SelectKeyResults IndexOrdered::SelectKey(const VariantArray& keys, CondType condition, SortType sortId, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& ctx, const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); - if (opts.forceComparator) return IndexStore>::SelectKey(keys, condition, sortId, opts, ctx, rdxCtx); + if (opts.forceComparator) { + return IndexStore>::SelectKey(keys, condition, sortId, opts, ctx, rdxCtx); + } // Get set of keys or single key if (!IsOrderedCondition(condition)) { @@ -62,23 +65,31 @@ SelectKeyResults IndexOrdered::SelectKey(const VariantArray &keys, CondType c break; case CondLe: endIt = this->idx_map.lower_bound(static_cast(key1)); - if (endIt != this->idx_map.end() && !this->idx_map.key_comp()(static_cast(key1), endIt->first)) ++endIt; + if (endIt != this->idx_map.end() && !this->idx_map.key_comp()(static_cast(key1), endIt->first)) { + ++endIt; + } break; case CondGt: startIt = this->idx_map.upper_bound(static_cast(key1)); break; case CondGe: startIt = this->idx_map.find(static_cast(key1)); - if (startIt == this->idx_map.end()) startIt = this->idx_map.upper_bound(static_cast(key1)); + if (startIt == this->idx_map.end()) { + startIt = this->idx_map.upper_bound(static_cast(key1)); + } break; case CondRange: { - const auto &key2 = keys[1]; + const auto& key2 = keys[1]; startIt = this->idx_map.find(static_cast(key1)); - if (startIt == this->idx_map.end()) startIt = this->idx_map.upper_bound(static_cast(key1)); + if (startIt == this->idx_map.end()) { + startIt = this->idx_map.upper_bound(static_cast(key1)); + } endIt = this->idx_map.lower_bound(static_cast(key2)); - if (endIt != this->idx_map.end() && !this->idx_map.key_comp()(static_cast(key2), endIt->first)) ++endIt; + if (endIt != this->idx_map.end() && !this->idx_map.key_comp()(static_cast(key2), endIt->first)) { + ++endIt; + } if (endIt != this->idx_map.end() && this->idx_map.key_comp()(endIt->first, static_cast(key1))) { return SelectKeyResults(std::move(res)); @@ -123,12 +134,12 @@ SelectKeyResults IndexOrdered::SelectKey(const VariantArray &keys, CondType c // TODO: use count of items in ns to more clever select plan if (count < 50) { struct { - T *i_map; + T* i_map; SortType sortId; typename T::iterator startIt, endIt; } ctx = {&this->idx_map, sortId, startIt, endIt}; - auto selector = [&ctx, count](SelectKeyResult &res, size_t &idsCount) { + auto selector = [&ctx, count](SelectKeyResult& res, size_t& idsCount) { idsCount = 0; res.reserve(count); for (auto it = ctx.startIt; it != ctx.endIt; ++it) { @@ -158,17 +169,20 @@ SelectKeyResults IndexOrdered::SelectKey(const VariantArray &keys, CondType c } template -void IndexOrdered::MakeSortOrders(UpdateSortedContext &ctx) { +void IndexOrdered::MakeSortOrders(UpdateSortedContext& ctx) { logPrintf(LogTrace, "IndexOrdered::MakeSortOrders (%s)", this->name_); - auto &ids2Sorts = ctx.ids2Sorts(); + auto& ids2Sorts = ctx.ids2Sorts(); size_t totalIds = 0; - for (auto it : ids2Sorts) - if (it != SortIdUnexists) totalIds++; + for (auto it : ids2Sorts) { + if (it != SortIdUnexists) { + totalIds++; + } + } this->sortId_ = ctx.getCurSortId(); this->sortOrders_.resize(totalIds); size_t idx = 0; - for (auto &keyIt : this->idx_map) { + for (auto& keyIt : this->idx_map) { // assert (keyIt.second.size()); for (auto id : keyIt.second.Unsorted()) { if (id >= int(ids2Sorts.size()) || ids2Sorts[id] == SortIdUnexists) { @@ -202,8 +216,8 @@ IndexIterator::Ptr IndexOrdered::CreateIterator() const { } template -static std::unique_ptr IndexOrdered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +static std::unique_ptr IndexOrdered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { switch (idef.Type()) { case IndexIntBTree: return std::make_unique>>(idef, std::move(payloadType), std::move(fields), cacheCfg); @@ -239,8 +253,8 @@ static std::unique_ptr IndexOrdered_New(const IndexDef &idef, PayloadType } // NOLINTBEGIN(*cplusplus.NewDeleteLeaks) -std::unique_ptr IndexOrdered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr IndexOrdered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { return (idef.opts_.IsPK() || idef.opts_.IsDense()) ? IndexOrdered_New(idef, std::move(payloadType), std::move(fields), cacheCfg) : IndexOrdered_New(idef, std::move(payloadType), std::move(fields), cacheCfg); diff --git a/cpp_src/core/index/indexordered.h b/cpp_src/core/index/indexordered.h index a12928024..f0d0e25ad 100644 --- a/cpp_src/core/index/indexordered.h +++ b/cpp_src/core/index/indexordered.h @@ -10,19 +10,19 @@ class IndexOrdered : public IndexUnordered { using ref_type = typename IndexUnordered::ref_type; using key_type = typename IndexUnordered::key_type; - IndexOrdered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, const NamespaceCacheConfigData &cacheCfg) + IndexOrdered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg) : IndexUnordered(idef, std::move(payloadType), std::move(fields), cacheCfg) {} - SelectKeyResults SelectKey(const VariantArray &keys, CondType condition, SortType stype, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &ctx, const RdxContext &) override; - Variant Upsert(const Variant &key, IdType id, bool &clearCache) override; - void MakeSortOrders(UpdateSortedContext &ctx) override; + SelectKeyResults SelectKey(const VariantArray& keys, CondType condition, SortType stype, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& ctx, const RdxContext&) override; + Variant Upsert(const Variant& key, IdType id, bool& clearCache) override; + void MakeSortOrders(UpdateSortedContext& ctx) override; IndexIterator::Ptr CreateIterator() const override; std::unique_ptr Clone() const override { return std::make_unique>(*this); } bool IsOrdered() const noexcept override { return true; } }; -std::unique_ptr IndexOrdered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg); +std::unique_ptr IndexOrdered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg); } // namespace reindexer diff --git a/cpp_src/core/index/indexstore.cc b/cpp_src/core/index/indexstore.cc index 0d1ac79df..1fc21dcad 100644 --- a/cpp_src/core/index/indexstore.cc +++ b/cpp_src/core/index/indexstore.cc @@ -7,14 +7,14 @@ namespace reindexer { template <> -IndexStore::IndexStore(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields) +IndexStore::IndexStore(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields) : Index(idef, std::move(payloadType), std::move(fields)) { keyType_ = selectKeyType_ = KeyValueType::Double{}; opts_.Array(true); } template <> -void IndexStore::Delete(const Variant &key, IdType /*id*/, StringsHolder &strHolder, bool & /*clearCache*/) { +void IndexStore::Delete(const Variant& key, IdType /*id*/, StringsHolder& strHolder, bool& /*clearCache*/) { assertrx_dbg(!IsFulltext()); if (key.Type().Is()) { return; @@ -36,26 +36,28 @@ void IndexStore::Delete(const Variant &key, IdType /*id*/, StringsHo } } template -void IndexStore::Delete(const Variant & /*key*/, IdType /* id */, StringsHolder &, bool & /*clearCache*/) { +void IndexStore::Delete(const Variant& /*key*/, IdType /* id */, StringsHolder&, bool& /*clearCache*/) { assertrx_dbg(!IsFulltext()); } template -void IndexStore::Delete(const VariantArray &keys, IdType id, StringsHolder &strHolder, bool &clearCache) { +void IndexStore::Delete(const VariantArray& keys, IdType id, StringsHolder& strHolder, bool& clearCache) { if (keys.empty()) { Delete(Variant{}, id, strHolder, clearCache); } else { - for (const auto &key : keys) Delete(key, id, strHolder, clearCache); + for (const auto& key : keys) { + Delete(key, id, strHolder, clearCache); + } } } template <> -void IndexStore::Delete(const VariantArray & /*keys*/, IdType /*id*/, StringsHolder &, bool & /*clearCache*/) { +void IndexStore::Delete(const VariantArray& /*keys*/, IdType /*id*/, StringsHolder&, bool& /*clearCache*/) { assertrx(0); } template <> -Variant IndexStore::Upsert(const Variant &key, IdType id, bool & /*clearCache*/) { +Variant IndexStore::Upsert(const Variant& key, IdType id, bool& /*clearCache*/) { assertrx_dbg(!IsFulltext()); if (key.Type().Is()) { return Variant(); @@ -85,12 +87,12 @@ Variant IndexStore::Upsert(const Variant &key, IdType id, bool & /*c } template <> -Variant IndexStore::Upsert(const Variant &key, IdType /*id*/, bool & /*clearCache*/) { +Variant IndexStore::Upsert(const Variant& key, IdType /*id*/, bool& /*clearCache*/) { return key; } template -Variant IndexStore::Upsert(const Variant &key, IdType id, bool & /*clearCache*/) { +Variant IndexStore::Upsert(const Variant& key, IdType id, bool& /*clearCache*/) { if (!opts_.IsArray() && !opts_.IsDense() && !opts_.IsSparse() && !key.Type().Is()) { idx_data.resize(std::max(id + 1, IdType(idx_data.size()))); idx_data[id] = static_cast(key); @@ -99,17 +101,19 @@ Variant IndexStore::Upsert(const Variant &key, IdType id, bool & /*clearCache } template -void IndexStore::Upsert(VariantArray &result, const VariantArray &keys, IdType id, bool &clearCache) { +void IndexStore::Upsert(VariantArray& result, const VariantArray& keys, IdType id, bool& clearCache) { if (keys.empty()) { Upsert(Variant{}, id, clearCache); } else { result.reserve(keys.size()); - for (const auto &key : keys) result.emplace_back(Upsert(key, id, clearCache)); + for (const auto& key : keys) { + result.emplace_back(Upsert(key, id, clearCache)); + } } } template <> -void IndexStore::Upsert(VariantArray & /*result*/, const VariantArray & /*keys*/, IdType /*id*/, bool & /*clearCache*/) { +void IndexStore::Upsert(VariantArray& /*result*/, const VariantArray& /*keys*/, IdType /*id*/, bool& /*clearCache*/) { assertrx(0); } @@ -119,8 +123,8 @@ void IndexStore::Commit() { } template -SelectKeyResults IndexStore::SelectKey(const VariantArray &keys, CondType condition, SortType /*sortId*/, Index::SelectOpts sopts, - const BaseFunctionCtx::Ptr & /*ctx*/, const RdxContext &rdxCtx) { +SelectKeyResults IndexStore::SelectKey(const VariantArray& keys, CondType condition, SortType /*sortId*/, Index::SelectOpts sopts, + const BaseFunctionCtx::Ptr& /*ctx*/, const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); if (condition == CondEmpty && !this->opts_.IsArray() && !this->opts_.IsSparse()) { throw Error(errParams, "The 'is NULL' condition is suported only by 'sparse' or 'array' indexes"); @@ -136,7 +140,7 @@ SelectKeyResults IndexStore::SelectKey(const VariantArray &keys, CondType con } template -IndexMemStat IndexStore::GetMemStat(const RdxContext &) { +IndexMemStat IndexStore::GetMemStat(const RdxContext&) { IndexMemStat ret = memStat_; ret.name = name_; ret.uniqKeysCount = str_map.size(); @@ -146,26 +150,30 @@ IndexMemStat IndexStore::GetMemStat(const RdxContext &) { template template -void IndexStore::dump(S &os, std::string_view step, std::string_view offset) const { +void IndexStore::dump(S& os, std::string_view step, std::string_view offset) const { std::string newOffset{offset}; newOffset += step; os << "{\n" << newOffset << ": "; Index::Dump(os, step, newOffset); os << ",\n" << newOffset << "str_map: {"; for (auto b = str_map.begin(), it = b, e = str_map.end(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << '{' << (*it).first << ": " << (*it).second << '}'; } os << "},\n" << newOffset << "idx_data: ["; for (auto b = idx_data.cbegin(), it = b, e = idx_data.cend(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << *it; } os << "]\n" << offset << '}'; } template -void IndexStore::AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue &q) { +void IndexStore::AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue& q) { if constexpr (HasAddTask::value) { str_map.add_destroy_task(&q); } @@ -177,7 +185,7 @@ bool IndexStore::shouldHoldValueInStrMap() const noexcept { return this->opts_.GetCollateMode() != CollateNone || Type() == IndexStrStore; } -std::unique_ptr IndexStore_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields) { +std::unique_ptr IndexStore_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields) { switch (idef.Type()) { case IndexBool: return std::make_unique>(idef, std::move(payloadType), std::move(fields)); diff --git a/cpp_src/core/index/indexstore.h b/cpp_src/core/index/indexstore.h index 18e17f542..f9e26d82a 100644 --- a/cpp_src/core/index/indexstore.h +++ b/cpp_src/core/index/indexstore.h @@ -8,29 +8,29 @@ namespace reindexer { template class IndexStore : public Index { public: - IndexStore(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields) + IndexStore(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields) : Index(idef, std::move(payloadType), std::move(fields)) { static T a; keyType_ = selectKeyType_ = Variant(a).Type(); } - Variant Upsert(const Variant &key, IdType id, bool &clearCache) override; - void Upsert(VariantArray &result, const VariantArray &keys, IdType id, bool &clearCache) override; - void Delete(const Variant &key, IdType id, StringsHolder &, bool &clearCache) override; - void Delete(const VariantArray &keys, IdType id, StringsHolder &, bool &clearCache) override; - SelectKeyResults SelectKey(const VariantArray &keys, CondType condition, SortType stype, Index::SelectOpts res_type, - const BaseFunctionCtx::Ptr &ctx, const RdxContext &) override; + Variant Upsert(const Variant& key, IdType id, bool& clearCache) override; + void Upsert(VariantArray& result, const VariantArray& keys, IdType id, bool& clearCache) override; + void Delete(const Variant& key, IdType id, StringsHolder&, bool& clearCache) override; + void Delete(const VariantArray& keys, IdType id, StringsHolder&, bool& clearCache) override; + SelectKeyResults SelectKey(const VariantArray& keys, CondType condition, SortType stype, Index::SelectOpts res_type, + const BaseFunctionCtx::Ptr& ctx, const RdxContext&) override; void Commit() override; - void UpdateSortedIds(const UpdateSortedContext & /*ctx*/) override {} + void UpdateSortedIds(const UpdateSortedContext& /*ctx*/) override {} std::unique_ptr Clone() const override { return std::make_unique>(*this); } - IndexMemStat GetMemStat(const RdxContext &) override; + IndexMemStat GetMemStat(const RdxContext&) override; bool HoldsStrings() const noexcept override { return std::is_same_v || std::is_same_v; } - void Dump(std::ostream &os, std::string_view step = " ", std::string_view offset = "") const override { dump(os, step, offset); } - virtual void AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue &) override; + void Dump(std::ostream& os, std::string_view step = " ", std::string_view offset = "") const override { dump(os, step, offset); } + virtual void AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue&) override; virtual bool IsDestroyPartSupported() const noexcept override final { return true; } virtual bool IsUuid() const noexcept override final { return std::is_same_v; } - virtual void ReconfigureCache(const NamespaceCacheConfigData &) override {} - const void *ColumnData() const noexcept override final { return idx_data.size() ? idx_data.data() : nullptr; } + virtual void ReconfigureCache(const NamespaceCacheConfigData&) override {} + const void* ColumnData() const noexcept override final { return idx_data.size() ? idx_data.data() : nullptr; } template struct HasAddTask : std::false_type {}; @@ -49,12 +49,12 @@ class IndexStore : public Index { bool shouldHoldValueInStrMap() const noexcept; template - void dump(S &os, std::string_view step, std::string_view offset) const; + void dump(S& os, std::string_view step, std::string_view offset) const; }; template <> -IndexStore::IndexStore(const IndexDef &, PayloadType &&, FieldsSet &&); +IndexStore::IndexStore(const IndexDef&, PayloadType&&, FieldsSet&&); -std::unique_ptr IndexStore_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&); +std::unique_ptr IndexStore_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&&); } // namespace reindexer diff --git a/cpp_src/core/index/indextext/fastindextext.cc b/cpp_src/core/index/indextext/fastindextext.cc index c98c4ae40..7e56292de 100644 --- a/cpp_src/core/index/indextext/fastindextext.cc +++ b/cpp_src/core/index/indextext/fastindextext.cc @@ -10,7 +10,7 @@ namespace { // Available stemmers for languages -const char *stemLangs[] = {"en", "ru", "nl", "fin", "de", "da", "fr", "it", "hu", "no", "pt", "ro", "es", "sv", "tr", nullptr}; +const char* stemLangs[] = {"en", "ru", "nl", "fin", "de", "da", "fr", "it", "hu", "no", "pt", "ro", "es", "sv", "tr", nullptr}; } // namespace namespace reindexer { @@ -19,7 +19,7 @@ using std::chrono::duration_cast; using std::chrono::milliseconds; template -void FastIndexText::initHolder(FtFastConfig &cfg) { +void FastIndexText::initHolder(FtFastConfig& cfg) { switch (cfg.optimization) { case FtFastConfig::Optimization::Memory: holder_.reset(new DataHolder); @@ -34,14 +34,14 @@ void FastIndexText::initHolder(FtFastConfig &cfg) { holder_->translit_.reset(new Translit); holder_->kbLayout_.reset(new KbLayout); holder_->synonyms_.reset(new Synonyms); - for (const char **lang = stemLangs; *lang; ++lang) { + for (const char** lang = stemLangs; *lang; ++lang) { holder_->stemmers_.emplace(*lang, *lang); } holder_->SetConfig(&cfg); } template -Variant FastIndexText::Upsert(const Variant &key, IdType id, bool &clearCache) { +Variant FastIndexText::Upsert(const Variant& key, IdType id, bool& clearCache) { if rx_unlikely (key.Type().Is()) { if (this->empty_ids_.Unsorted().Add(id, IdSet::Auto, 0)) { this->isBuilt_ = false; @@ -59,7 +59,9 @@ Variant FastIndexText::Upsert(const Variant &key, IdType id, bool &clearCache } if (keyIt->second.Unsorted().Add(id, this->opts_.IsPK() ? IdSet::Ordered : IdSet::Auto, 0)) { this->isBuilt_ = false; - if (this->cache_ft_) this->cache_ft_->Clear(); + if (this->cache_ft_) { + this->cache_ft_->Clear(); + } clearCache = true; } this->addMemStat(keyIt); @@ -68,7 +70,7 @@ Variant FastIndexText::Upsert(const Variant &key, IdType id, bool &clearCache } template -void FastIndexText::Delete(const Variant &key, IdType id, StringsHolder &strHolder, bool &clearCache) { +void FastIndexText::Delete(const Variant& key, IdType id, StringsHolder& strHolder, bool& clearCache) { if rx_unlikely (key.Type().Is()) { this->empty_ids_.Unsorted().Erase(id); // ignore result this->isBuilt_ = false; @@ -76,7 +78,9 @@ void FastIndexText::Delete(const Variant &key, IdType id, StringsHolder &strH } auto keyIt = this->idx_map.find(static_cast(key)); - if (keyIt == this->idx_map.end()) return; + if (keyIt == this->idx_map.end()) { + return; + } this->isBuilt_ = false; this->delMemStat(keyIt); @@ -105,12 +109,14 @@ void FastIndexText::Delete(const Variant &key, IdType id, StringsHolder &strH if (this->KeyType().template Is() && this->opts_.GetCollateMode() != CollateNone) { IndexStore>::Delete(key, id, strHolder, clearCache); } - if (this->cache_ft_) this->cache_ft_->Clear(); + if (this->cache_ft_) { + this->cache_ft_->Clear(); + } clearCache = true; } template -IndexMemStat FastIndexText::GetMemStat(const RdxContext &ctx) { +IndexMemStat FastIndexText::GetMemStat(const RdxContext& ctx) { auto ret = IndexUnordered::GetMemStat(ctx); contexted_shared_lock lck(this->mtx_, ctx); @@ -120,15 +126,15 @@ IndexMemStat FastIndexText::GetMemStat(const RdxContext &ctx) { } template -IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTransaction, FtMergeStatuses &&statuses, - FtUseExternStatuses useExternSt, const RdxContext &rdxCtx) { +IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery&& dsl, bool inTransaction, FtMergeStatuses&& statuses, + FtUseExternStatuses useExternSt, const RdxContext& rdxCtx) { fctx->GetData()->extraWordSymbols_ = this->getConfig()->extraWordSymbols; fctx->GetData()->isWordPositions_ = true; MergeData mergeData; switch (holder_->cfg_->optimization) { case FtFastConfig::Optimization::Memory: { - DataHolder *d = dynamic_cast *>(holder_.get()); + DataHolder* d = dynamic_cast*>(holder_.get()); assertrx_throw(d); Selecter selecter{*d, this->Fields().size(), fctx->NeedArea(), holder_->cfg_->maxAreasInDoc}; if (useExternSt == FtUseExternStatuses::No) { @@ -139,7 +145,7 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr break; } case FtFastConfig::Optimization::CPU: { - DataHolder *d = dynamic_cast *>(holder_.get()); + DataHolder* d = dynamic_cast*>(holder_.get()); assertrx_throw(d); Selecter selecter{*d, this->Fields().size(), fctx->NeedArea(), holder_->cfg_->maxAreasInDoc}; if (useExternSt == FtUseExternStatuses::No) { @@ -155,7 +161,7 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr // convert vids(uniq documents id) to ids (real ids) IdSet::Ptr mergedIds = make_intrusive>(); - auto &holder = *this->holder_; + auto& holder = *this->holder_; if (mergeData.empty()) { return mergedIds; @@ -164,13 +170,15 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr const double scalingFactor = mergeData.maxRank > 255 ? 255.0 / mergeData.maxRank : 1.0; const int minRelevancy = getConfig()->minRelevancy * 100 * scalingFactor; size_t releventDocs = 0; - for (auto &vid : mergeData) { - auto &vdoc = holder.vdocs_[vid.id]; + for (auto& vid : mergeData) { + auto& vdoc = holder.vdocs_[vid.id]; if (!vdoc.keyEntry) { continue; } vid.proc *= scalingFactor; - if (vid.proc <= minRelevancy) break; + if (vid.proc <= minRelevancy) { + break; + } assertrx_throw(!vdoc.keyEntry->Unsorted().empty()); cnt += vdoc.keyEntry->Sorted(0).size(); @@ -182,13 +190,13 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr if (!fctx->NeedArea()) { if (useExternSt == FtUseExternStatuses::No) { appendMergedIds(mergeData, releventDocs, - [&fctx, &mergedIds](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo &vid) { + [&fctx, &mergedIds](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo& vid) { fctx->Add(ebegin, eend, vid.proc); mergedIds->Append(ebegin, eend, IdSet::Unordered); }); } else { appendMergedIds(mergeData, releventDocs, - [&fctx, &mergedIds, &statuses](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo &vid) { + [&fctx, &mergedIds, &statuses](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo& vid) { fctx->Add(ebegin, eend, vid.proc, statuses.rowIds); mergedIds->Append(ebegin, eend, statuses.rowIds, IdSet::Unordered); }); @@ -196,7 +204,7 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr } else { if (useExternSt == FtUseExternStatuses::No) { appendMergedIds(mergeData, releventDocs, - [&fctx, &mergedIds, &mergeData](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo &vid) { + [&fctx, &mergedIds, &mergeData](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo& vid) { assertrx_throw(vid.areaIndex != std::numeric_limits::max()); fctx->Add(ebegin, eend, vid.proc, std::move(mergeData.vectorAreas[vid.areaIndex])); mergedIds->Append(ebegin, eend, IdSet::Unordered); @@ -204,7 +212,7 @@ IdSet::Ptr FastIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery &&dsl, bool inTr } else { appendMergedIds( mergeData, releventDocs, - [&fctx, &mergedIds, &mergeData, &statuses](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo &vid) { + [&fctx, &mergedIds, &mergeData, &statuses](IdSetCRef::iterator ebegin, IdSetCRef::iterator eend, const MergeInfo& vid) { assertrx_throw(vid.areaIndex != std::numeric_limits::max()); fctx->Add(ebegin, eend, vid.proc, statuses.rowIds, std::move(mergeData.vectorAreas[vid.areaIndex])); mergedIds->Append(ebegin, eend, statuses.rowIds, IdSet::Unordered); @@ -253,7 +261,7 @@ void FastIndexText::commitFulltextImpl() { this->holder_->rowId2Vdoc_.clear(); this->holder_->rowId2Vdoc_.reserve(this->holder_->vdocs_.size()); for (size_t i = 0, s = this->holder_->vdocs_.size(); i < s; ++i) { - const auto &vdoc = this->holder_->vdocs_[i]; + const auto& vdoc = this->holder_->vdocs_[i]; if (vdoc.keyEntry) { for (const auto id : vdoc.keyEntry->Unsorted()) { if (static_cast(id) >= this->holder_->rowId2Vdoc_.size()) { @@ -269,11 +277,11 @@ void FastIndexText::commitFulltextImpl() { duration_cast(tm2 - tm0).count(), duration_cast(tm1 - tm0).count(), duration_cast(tm2 - tm1).count()); } - } catch (Error &e) { + } catch (Error& e) { logPrintf(LogError, "FastIndexText::Commit exception: '%s'. Index will be rebuilt on the next query", e.what()); this->holder_->steps.clear(); throw; - } catch (std::exception &e) { + } catch (std::exception& e) { logPrintf(LogError, "FastIndexText::Commit exception: '%s'. Index will be rebuilt on the next query", e.what()); this->holder_->steps.clear(); throw; @@ -286,15 +294,15 @@ void FastIndexText::commitFulltextImpl() { template template -void FastIndexText::buildVdocs(Container &data) { +void FastIndexText::buildVdocs(Container& data) { // buffer strings, for printing non text fields - auto &bufStrs = this->holder_->bufStrs_; + auto& bufStrs = this->holder_->bufStrs_; // array with pointers to docs fields text // Prepare vdocs -> addresable array all docs in the index this->holder_->szCnt = 0; - auto &vdocs = this->holder_->vdocs_; - auto &vdocsTexts = this->holder_->vdocsTexts; + auto& vdocs = this->holder_->vdocs_; + auto& vdocsTexts = this->holder_->vdocsTexts; vdocs.reserve(vdocs.size() + data.size()); vdocsTexts.reserve(data.size()); @@ -329,7 +337,9 @@ void FastIndexText::buildVdocs(Container &data) { #endif if rx_unlikely (getConfig()->logLevel <= LogInfo) { - for (auto &f : vdocsTexts.back()) this->holder_->szCnt += f.first.length(); + for (auto& f : vdocsTexts.back()) { + this->holder_->szCnt += f.first.length(); + } } } if (status == FullRebuild) { @@ -339,11 +349,11 @@ void FastIndexText::buildVdocs(Container &data) { template template -RX_ALWAYS_INLINE void FastIndexText::appendMergedIds(MergeData &mergeData, size_t releventDocs, F &&appender) { - auto &holder = *this->holder_; +RX_ALWAYS_INLINE void FastIndexText::appendMergedIds(MergeData& mergeData, size_t releventDocs, F&& appender) { + auto& holder = *this->holder_; for (size_t i = 0; i < releventDocs; ++i) { - auto &vid = mergeData[i]; - auto &vdoc = holder.vdocs_[vid.id]; + auto& vid = mergeData[i]; + auto& vdoc = holder.vdocs_[vid.id]; if (vdoc.keyEntry) { appender(vdoc.keyEntry->Sorted(0).begin(), vdoc.keyEntry->Sorted(0).end(), vid); } @@ -351,7 +361,7 @@ RX_ALWAYS_INLINE void FastIndexText::appendMergedIds(MergeData &mergeData, si } template -void FastIndexText::initConfig(const FtFastConfig *cfg) { +void FastIndexText::initConfig(const FtFastConfig* cfg) { if (cfg) { this->cfg_.reset(new FtFastConfig(*cfg)); } else { @@ -363,15 +373,15 @@ void FastIndexText::initConfig(const FtFastConfig *cfg) { } template -bool eq_c(Container &c1, Container &c2) { +bool eq_c(Container& c1, Container& c2) { return c1.size() == c2.size() && std::equal(c1.begin(), c1.end(), c2.begin()); } template -void FastIndexText::SetOpts(const IndexOpts &opts) { +void FastIndexText::SetOpts(const IndexOpts& opts) { auto oldCfg = *getConfig(); IndexText::SetOpts(opts); - auto &newCfg = *getConfig(); + auto& newCfg = *getConfig(); if (!eq_c(oldCfg.stopWords, newCfg.stopWords) || oldCfg.stemmers != newCfg.stemmers || oldCfg.maxTypoLen != newCfg.maxTypoLen || oldCfg.enableNumbersSearch != newCfg.enableNumbersSearch || oldCfg.extraWordSymbols != newCfg.extraWordSymbols || @@ -384,24 +394,30 @@ void FastIndexText::SetOpts(const IndexOpts &opts) { this->holder_->Clear(); } this->holder_->status_ = FullRebuild; - if (this->cache_ft_) this->cache_ft_->Clear(); - for (auto &idx : this->idx_map) idx.second.SetVDocID(FtKeyEntryData::ndoc); + if (this->cache_ft_) { + this->cache_ft_->Clear(); + } + for (auto& idx : this->idx_map) { + idx.second.SetVDocID(FtKeyEntryData::ndoc); + } } else { logPrintf(LogInfo, "FulltextIndex config changed, cache cleared"); - if (this->cache_ft_) this->cache_ft_->Clear(); + if (this->cache_ft_) { + this->cache_ft_->Clear(); + } } this->holder_->synonyms_->SetConfig(&newCfg); } template -reindexer::FtPreselectT FastIndexText::FtPreselect(const RdxContext &rdxCtx) { +reindexer::FtPreselectT FastIndexText::FtPreselect(const RdxContext& rdxCtx) { this->build(rdxCtx); return FtMergeStatuses{FtMergeStatuses::Statuses(holder_->vdocs_.size(), FtMergeStatuses::kExcluded), std::vector(holder_->rowId2Vdoc_.size(), false), &holder_->rowId2Vdoc_}; } -std::unique_ptr FastIndexText_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr FastIndexText_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { switch (idef.Type()) { case IndexFastFT: return std::make_unique>>(idef, std::move(payloadType), std::move(fields), diff --git a/cpp_src/core/index/indextext/fastindextext.h b/cpp_src/core/index/indextext/fastindextext.h index ae6f74d5b..054afa650 100644 --- a/cpp_src/core/index/indextext/fastindextext.h +++ b/cpp_src/core/index/indextext/fastindextext.h @@ -18,7 +18,9 @@ class FastIndexText : public IndexText { FastIndexText(const FastIndexText& other) : Base(other) { initConfig(other.getConfig()); - for (auto& idx : this->idx_map) idx.second.SetVDocID(FtKeyEntryData::ndoc); + for (auto& idx : this->idx_map) { + idx.second.SetVDocID(FtKeyEntryData::ndoc); + } } FastIndexText(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg) diff --git a/cpp_src/core/index/indextext/fieldsgetter.h b/cpp_src/core/index/indextext/fieldsgetter.h index 7eccdc7da..300fe4cdc 100644 --- a/cpp_src/core/index/indextext/fieldsgetter.h +++ b/cpp_src/core/index/indextext/fieldsgetter.h @@ -7,10 +7,12 @@ namespace reindexer { class FieldsGetter { public: - FieldsGetter(const FieldsSet &fields, const PayloadType &plt, KeyValueType type) : fields_(fields), plt_(plt), type_(type) {} + FieldsGetter(const FieldsSet& fields, const PayloadType& plt, KeyValueType type) : fields_(fields), plt_(plt), type_(type) {} - RVector, 8> getDocFields(const key_string &doc, std::vector> &) { - if (!utf8::is_valid(doc->cbegin(), doc->cend())) throw Error(errParams, "Invalid UTF8 string in FullText index"); + RVector, 8> getDocFields(const key_string& doc, std::vector>&) { + if (!utf8::is_valid(doc->cbegin(), doc->cend())) { + throw Error(errParams, "Invalid UTF8 string in FullText index"); + } return {{std::string_view(*doc.get()), 0}}; } @@ -18,8 +20,8 @@ class FieldsGetter { VariantArray krefs; // Specific implemetation for composite index - RVector, 8> getDocFields(const PayloadValue &doc, - std::vector> &strsBuf) { + RVector, 8> getDocFields(const PayloadValue& doc, + std::vector>& strsBuf) { ConstPayload pl(plt_, doc); uint32_t fieldPos = 0; @@ -36,9 +38,9 @@ class FieldsGetter { } else { pl.Get(field, krefs); } - for (const Variant &kref : krefs) { + for (const Variant& kref : krefs) { if (!kref.Type().Is()) { - auto &str = strsBuf.emplace_back(std::make_unique(kref.As())); + auto& str = strsBuf.emplace_back(std::make_unique(kref.As())); ret.emplace_back(*str, fieldPos); } else { const std::string_view stringRef(kref); @@ -54,8 +56,8 @@ class FieldsGetter { } private: - const FieldsSet &fields_; - const PayloadType &plt_; + const FieldsSet& fields_; + const PayloadType& plt_; KeyValueType type_; }; diff --git a/cpp_src/core/index/indextext/fuzzyindextext.cc b/cpp_src/core/index/indextext/fuzzyindextext.cc index 8d875ba58..a3ea56d02 100644 --- a/cpp_src/core/index/indextext/fuzzyindextext.cc +++ b/cpp_src/core/index/indextext/fuzzyindextext.cc @@ -22,12 +22,16 @@ IdSet::Ptr FuzzyIndexText::Select(FtCtx::Ptr fctx, FtDSLQuery&& dsl, bool inT size_t counter = 0; for (auto it = result.data_->begin(); it != result.data_->end(); ++it, ++counter) { it->proc_ *= coof; - if (it->proc_ < getConfig()->minOkProc) continue; + if (it->proc_ < getConfig()->minOkProc) { + continue; + } assertrx(it->id_ < this->vdocs_.size()); const auto& id_set = this->vdocs_[it->id_].keyEntry->Sorted(0); fctx->Add(id_set.begin(), id_set.end(), it->proc_); mergedIds->Append(id_set.begin(), id_set.end(), IdSet::Unordered); - if ((counter & 0xFF) == 0 && !inTransaction) ThrowOnCancel(rdxCtx); + if ((counter & 0xFF) == 0 && !inTransaction) { + ThrowOnCancel(rdxCtx); + } } return mergedIds; diff --git a/cpp_src/core/index/indextext/indextext.cc b/cpp_src/core/index/indextext/indextext.cc index dbf99e8d1..6ba1425ed 100644 --- a/cpp_src/core/index/indextext/indextext.cc +++ b/cpp_src/core/index/indextext/indextext.cc @@ -8,7 +8,7 @@ namespace reindexer { template -IndexText::IndexText(const IndexText &other) +IndexText::IndexText(const IndexText& other) : IndexUnordered(other), cache_ft_(std::make_unique(other.cacheMaxSize_, other.hitsToCache_)), cacheMaxSize_(other.cacheMaxSize_), @@ -22,7 +22,7 @@ void IndexText::initSearchers() { size_t jsonPathIdx = 0; if (this->payloadType_) { - const auto &fields = this->Fields(); + const auto& fields = this->Fields(); for (unsigned i = 0, s = fields.size(); i < s; i++) { auto fieldIdx = fields[i]; if (fieldIdx == IndexValueType::SetByJsonPath) { @@ -43,7 +43,7 @@ void IndexText::initSearchers() { } template -void IndexText::SetOpts(const IndexOpts &opts) { +void IndexText::SetOpts(const IndexOpts& opts) { std::string oldCfg = this->opts_.config; this->opts_ = opts; @@ -60,7 +60,7 @@ void IndexText::SetOpts(const IndexOpts &opts) { } template -void IndexText::ReconfigureCache(const NamespaceCacheConfigData &cacheCfg) { +void IndexText::ReconfigureCache(const NamespaceCacheConfigData& cacheCfg) { if (cacheMaxSize_ != cacheCfg.ftIdxCacheSize || hitsToCache_ != cacheCfg.ftIdxHitsToCache) { cacheMaxSize_ = cacheCfg.ftIdxCacheSize; hitsToCache_ = cacheCfg.ftIdxHitsToCache; @@ -72,7 +72,7 @@ void IndexText::ReconfigureCache(const NamespaceCacheConfigData &cacheCfg) { } template -FtCtx::Ptr IndexText::prepareFtCtx(const BaseFunctionCtx::Ptr &ctx) { +FtCtx::Ptr IndexText::prepareFtCtx(const BaseFunctionCtx::Ptr& ctx) { FtCtx::Ptr ftctx = reindexer::static_ctx_pointer_cast(ctx); if rx_unlikely (!ftctx) { throw Error(errParams, "Full text index (%s) may not be used without context", Index::Name()); @@ -82,7 +82,7 @@ FtCtx::Ptr IndexText::prepareFtCtx(const BaseFunctionCtx::Ptr &ctx) { } template -void IndexText::build(const RdxContext &rdxCtx) { +void IndexText::build(const RdxContext& rdxCtx) { smart_lock lck(mtx_, rdxCtx); if (!this->isBuilt_) { // non atomic upgrade mutex to unique @@ -96,8 +96,8 @@ void IndexText::build(const RdxContext &rdxCtx) { // Generic implemetation for string index template -SelectKeyResults IndexText::SelectKey(const VariantArray &keys, CondType condition, SortType, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &ctx, const RdxContext &rdxCtx) { +SelectKeyResults IndexText::SelectKey(const VariantArray& keys, CondType condition, SortType, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& ctx, const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); if rx_unlikely (keys.size() < 1 || (condition != CondEq && condition != CondSet)) { throw Error(errParams, "Full text index (%s) support only EQ or SET condition with 1 or 2 parameter", Index::Name()); @@ -122,7 +122,7 @@ SelectKeyResults IndexText::SelectKey(const VariantArray &keys, CondType cond } template -SelectKeyResults IndexText::resultFromCache(const VariantArray &keys, FtIdSetCache::Iterator &&it, FtCtx::Ptr &ftctx) { +SelectKeyResults IndexText::resultFromCache(const VariantArray& keys, FtIdSetCache::Iterator&& it, FtCtx::Ptr& ftctx) { if rx_unlikely (cfg_->logLevel >= LogInfo) { logPrintf(LogInfo, "Get search results for '%s' in '%s' from cache", keys[0].As(), this->payloadType_ ? this->payloadType_->Name() : ""); @@ -133,9 +133,9 @@ SelectKeyResults IndexText::resultFromCache(const VariantArray &keys, FtIdSet } template -SelectKeyResults IndexText::doSelectKey(const VariantArray &keys, const std::optional &ckey, - FtMergeStatuses &&mergeStatuses, FtUseExternStatuses useExternSt, bool inTransaction, - FtCtx::Ptr ftctx, const RdxContext &rdxCtx) { +SelectKeyResults IndexText::doSelectKey(const VariantArray& keys, const std::optional& ckey, + FtMergeStatuses&& mergeStatuses, FtUseExternStatuses useExternSt, bool inTransaction, + FtCtx::Ptr ftctx, const RdxContext& rdxCtx) { if rx_unlikely (cfg_->logLevel >= LogInfo) { logPrintf(LogInfo, "Searching for '%s' in '%s' %s", keys[0].As(), this->payloadType_ ? this->payloadType_->Name() : "", ckey ? "(will cache)" : ""); @@ -150,12 +150,12 @@ SelectKeyResults IndexText::doSelectKey(const VariantArray &keys, const std:: if (mergedIds) { bool need_put = (useExternSt == FtUseExternStatuses::No) && ckey.has_value(); if (ftctx->NeedArea() && need_put && mergedIds->size()) { - auto config = dynamic_cast(cfg_.get()); + auto config = dynamic_cast(cfg_.get()); if (config && config->maxTotalAreasToCache >= 0) { - auto &d = *ftctx->GetData(); + auto& d = *ftctx->GetData(); size_t totalAreas = 0; assertrx_throw(d.holders_.has_value()); - for (auto &area : d.holders_.value()) { + for (auto& area : d.holders_.value()) { totalAreas += d.area_[area.second].GetAreasCount(); } if (totalAreas > unsigned(config->maxTotalAreasToCache)) { @@ -166,10 +166,10 @@ SelectKeyResults IndexText::doSelectKey(const VariantArray &keys, const std:: if (need_put && mergedIds->size()) { // This areas will be shared via cache, so lazy commit may race auto dPtr = ftctx->GetData(); - auto &d = *dPtr; + auto& d = *dPtr; if (d.holders_.has_value()) { - for (auto &area : d.holders_.value()) { - if (auto &aData = d.area_[area.second]; !aData.IsCommited()) { + for (auto& area : d.holders_.value()) { + if (auto& aData = d.area_[area.second]; !aData.IsCommited()) { aData.Commit(); } } @@ -183,8 +183,8 @@ SelectKeyResults IndexText::doSelectKey(const VariantArray &keys, const std:: } template -SelectKeyResults IndexText::SelectKey(const VariantArray &keys, CondType condition, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &ctx, FtPreselectT &&preselect, const RdxContext &rdxCtx) { +SelectKeyResults IndexText::SelectKey(const VariantArray& keys, CondType condition, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& ctx, FtPreselectT&& preselect, const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); if rx_unlikely (keys.size() < 1 || (condition != CondEq && condition != CondSet)) { throw Error(errParams, "Full text index (%s) support only EQ or SET condition with 1 or 2 parameter", Index::Name()); diff --git a/cpp_src/core/index/indextext/indextext.h b/cpp_src/core/index/indextext/indextext.h index 9580d50c3..65f54d7b0 100644 --- a/cpp_src/core/index/indextext/indextext.h +++ b/cpp_src/core/index/indextext/indextext.h @@ -52,7 +52,9 @@ class IndexText : public IndexUnordered { } void ClearCache() override { Base::ClearCache(); - if (cache_ft_) cache_ft_->Clear(); + if (cache_ft_) { + cache_ft_->Clear(); + } } void ClearCache(const std::bitset& s) override { Base::ClearCache(s); } void MarkBuilt() noexcept override { assertrx(0); } diff --git a/cpp_src/core/index/indexunordered.cc b/cpp_src/core/index/indexunordered.cc index bfd90c2dd..18af49bea 100644 --- a/cpp_src/core/index/indexunordered.cc +++ b/cpp_src/core/index/indexunordered.cc @@ -17,8 +17,8 @@ namespace reindexer { constexpr int kMaxIdsForDistinct = 500; template -IndexUnordered::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), @@ -27,81 +27,81 @@ IndexUnordered::IndexUnordered(const IndexDef &idef, PayloadType &&payloadTyp } template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(idef.opts_.collateOpts_), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(idef.opts_.collateOpts_), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(idef.opts_.collateOpts_), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(idef.opts_.collateOpts_), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(idef.opts_.collateOpts_), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, - FieldsSet &&fields, const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, + FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, - FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, + FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), hitsToCache_(cacheCfg.idxIdsetHitsToCache) {} template <> -IndexUnordered>::IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) +IndexUnordered>::IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) : Base(idef, std::move(payloadType), std::move(fields)), idx_map(PayloadType{Base::GetPayloadType()}, FieldsSet{Base::Fields()}), cacheMaxSize_(cacheCfg.idxIdsetCacheSize), @@ -117,7 +117,7 @@ bool IndexUnordered::HoldsStrings() const noexcept { } template -IndexUnordered::IndexUnordered(const IndexUnordered &other) +IndexUnordered::IndexUnordered(const IndexUnordered& other) : Base(other), idx_map(other.idx_map), cache_(nullptr), @@ -127,29 +127,29 @@ IndexUnordered::IndexUnordered(const IndexUnordered &other) tracker_(other.tracker_) {} template -size_t heap_size(const key_type & /*kt*/) { +size_t heap_size(const key_type& /*kt*/) { return 0; } template <> -size_t heap_size(const key_string &kt) { +size_t heap_size(const key_string& kt) { return kt->heap_size() + sizeof(*kt.get()); } template <> -size_t heap_size(const key_string_with_hash &kt) { +size_t heap_size(const key_string_with_hash& kt) { return kt->heap_size() + sizeof(*kt.get()); } struct DeepClean { template - void operator()(T &v) const { + void operator()(T& v) const { free_node(v.first); free_node(v.second); } template - void free_node(T &v) const { + void free_node(T& v) const { if constexpr (!std::is_const_v) { v = T{}; } @@ -171,7 +171,7 @@ void IndexUnordered::delMemStat(typename T::iterator it) { } template -Variant IndexUnordered::Upsert(const Variant &key, IdType id, bool &clearCache) { +Variant IndexUnordered::Upsert(const Variant& key, IdType id, bool& clearCache) { // reset cache if (key.Type().Is()) { // TODO maybe error or default value if the index is not sparse if (this->empty_ids_.Unsorted().Add(id, IdSet::Auto, this->sortedIdxCount_)) { @@ -203,7 +203,7 @@ Variant IndexUnordered::Upsert(const Variant &key, IdType id, bool &clearCach } template -void IndexUnordered::Delete(const Variant &key, IdType id, StringsHolder &strHolder, bool &clearCache) { +void IndexUnordered::Delete(const Variant& key, IdType id, StringsHolder& strHolder, bool& clearCache) { if (key.Type().Is()) { this->empty_ids_.Unsorted().Erase(id); // ignore result this->isBuilt_ = false; @@ -251,8 +251,8 @@ void IndexUnordered::Delete(const Variant &key, IdType id, StringsHolder &str // WARNING: 'keys' is a key for LRUCache and in some cases (for ordered indexes, for example) can contain values, // which are not correspond to the initial values from queries conditions template -bool IndexUnordered::tryIdsetCache(const VariantArray &keys, CondType condition, SortType sortId, - const std::function &selector, SelectKeyResult &res) { +bool IndexUnordered::tryIdsetCache(const VariantArray& keys, CondType condition, SortType sortId, + const std::function& selector, SelectKeyResult& res) { size_t idsCount; if (!cache_ || IsComposite(this->Type())) { selector(res, idsCount); @@ -282,10 +282,12 @@ bool IndexUnordered::tryIdsetCache(const VariantArray &keys, CondType conditi } template -SelectKeyResults IndexUnordered::SelectKey(const VariantArray &keys, CondType condition, SortType sortId, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &funcCtx, const RdxContext &rdxCtx) { +SelectKeyResults IndexUnordered::SelectKey(const VariantArray& keys, CondType condition, SortType sortId, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& funcCtx, const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); - if (opts.forceComparator) return Base::SelectKey(keys, condition, sortId, opts, funcCtx, rdxCtx); + if (opts.forceComparator) { + return Base::SelectKey(keys, condition, sortId, opts, funcCtx, rdxCtx); + } SelectKeyResult res; @@ -300,15 +302,15 @@ SelectKeyResults IndexUnordered::SelectKey(const VariantArray &keys, CondType case CondEq: case CondSet: { struct { - T *i_map; - const VariantArray &keys; + T* i_map; + const VariantArray& keys; SortType sortId; Index::SelectOpts opts; bool isSparse; } ctx = {&this->idx_map, keys, sortId, opts, this->opts_.IsSparse()}; bool selectorWasSkipped = false; // should return true, if fallback to comparator required - auto selector = [&ctx, &selectorWasSkipped](SelectKeyResult &res, size_t &idsCount) -> bool { + auto selector = [&ctx, &selectorWasSkipped](SelectKeyResult& res, size_t& idsCount) -> bool { idsCount = 0; // Skip this index if there are some other indexes with potentially higher selectivity if (!ctx.opts.distinct && ctx.keys.size() > 1 && 8 * ctx.keys.size() > size_t(ctx.opts.maxIterations) && @@ -317,7 +319,7 @@ SelectKeyResults IndexUnordered::SelectKey(const VariantArray &keys, CondType return true; } res.reserve(ctx.keys.size()); - for (const auto &key : ctx.keys) { + for (const auto& key : ctx.keys) { auto keyIt = ctx.i_map->find(static_cast(key)); if (keyIt != ctx.i_map->end()) { res.emplace_back(keyIt->second, ctx.sortId); @@ -328,7 +330,9 @@ SelectKeyResults IndexUnordered::SelectKey(const VariantArray &keys, CondType res.deferedExplicitSort = SelectKeyResult::IsGenericSortRecommended(res.size(), idsCount, idsCount); // avoid comparator for sparse index - if (ctx.isSparse || !ctx.opts.itemsCountInNamespace) return false; + if (ctx.isSparse || !ctx.opts.itemsCountInNamespace) { + return false; + } // Check selectivity: // if ids count too much (more than maxSelectivityPercentForIdset() of namespace), // and index not optimized, or we have >4 other conditions @@ -371,7 +375,7 @@ SelectKeyResults IndexUnordered::SelectKey(const VariantArray &keys, CondType if (opts.distinct && this->idx_map.size() < kMaxIdsForDistinct) { // TODO change to more clever condition // Get set of any keys res.reserve(this->idx_map.size()); - for (auto &keyIt : this->idx_map) { + for (auto& keyIt : this->idx_map) { res.emplace_back(keyIt.second, sortId); } break; @@ -394,15 +398,19 @@ template void IndexUnordered::Commit() { this->empty_ids_.Unsorted().Commit(); - if (!cache_) cache_.reset(new IdSetCache(cacheMaxSize_, hitsToCache_)); + if (!cache_) { + cache_.reset(new IdSetCache(cacheMaxSize_, hitsToCache_)); + } - if (!tracker_.isUpdated()) return; + if (!tracker_.isUpdated()) { + return; + } logPrintf(LogTrace, "IndexUnordered::Commit (%s) %d uniq keys, %d empty, %s", this->name_, this->idx_map.size(), this->empty_ids_.Unsorted().size(), tracker_.isCompleteUpdated() ? "complete" : "partial"); if (tracker_.isCompleteUpdated()) { - for (auto &keyIt : this->idx_map) { + for (auto& keyIt : this->idx_map) { keyIt.second.Unsorted().Commit(); assertrx(keyIt.second.Unsorted().size()); } @@ -413,11 +421,11 @@ void IndexUnordered::Commit() { } template -void IndexUnordered::UpdateSortedIds(const UpdateSortedContext &ctx) { +void IndexUnordered::UpdateSortedIds(const UpdateSortedContext& ctx) { logPrintf(LogTrace, "IndexUnordered::UpdateSortedIds (%s) %d uniq keys, %d empty", this->name_, this->idx_map.size(), this->empty_ids_.Unsorted().size()); // For all keys in index - for (auto &keyIt : this->idx_map) { + for (auto& keyIt : this->idx_map) { keyIt.second.UpdateSortedIds(ctx); } @@ -428,15 +436,19 @@ template void IndexUnordered::SetSortedIdxCount(int sortedIdxCount) { if (this->sortedIdxCount_ != sortedIdxCount) { this->sortedIdxCount_ = sortedIdxCount; - for (auto &keyIt : idx_map) keyIt.second.Unsorted().ReserveForSorted(this->sortedIdxCount_); + for (auto& keyIt : idx_map) { + keyIt.second.Unsorted().ReserveForSorted(this->sortedIdxCount_); + } } } template -IndexMemStat IndexUnordered::GetMemStat(const RdxContext &ctx) { +IndexMemStat IndexUnordered::GetMemStat(const RdxContext& ctx) { IndexMemStat ret = Base::GetMemStat(ctx); ret.uniqKeysCount = idx_map.size(); - if (cache_) ret.idsetCache = cache_->GetMemStat(); + if (cache_) { + ret.idsetCache = cache_->GetMemStat(); + } ret.trackedUpdatesCount = tracker_.updatesSize(); ret.trackedUpdatesBuckets = tracker_.updatesBuckets(); ret.trackedUpdatesSize = tracker_.allocated(); @@ -446,7 +458,7 @@ IndexMemStat IndexUnordered::GetMemStat(const RdxContext &ctx) { template template -void IndexUnordered::dump(S &os, std::string_view step, std::string_view offset) const { +void IndexUnordered::dump(S& os, std::string_view step, std::string_view offset) const { std::string newOffset{offset}; newOffset += step; os << "{\n" << newOffset << ": "; @@ -456,7 +468,9 @@ void IndexUnordered::dump(S &os, std::string_view step, std::string_view offs std::string secondOffset{newOffset}; secondOffset += step; for (auto b = idx_map.begin(), it = b, e = idx_map.end(); it != e; ++it) { - if (it != b) os << ','; + if (it != b) { + os << ','; + } os << '\n' << secondOffset << '{' << it->first << ": "; it->second.Dump(os, step, secondOffset); os << '}'; @@ -475,7 +489,7 @@ void IndexUnordered::dump(S &os, std::string_view step, std::string_view offs } template -void IndexUnordered::AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue &q) { +void IndexUnordered::AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue& q) { if constexpr (Base::template HasAddTask::value) { idx_map.add_destroy_task(&q); } @@ -483,7 +497,7 @@ void IndexUnordered::AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue } template -void IndexUnordered::ReconfigureCache(const NamespaceCacheConfigData &cacheCfg) { +void IndexUnordered::ReconfigureCache(const NamespaceCacheConfigData& cacheCfg) { if (cacheMaxSize_ != cacheCfg.idxIdsetCacheSize || hitsToCache_ != cacheCfg.idxIdsetHitsToCache) { cacheMaxSize_ = cacheCfg.idxIdsetCacheSize; hitsToCache_ = cacheCfg.idxIdsetHitsToCache; @@ -494,8 +508,8 @@ void IndexUnordered::ReconfigureCache(const NamespaceCacheConfigData &cacheCf } template -static std::unique_ptr IndexUnordered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +static std::unique_ptr IndexUnordered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { switch (idef.Type()) { case IndexIntHash: return std::make_unique>>(idef, std::move(payloadType), std::move(fields), @@ -533,8 +547,8 @@ static std::unique_ptr IndexUnordered_New(const IndexDef &idef, PayloadTy } // NOLINTBEGIN(*cplusplus.NewDeleteLeaks) -std::unique_ptr IndexUnordered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr IndexUnordered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { return (idef.opts_.IsPK() || idef.opts_.IsDense()) ? IndexUnordered_New(idef, std::move(payloadType), std::move(fields), cacheCfg) : IndexUnordered_New(idef, std::move(payloadType), std::move(fields), cacheCfg); diff --git a/cpp_src/core/index/indexunordered.h b/cpp_src/core/index/indexunordered.h index 541fef791..418931c9e 100644 --- a/cpp_src/core/index/indexunordered.h +++ b/cpp_src/core/index/indexunordered.h @@ -26,36 +26,40 @@ class IndexUnordered : public IndexStore> { typename T::key_type>::type>::type>::type; using key_type = StoreIndexKeyType; - IndexUnordered(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, const NamespaceCacheConfigData &cacheCfg); - IndexUnordered(const IndexUnordered &other); + IndexUnordered(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg); + IndexUnordered(const IndexUnordered& other); - Variant Upsert(const Variant &key, IdType id, bool &chearCache) override; - void Delete(const Variant &key, IdType id, StringsHolder &, bool &chearCache) override; - SelectKeyResults SelectKey(const VariantArray &keys, CondType cond, SortType stype, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &ctx, const RdxContext &) override; + Variant Upsert(const Variant& key, IdType id, bool& chearCache) override; + void Delete(const Variant& key, IdType id, StringsHolder&, bool& chearCache) override; + SelectKeyResults SelectKey(const VariantArray& keys, CondType cond, SortType stype, Index::SelectOpts opts, + const BaseFunctionCtx::Ptr& ctx, const RdxContext&) override; void Commit() override; - void UpdateSortedIds(const UpdateSortedContext &) override; + void UpdateSortedIds(const UpdateSortedContext&) override; std::unique_ptr Clone() const override { return std::make_unique>(*this); } - IndexMemStat GetMemStat(const RdxContext &) override; + IndexMemStat GetMemStat(const RdxContext&) override; size_t Size() const noexcept override final { return idx_map.size(); } void SetSortedIdxCount(int sortedIdxCount) override; bool HoldsStrings() const noexcept override; void DestroyCache() override { cache_.reset(); } void ClearCache() override { - if (cache_) cache_->Clear(); + if (cache_) { + cache_->Clear(); + } } - void ClearCache(const std::bitset &s) override { - if (cache_) cache_->ClearSorted(s); + void ClearCache(const std::bitset& s) override { + if (cache_) { + cache_->ClearSorted(s); + } } - void Dump(std::ostream &os, std::string_view step = " ", std::string_view offset = "") const override { dump(os, step, offset); } + void Dump(std::ostream& os, std::string_view step = " ", std::string_view offset = "") const override { dump(os, step, offset); } void EnableUpdatesCountingMode(bool val) noexcept override { tracker_.enableCountingMode(val); } - void AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue &) override; - void ReconfigureCache(const NamespaceCacheConfigData &cacheCfg) override; + void AddDestroyTask(tsl::detail_sparse_hash::ThreadTaskQueue&) override; + void ReconfigureCache(const NamespaceCacheConfigData& cacheCfg) override; protected: - bool tryIdsetCache(const VariantArray &keys, CondType condition, SortType sortId, - const std::function &selector, SelectKeyResult &res); + bool tryIdsetCache(const VariantArray& keys, CondType condition, SortType sortId, + const std::function& selector, SelectKeyResult& res); void addMemStat(typename T::iterator it); void delMemStat(typename T::iterator it); @@ -72,12 +76,12 @@ class IndexUnordered : public IndexStore> { private: template - void dump(S &os, std::string_view step, std::string_view offset) const; + void dump(S& os, std::string_view step, std::string_view offset) const; }; constexpr unsigned maxSelectivityPercentForIdset() noexcept { return 30u; } -std::unique_ptr IndexUnordered_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg); +std::unique_ptr IndexUnordered_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg); } // namespace reindexer diff --git a/cpp_src/core/index/keyentry.h b/cpp_src/core/index/keyentry.h index 169e233c1..1e56711f4 100644 --- a/cpp_src/core/index/keyentry.h +++ b/cpp_src/core/index/keyentry.h @@ -65,11 +65,15 @@ class KeyEntry { if (ids_.size() != 0) { unsigned sortId = 0; while (ids_.capacity() >= ids_.size() * (sortId + 1)) { - if (sortId != 0) os << ", "; + if (sortId != 0) { + os << ", "; + } os << '['; const auto sorted = Sorted(sortId); for (auto b = sorted.begin(), it = b, e = sorted.end(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << *it; } os << ']'; @@ -77,7 +81,9 @@ class KeyEntry { } } os << ']'; - if (!newOffset.empty()) os << '\n' << offset; + if (!newOffset.empty()) { + os << '\n' << offset; + } os << '}'; } diff --git a/cpp_src/core/index/payload_map.h b/cpp_src/core/index/payload_map.h index 7a16a1cbb..d5a846524 100644 --- a/cpp_src/core/index/payload_map.h +++ b/cpp_src/core/index/payload_map.h @@ -12,13 +12,13 @@ namespace reindexer { class PayloadValueWithHash : public PayloadValue { public: PayloadValueWithHash() noexcept : PayloadValue() {} - PayloadValueWithHash(PayloadValue &&pv, const PayloadType &pt, const FieldsSet &fields) - : PayloadValue(std::move(pv)), hash_(ConstPayload(pt, *static_cast(this)).GetHash(fields)) {} - PayloadValueWithHash(const PayloadValueWithHash &o) noexcept : PayloadValue(o), hash_(o.hash_) {} - PayloadValueWithHash(PayloadValueWithHash &&o) noexcept : PayloadValue(std::move(o)), hash_(o.hash_) {} - PayloadValueWithHash &operator=(PayloadValueWithHash &&o) noexcept { + PayloadValueWithHash(PayloadValue&& pv, const PayloadType& pt, const FieldsSet& fields) + : PayloadValue(std::move(pv)), hash_(ConstPayload(pt, *static_cast(this)).GetHash(fields)) {} + PayloadValueWithHash(const PayloadValueWithHash& o) noexcept : PayloadValue(o), hash_(o.hash_) {} + PayloadValueWithHash(PayloadValueWithHash&& o) noexcept : PayloadValue(std::move(o)), hash_(o.hash_) {} + PayloadValueWithHash& operator=(PayloadValueWithHash&& o) noexcept { hash_ = o.hash_; - return static_cast(PayloadValue::operator=(std::move(o))); + return static_cast(PayloadValue::operator=(std::move(o))); } uint32_t GetHash() const noexcept { return hash_; } @@ -31,15 +31,15 @@ class equal_composite { using is_transparent = void; template - equal_composite(PT &&type, FS &&fields) : type_(std::forward(type)), fields_(std::forward(fields)) { + equal_composite(PT&& type, FS&& fields) : type_(std::forward(type)), fields_(std::forward(fields)) { assertrx_dbg(type_); } - bool operator()(const PayloadValue &lhs, const PayloadValue &rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } - bool operator()(const PayloadValueWithHash &lhs, const PayloadValueWithHash &rhs) const { + bool operator()(const PayloadValue& lhs, const PayloadValue& rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } + bool operator()(const PayloadValueWithHash& lhs, const PayloadValueWithHash& rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } - bool operator()(const PayloadValueWithHash &lhs, const PayloadValue &rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } - bool operator()(const PayloadValue &lhs, const PayloadValueWithHash &rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } + bool operator()(const PayloadValueWithHash& lhs, const PayloadValue& rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } + bool operator()(const PayloadValue& lhs, const PayloadValueWithHash& rhs) const { return ConstPayload(type_, lhs).IsEQ(rhs, fields_); } private: PayloadType type_; @@ -48,10 +48,10 @@ class equal_composite { class equal_composite_ref { public: - equal_composite_ref(const PayloadType &type, const FieldsSet &fields) noexcept : type_(type), fields_(fields) { + equal_composite_ref(const PayloadType& type, const FieldsSet& fields) noexcept : type_(type), fields_(fields) { assertrx_dbg(type_.get()); } - bool operator()(const PayloadValue &lhs, const PayloadValue &rhs) const { + bool operator()(const PayloadValue& lhs, const PayloadValue& rhs) const { assertrx_dbg(!lhs.IsFree()); assertrx_dbg(!rhs.IsFree()); return ConstPayload(type_, lhs).IsEQ(rhs, fields_); @@ -65,11 +65,11 @@ class equal_composite_ref { class hash_composite { public: template - hash_composite(PT &&type, FS &&fields) : type_(std::forward(type)), fields_(std::forward(fields)) { + hash_composite(PT&& type, FS&& fields) : type_(std::forward(type)), fields_(std::forward(fields)) { assertrx_dbg(type_); } - size_t operator()(const PayloadValueWithHash &s) const noexcept { return s.GetHash(); } - size_t operator()(const PayloadValue &s) const { return ConstPayload(type_, s).GetHash(fields_); } + size_t operator()(const PayloadValueWithHash& s) const noexcept { return s.GetHash(); } + size_t operator()(const PayloadValue& s) const { return ConstPayload(type_, s).GetHash(fields_); } private: PayloadType type_; @@ -78,10 +78,10 @@ class hash_composite { class hash_composite_ref { public: - hash_composite_ref(const PayloadType &type, const FieldsSet &fields) noexcept : type_(type), fields_(fields) { + hash_composite_ref(const PayloadType& type, const FieldsSet& fields) noexcept : type_(type), fields_(fields) { assertrx_dbg(type_.get()); } - size_t operator()(const PayloadValue &s) const { return ConstPayload(type_, s).GetHash(fields_); } + size_t operator()(const PayloadValue& s) const { return ConstPayload(type_, s).GetHash(fields_); } private: std::reference_wrapper type_; @@ -90,10 +90,10 @@ class hash_composite_ref { class less_composite { public: - less_composite(PayloadType &&type, FieldsSet &&fields) noexcept : type_(std::move(type)), fields_(std::move(fields)) { + less_composite(PayloadType&& type, FieldsSet&& fields) noexcept : type_(std::move(type)), fields_(std::move(fields)) { assertrx_dbg(type_); } - bool operator()(const PayloadValue &lhs, const PayloadValue &rhs) const { + bool operator()(const PayloadValue& lhs, const PayloadValue& rhs) const { assertrx_dbg(!lhs.IsFree()); assertrx_dbg(!rhs.IsFree()); return (ConstPayload(type_, lhs).Compare(rhs, fields_) == ComparationResult::Lt); @@ -106,10 +106,10 @@ class less_composite { class less_composite_ref { public: - less_composite_ref(const PayloadType &type, const FieldsSet &fields) noexcept : type_(type), fields_(fields) { + less_composite_ref(const PayloadType& type, const FieldsSet& fields) noexcept : type_(type), fields_(fields) { assertrx_dbg(type_.get()); } - bool operator()(const PayloadValue &lhs, const PayloadValue &rhs) const { + bool operator()(const PayloadValue& lhs, const PayloadValue& rhs) const { assertrx_dbg(!lhs.IsFree()); assertrx_dbg(!rhs.IsFree()); return (ConstPayload(type_, lhs).Compare(rhs, fields_) == ComparationResult::Lt); @@ -126,30 +126,38 @@ class payload_str_fields_helper; template <> class payload_str_fields_helper { protected: - payload_str_fields_helper(PayloadType &&payloadType, const FieldsSet &fields) : payload_type_(std::move(payloadType)) { + payload_str_fields_helper(PayloadType&& payloadType, const FieldsSet& fields) : payload_type_(std::move(payloadType)) { if (fields.getTagsPathsLength() || fields.getJsonPathsLength()) { str_fields_.push_back(0); } for (int f : payload_type_.StrFields()) { - if (fields.contains(f)) str_fields_.push_back(f); + if (fields.contains(f)) { + str_fields_.push_back(f); + } } } - payload_str_fields_helper(const payload_str_fields_helper &) = default; - payload_str_fields_helper(payload_str_fields_helper &&) = default; + payload_str_fields_helper(const payload_str_fields_helper&) = default; + payload_str_fields_helper(payload_str_fields_helper&&) = default; - inline void add_ref(PayloadValue &pv) const { + inline void add_ref(PayloadValue& pv) const { Payload pl(payload_type_, pv); - for (int f : str_fields_) pl.AddRefStrings(f); + for (int f : str_fields_) { + pl.AddRefStrings(f); + } } - inline void release(PayloadValue &pv) const { + inline void release(PayloadValue& pv) const { Payload pl(payload_type_, pv); - for (int f : str_fields_) pl.ReleaseStrings(f); + for (int f : str_fields_) { + pl.ReleaseStrings(f); + } } - inline void move_strings_to_holder(PayloadValue &pv, StringsHolder &strHolder) const { + inline void move_strings_to_holder(PayloadValue& pv, StringsHolder& strHolder) const { Payload pl(payload_type_, pv); - for (int f : str_fields_) pl.MoveStrings(f, strHolder); + for (int f : str_fields_) { + pl.MoveStrings(f, strHolder); + } } inline bool have_str_fields() const noexcept { return !str_fields_.empty(); } @@ -162,17 +170,17 @@ class payload_str_fields_helper { template <> class payload_str_fields_helper { protected: - payload_str_fields_helper(const PayloadType &, const FieldsSet &) noexcept {} + payload_str_fields_helper(const PayloadType&, const FieldsSet&) noexcept {} - inline void add_ref(PayloadValue &) const noexcept {} - inline void release(PayloadValue &) const noexcept {} - inline void move_strings_to_holder(PayloadValue &, StringsHolder &) const noexcept {} + inline void add_ref(PayloadValue&) const noexcept {} + inline void release(PayloadValue&) const noexcept {} + inline void move_strings_to_holder(PayloadValue&, StringsHolder&) const noexcept {} inline bool have_str_fields() const noexcept { return false; } }; struct no_deep_clean { template - void operator()(const T &) const noexcept {} + void operator()(const T&) const noexcept {} }; template @@ -201,70 +209,86 @@ class unordered_payload_map static_assert(std::is_nothrow_move_constructible>::value, "Nothrow movebale key and value required"); - unordered_payload_map(size_t size, PayloadType &&pt, FieldsSet &&f) + unordered_payload_map(size_t size, PayloadType&& pt, FieldsSet&& f) : base_hash_map(size, hash_composite(PayloadType{pt}, FieldsSet{f}), equal_composite(PayloadType{pt}, FieldsSet{f})), payload_str_fields_helper(PayloadType{pt}, f), payloadType_(std::move(pt)), fields_(std::move(f)) {} - unordered_payload_map(PayloadType &&pt, FieldsSet &&f) : unordered_payload_map(1000, std::move(pt), std::move(f)) {} + unordered_payload_map(PayloadType&& pt, FieldsSet&& f) : unordered_payload_map(1000, std::move(pt), std::move(f)) {} - unordered_payload_map(const unordered_payload_map &other) + unordered_payload_map(const unordered_payload_map& other) : base_hash_map(other), payload_str_fields_helper(other), payloadType_(other.payloadType_), fields_(other.fields_) { - for (auto &item : *this) this->add_ref(item.first); + for (auto& item : *this) { + this->add_ref(item.first); + } } - unordered_payload_map(unordered_payload_map &&) = default; - unordered_payload_map &operator=(unordered_payload_map &&other) { - for (auto &item : *this) this->release(item.first); + unordered_payload_map(unordered_payload_map&&) = default; + unordered_payload_map& operator=(unordered_payload_map&& other) { + for (auto& item : *this) { + this->release(item.first); + } base_hash_map::operator=(std::move(other)); return *this; } - unordered_payload_map &operator=(const unordered_payload_map &) = delete; + unordered_payload_map& operator=(const unordered_payload_map&) = delete; ~unordered_payload_map() { - for (auto &item : *this) this->release(item.first); + for (auto& item : *this) { + this->release(item.first); + } } - std::pair insert(const std::pair &v) { + std::pair insert(const std::pair& v) { PayloadValueWithHash key(v.first, payloadType_, fields_); auto res = base_hash_map::emplate(std::move(key), v.second); - if (res.second) add_ref(res.first->first); + if (res.second) { + add_ref(res.first->first); + } return res; } - std::pair insert(std::pair &&v) { + std::pair insert(std::pair&& v) { PayloadValueWithHash key(std::move(v.first), payloadType_, fields_); auto res = base_hash_map::emplace(std::move(key), std::move(v.second)); - if (res.second) this->add_ref(res.first->first); + if (res.second) { + this->add_ref(res.first->first); + } return res; } template - std::pair emplace(const PayloadValue &pl, V &&v) { + std::pair emplace(const PayloadValue& pl, V&& v) { PayloadValueWithHash key(PayloadValue{pl}, payloadType_, fields_); auto res = base_hash_map::emplace(std::move(key), std::forward(v)); - if (res.second) this->add_ref(res.first->first); + if (res.second) { + this->add_ref(res.first->first); + } return res; } template - std::pair emplace(PayloadValue &&pl, V &&v) { + std::pair emplace(PayloadValue&& pl, V&& v) { PayloadValueWithHash key(std::move(pl), payloadType_, fields_); auto res = base_hash_map::emplace(std::move(key), std::forward(v)); - if (res.second) this->add_ref(res.first->first); + if (res.second) { + this->add_ref(res.first->first); + } return res; } template - iterator erase(iterator pos, StringsHolder &strHolder) { + iterator erase(iterator pos, StringsHolder& strHolder) { static const deep_cleaner deep_clean; - if (pos != end()) this->move_strings_to_holder(pos->first, strHolder); + if (pos != end()) { + this->move_strings_to_holder(pos->first, strHolder); + } deep_clean(*pos); return base_hash_map::erase(pos); } - T1 &operator[](const PayloadValue &k) { + T1& operator[](const PayloadValue& k) { PayloadValueWithHash key(PayloadValue{k}, payloadType_, fields_); return base_hash_map::operator[](std::move(key)); } - T1 &operator[](PayloadValue &&k) { + T1& operator[](PayloadValue&& k) { PayloadValueWithHash key(std::move(k), payloadType_, fields_); return base_hash_map::operator[](std::move(key)); } @@ -300,29 +324,37 @@ class payload_map : private btree::btree_map, using base_tree_map::find; using payload_str_fields_helper::have_str_fields; - payload_map(PayloadType payloadType, const FieldsSet &fields) + payload_map(PayloadType payloadType, const FieldsSet& fields) : base_tree_map(less_composite(PayloadType{payloadType}, FieldsSet{fields})), payload_str_fields_helper(std::move(payloadType), fields) {} - payload_map(const payload_map &other) : base_tree_map(other), payload_str_fields_helper(other) { - for (auto &item : *this) this->add_ref(const_cast(item.first)); + payload_map(const payload_map& other) : base_tree_map(other), payload_str_fields_helper(other) { + for (auto& item : *this) { + this->add_ref(const_cast(item.first)); + } } - payload_map(payload_map &&) = default; + payload_map(payload_map&&) = default; ~payload_map() { - for (auto &item : *this) this->release(const_cast(item.first)); + for (auto& item : *this) { + this->release(const_cast(item.first)); + } } - std::pair insert(const value_type &v) { + std::pair insert(const value_type& v) { auto res = base_tree_map::insert(v); - if (res.second) this->add_ref(const_cast(res.first->first)); + if (res.second) { + this->add_ref(const_cast(res.first->first)); + } return res; } - iterator insert(iterator, const value_type &v) { return insert(v).first; } + iterator insert(iterator, const value_type& v) { return insert(v).first; } template - iterator erase(const iterator &pos, StringsHolder &strHolder) { + iterator erase(const iterator& pos, StringsHolder& strHolder) { static const deep_cleaner deep_clean; - if (pos != end()) this->move_strings_to_holder(const_cast(pos->first), strHolder); + if (pos != end()) { + this->move_strings_to_holder(const_cast(pos->first), strHolder); + } deep_clean(*pos); return base_tree_map::erase(pos); } diff --git a/cpp_src/core/index/rtree/greenesplitter.h b/cpp_src/core/index/rtree/greenesplitter.h index c8c6a7179..1ceb8760a 100644 --- a/cpp_src/core/index/rtree/greenesplitter.h +++ b/cpp_src/core/index/rtree/greenesplitter.h @@ -30,9 +30,15 @@ class GreeneSplitter : private SplitterappendingEntry_ : src[seeds.second]); @@ -76,7 +82,9 @@ class GreeneSplitter : private SplittermoveEntryTo(*firstNode, indexes[i]); } - if (MaxEntries % 2 == 0) ++i; + if (MaxEntries % 2 == 0) { + ++i; + } for (; i < MaxEntries - 1; ++i) { this->moveEntryTo(*secondNode, indexes[i]); } diff --git a/cpp_src/core/index/rtree/indexrtree.cc b/cpp_src/core/index/rtree/indexrtree.cc index c285a768d..fe6628dbf 100644 --- a/cpp_src/core/index/rtree/indexrtree.cc +++ b/cpp_src/core/index/rtree/indexrtree.cc @@ -10,10 +10,10 @@ namespace reindexer { template class Splitter, size_t MaxEntries, size_t MinEntries> -SelectKeyResults IndexRTree::SelectKey(const VariantArray &keys, CondType condition, +SelectKeyResults IndexRTree::SelectKey(const VariantArray& keys, CondType condition, SortType sortId, Index::SelectOpts opts, - const BaseFunctionCtx::Ptr &funcCtx, - const RdxContext &rdxCtx) { + const BaseFunctionCtx::Ptr& funcCtx, + const RdxContext& rdxCtx) { const auto indexWard(rdxCtx.BeforeIndexWork()); if (opts.forceComparator) { return IndexStore::SelectKey(keys, condition, sortId, opts, funcCtx, rdxCtx); @@ -21,8 +21,12 @@ SelectKeyResults IndexRTree::Select SelectKeyResult res; - if (condition != CondDWithin) throw Error(errQueryExec, "Only CondDWithin available for RTree index"); - if (keys.size() != 2) throw Error(errQueryExec, "CondDWithin expects two arguments"); + if (condition != CondDWithin) { + throw Error(errQueryExec, "Only CondDWithin available for RTree index"); + } + if (keys.size() != 2) { + throw Error(errQueryExec, "CondDWithin expects two arguments"); + } Point point; double distance; if (keys[0].Type().Is()) { @@ -34,9 +38,9 @@ SelectKeyResults IndexRTree::Select } class Visitor : public Map::Visitor { public: - Visitor(SortType sId, unsigned distinct, unsigned iCountInNs, SelectKeyResult &r) + Visitor(SortType sId, unsigned distinct, unsigned iCountInNs, SelectKeyResult& r) : sortId_{sId}, itemsCountInNs_{distinct ? 0u : iCountInNs}, res_{r} {} - bool operator()(const typename Map::value_type &v) override { + bool operator()(const typename Map::value_type& v) override { idsCount_ += v.second.Unsorted().size(); res_.emplace_back(v.second, sortId_); return ScanWin(); @@ -48,7 +52,7 @@ SelectKeyResults IndexRTree::Select private: SortType sortId_; unsigned itemsCountInNs_; - SelectKeyResult &res_; + SelectKeyResult& res_; size_t idsCount_ = 0; } visitor{sortId, opts.distinct, opts.itemsCountInNamespace, res}; this->idx_map.DWithin(point, distance, visitor); @@ -61,8 +65,8 @@ SelectKeyResults IndexRTree::Select template class Splitter, size_t MaxEntries, size_t MinEntries> -void IndexRTree::Upsert(VariantArray &result, const VariantArray &keys, IdType id, - bool &clearCache) { +void IndexRTree::Upsert(VariantArray& result, const VariantArray& keys, IdType id, + bool& clearCache) { if (keys.empty() || keys.IsNullValue()) { Upsert(Variant{}, id, clearCache); return; @@ -90,15 +94,17 @@ void IndexRTree::Upsert(VariantArra template class Splitter, size_t MaxEntries, size_t MinEntries> -void IndexRTree::Delete(const VariantArray &keys, IdType id, StringsHolder &strHolder, - bool &clearCache) { +void IndexRTree::Delete(const VariantArray& keys, IdType id, StringsHolder& strHolder, + bool& clearCache) { if (keys.empty() || keys.IsNullValue()) { return Delete(Variant{}, id, strHolder, clearCache); } int delcnt = 0; const Point point = static_cast(keys); typename Map::iterator keyIt = this->idx_map.find(point); - if (keyIt == this->idx_map.end()) return; + if (keyIt == this->idx_map.end()) { + return; + } this->cache_.reset(); clearCache = true; this->isBuilt_ = false; @@ -120,8 +126,8 @@ void IndexRTree::Delete(const Varia } } -std::unique_ptr IndexRTree_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr IndexRTree_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { switch (idef.opts_.RTreeType()) { case IndexOpts::Linear: if (idef.opts_.IsPK() || idef.opts_.IsDense()) { diff --git a/cpp_src/core/index/rtree/indexrtree.h b/cpp_src/core/index/rtree/indexrtree.h index 9d4b23986..86cb022ae 100644 --- a/cpp_src/core/index/rtree/indexrtree.h +++ b/cpp_src/core/index/rtree/indexrtree.h @@ -11,20 +11,20 @@ class IndexRTree : public IndexUnordered; public: - IndexRTree(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, const NamespaceCacheConfigData &cacheCfg) + IndexRTree(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg) : IndexUnordered{idef, std::move(payloadType), std::move(fields), cacheCfg} {} - SelectKeyResults SelectKey(const VariantArray &keys, CondType, SortType, Index::SelectOpts, const BaseFunctionCtx::Ptr &, - const RdxContext &) override; + SelectKeyResults SelectKey(const VariantArray& keys, CondType, SortType, Index::SelectOpts, const BaseFunctionCtx::Ptr&, + const RdxContext&) override; using IndexUnordered::Upsert; - void Upsert(VariantArray &result, const VariantArray &keys, IdType id, bool &clearCache) override; + void Upsert(VariantArray& result, const VariantArray& keys, IdType id, bool& clearCache) override; using IndexUnordered::Delete; - void Delete(const VariantArray &keys, IdType id, StringsHolder &, bool &clearCache) override; + void Delete(const VariantArray& keys, IdType id, StringsHolder&, bool& clearCache) override; std::unique_ptr Clone() const override { return std::make_unique(*this); } }; -std::unique_ptr IndexRTree_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg); +std::unique_ptr IndexRTree_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg); } // namespace reindexer diff --git a/cpp_src/core/index/rtree/linearsplitter.h b/cpp_src/core/index/rtree/linearsplitter.h index 1654c6eae..473111f54 100644 --- a/cpp_src/core/index/rtree/linearsplitter.h +++ b/cpp_src/core/index/rtree/linearsplitter.h @@ -53,7 +53,9 @@ class LinearSplitter : public GuttmanSplitter newMinX) { newMinX = currRect.Left(); @@ -86,7 +88,9 @@ class LinearSplitter : public GuttmanSplitter newMinY) { newMinY = currRect.Bottom(); diff --git a/cpp_src/core/index/rtree/quadraticsplitter.h b/cpp_src/core/index/rtree/quadraticsplitter.h index c00d71e1c..c8ac8b257 100644 --- a/cpp_src/core/index/rtree/quadraticsplitter.h +++ b/cpp_src/core/index/rtree/quadraticsplitter.h @@ -28,7 +28,9 @@ class QuadraticSplitter : public GuttmanSplittermoved_[i]) continue; + if (this->moved_[i]) { + continue; + } const auto rect = Base::getBoundRect((i == MaxEntries) ? this->appendingEntry_ : this->srcNode_.data_[i]); const auto currFirstAreaIncrease = Base::AreaIncrease(firstNode->BoundRect(), rect); const auto currSecondAreaIncrease = Base::AreaIncrease(secondNode->BoundRect(), rect); diff --git a/cpp_src/core/index/rtree/rstarsplitter.h b/cpp_src/core/index/rtree/rstarsplitter.h index 427a4add3..7b02c49b8 100644 --- a/cpp_src/core/index/rtree/rstarsplitter.h +++ b/cpp_src/core/index/rtree/rstarsplitter.h @@ -123,7 +123,9 @@ class RStarSplitter : private SplitterIsFull()) ++i; + while (i < data.size() && data[i]->IsFull()) { + ++i; + } } assertrx(i < data.size()); auto minOverlapIncrease = overlap(boundRect(data[i]->BoundRect(), insertingRect), i, data) - overlap(data[i]->BoundRect(), i, data); @@ -166,7 +168,9 @@ class RStarSplitter : private SplitterBoundRect(), dstBoundRect), result, except, data) - overlap(dstBoundRect, result, except, data); for (size_t i = result + 1; i < data.size(); ++i) { - if (i == except) continue; + if (i == except) { + continue; + } const auto currOverlapIncrease = overlap(boundRect(data[i]->BoundRect(), dstBoundRect), i, except, data) - overlap(dstBoundRect, i, except, data); if (approxEqual(minOverlapIncrease, currOverlapIncrease)) { @@ -204,7 +208,9 @@ class RStarSplitter : private Splitter().data_)& data) noexcept { - if (index1 > index2) std::swap(index1, index2); + if (index1 > index2) { + std::swap(index1, index2); + } assertrx(index2 < data.size()); double result = 0.0; size_t i = 0; @@ -222,10 +228,14 @@ class RStarSplitter : private Splitter= right) return 0.0; + if (left >= right) { + return 0.0; + } const auto bottom = std::max(r1.Bottom(), r2.Bottom()); const auto top = std::min(r1.Top(), r2.Top()); - if (bottom >= top) return 0.0; + if (bottom >= top) { + return 0.0; + } return (right - left) * (top - bottom); } }; diff --git a/cpp_src/core/index/rtree/rtree.h b/cpp_src/core/index/rtree/rtree.h index 9d494dcab..1e61ce68e 100644 --- a/cpp_src/core/index/rtree/rtree.h +++ b/cpp_src/core/index/rtree/rtree.h @@ -199,14 +199,18 @@ class RectangleTree { bool DWithin(Point p, double distance, RectangleTree::Visitor& visitor) const noexcept override { for (const auto& v : data_) { if (reindexer::DWithin(Traits::GetPoint(v), p, distance)) { - if (visitor(v)) return true; + if (visitor(v)) { + return true; + } } } return false; } bool ForEach(RectangleTree::Visitor& visitor) const noexcept override { for (const auto& v : data_) { - if (visitor(v)) return true; + if (visitor(v)) { + return true; + } } return false; } @@ -216,7 +220,9 @@ class RectangleTree { if (visitor(*it)) { data_.erase(it); if (data_.size() < MinEntries) { - if (data_.empty()) this->SetBoundRect({}); + if (data_.empty()) { + this->SetBoundRect({}); + } return {true, true}; } else { adjustBoundRect(); @@ -239,23 +245,35 @@ class RectangleTree { } double AreaIncrease(const reindexer::Rectangle& r) const noexcept override { - if (data_.empty()) return r.Area(); + if (data_.empty()) { + return r.Area(); + } return SplitterT::AreaIncrease(this->BoundRect(), r); } bool Check(const Node* parent) const noexcept override { - if (parent != this->Parent()) return false; - if (data_.size() > MaxEntries) return false; + if (parent != this->Parent()) { + return false; + } + if (data_.size() > MaxEntries) { + return false; + } if (data_.empty()) { - if (this->BoundRect() != reindexer::Rectangle{}) return false; + if (this->BoundRect() != reindexer::Rectangle{}) { + return false; + } } else { const reindexer::Rectangle thisBoundRect{this->BoundRect()}; reindexer::Rectangle boundRectOfAllChildren = boundRect(Traits::GetPoint(data_[0])); for (const auto& v : data_) { boundRectOfAllChildren = boundRect(boundRectOfAllChildren, Traits::GetPoint(v)); - if (!thisBoundRect.Contain(Traits::GetPoint(v))) return false; + if (!thisBoundRect.Contain(Traits::GetPoint(v))) { + return false; + } + } + if (thisBoundRect != boundRectOfAllChildren) { + return false; } - if (thisBoundRect != boundRectOfAllChildren) return false; } return true; } @@ -301,9 +319,13 @@ class RectangleTree { bool IsLeaf() const noexcept override { return false; } bool IsFull() const noexcept override { - if (data_.size() < MaxEntries) return false; + if (data_.size() < MaxEntries) { + return false; + } for (const auto& n : data_) { - if (!n->IsFull()) return false; + if (!n->IsFull()) { + return false; + } } return true; } @@ -316,7 +338,9 @@ class RectangleTree { } bool Empty() const noexcept override { for (const auto& n : data_) { - if (!n->Empty()) return false; + if (!n->Empty()) { + return false; + } } return true; } @@ -345,7 +369,9 @@ class RectangleTree { for (auto& n : data_) { if (n->BoundRect().Contain(p)) { const auto res = n->find(p); - if (res.second) return res; + if (res.second) { + return res; + } } } return {{nullptr, {}}, false}; @@ -354,7 +380,9 @@ class RectangleTree { for (auto& n : data_) { if (n->BoundRect().Contain(p)) { const auto res = n->find(p); - if (res.second) return res; + if (res.second) { + return res; + } } } return {{nullptr, {}}, false}; @@ -369,7 +397,9 @@ class RectangleTree { if (splittedChildren.first) { data_[nodeToInsert] = std::move(splittedChildren.first); auto splittedNodes = insert(std::move(splittedChildren.second)); - if (splittedNodes.first) return splittedNodes; + if (splittedNodes.first) { + return splittedNodes; + } data_[nodeToInsert]->SetParent(this); } if (data_.size() == 1) { @@ -383,16 +413,22 @@ class RectangleTree { bool DWithin(Point p, double distance, RectangleTree::Visitor& visitor) const noexcept override { for (const auto& n : data_) { if (reindexer::DWithin(n->BoundRect(), p, distance)) { - if (n->ForEach(visitor)) return true; + if (n->ForEach(visitor)) { + return true; + } } else if (intersect(n->BoundRect(), Circle{p, distance})) { - if (n->DWithin(p, distance, visitor)) return true; + if (n->DWithin(p, distance, visitor)) { + return true; + } } } return false; } bool ForEach(RectangleTree::Visitor& visitor) const noexcept override { for (const auto& n : data_) { - if (n->ForEach(visitor)) return true; + if (n->ForEach(visitor)) { + return true; + } } return false; } @@ -419,17 +455,29 @@ class RectangleTree { } bool Check(const Node* parent) const noexcept override { - if (parent != this->Parent()) return false; - if (data_.empty()) return false; - if (data_.size() > MaxEntries) return false; + if (parent != this->Parent()) { + return false; + } + if (data_.empty()) { + return false; + } + if (data_.size() > MaxEntries) { + return false; + } const reindexer::Rectangle thisBoundRect{this->BoundRect()}; reindexer::Rectangle boundRectOfAllChildren = data_[0]->BoundRect(); for (const auto& n : data_) { - if (!n->Check(this)) return false; + if (!n->Check(this)) { + return false; + } boundRectOfAllChildren = boundRect(boundRectOfAllChildren, n->BoundRect()); - if (!thisBoundRect.Contain(n->BoundRect())) return false; + if (!thisBoundRect.Contain(n->BoundRect())) { + return false; + } + } + if (this->BoundRect() != boundRectOfAllChildren) { + return false; } - if (this->BoundRect() != boundRectOfAllChildren) return false; return true; } @@ -557,12 +605,16 @@ class RectangleTree { iterator find(Point p) noexcept { const auto res = root_.find(p); - if (res.second) return res.first; + if (res.second) { + return res.first; + } return end(); } const_iterator find(Point p) const noexcept { const auto res = root_.find(p); - if (res.second) return res.first; + if (res.second) { + return res.first; + } return cend(); } void DWithin(Point p, double distance, RectangleTree::Visitor& visitor) const { root_.DWithin(p, distance, visitor); } diff --git a/cpp_src/core/index/rtree/splitter.h b/cpp_src/core/index/rtree/splitter.h index 51675c1f0..59eb756bb 100644 --- a/cpp_src/core/index/rtree/splitter.h +++ b/cpp_src/core/index/rtree/splitter.h @@ -12,7 +12,9 @@ class Splitter { ~Splitter() = default; static double AreaIncrease(const Rectangle& lhs, const Rectangle& rhs) noexcept { - if (lhs.Contain(rhs)) return 0.0; + if (lhs.Contain(rhs)) { + return 0.0; + } return reindexer::boundRect(lhs, rhs).Area() - lhs.Area(); } @@ -45,13 +47,17 @@ class Splitter { bool splitOfChildAvailable) { size_t i = 0; if (!splitOfChildAvailable) { - while (i < data.size() && data[i]->IsFull()) ++i; + while (i < data.size() && data[i]->IsFull()) { + ++i; + } } assertrx(i < data.size()); auto minAreaIncrease = data[i]->AreaIncrease(insertingRect); size_t result = i; for (++i; i < data.size(); ++i) { - if (!splitOfChildAvailable && data[i]->IsFull()) continue; + if (!splitOfChildAvailable && data[i]->IsFull()) { + continue; + } const auto currAreaIncrease = data[i]->AreaIncrease(insertingRect); if ((approxEqual(currAreaIncrease, minAreaIncrease) && data[i]->BoundRect().Area() < data[result]->BoundRect().Area()) || currAreaIncrease < minAreaIncrease) { @@ -70,7 +76,9 @@ class Splitter { } auto minAreaIncrease = dst.AreaIncrease(data[result]->BoundRect()); for (size_t i = result + 1; i < data.size(); ++i) { - if (i == except) continue; + if (i == except) { + continue; + } const auto currAreaIncrease = dst.AreaIncrease(data[i]->BoundRect()); if ((approxEqual(currAreaIncrease, minAreaIncrease) && data[i]->BoundRect().Area() < data[result]->BoundRect().Area()) || currAreaIncrease < minAreaIncrease) { diff --git a/cpp_src/core/index/string_map.h b/cpp_src/core/index/string_map.h index 67fcda0ad..2f7d0a616 100644 --- a/cpp_src/core/index/string_map.h +++ b/cpp_src/core/index/string_map.h @@ -245,7 +245,9 @@ struct StringMapEntryCleaner { template (), bool> = true> void free_node(const T& str) const { - if (needSaveExpiredStrings_) strHolder_.Add(str); + if (needSaveExpiredStrings_) { + strHolder_.Add(str); + } } template (), bool> = true> diff --git a/cpp_src/core/index/ttlindex.cc b/cpp_src/core/index/ttlindex.cc index 7fdbc1e5b..7a10c0b69 100644 --- a/cpp_src/core/index/ttlindex.cc +++ b/cpp_src/core/index/ttlindex.cc @@ -2,10 +2,10 @@ namespace reindexer { -void UpdateExpireAfter(Index *i, int64_t v) { - auto ttlIndexEntryPlain = dynamic_cast> *>(i); +void UpdateExpireAfter(Index* i, int64_t v) { + auto ttlIndexEntryPlain = dynamic_cast>*>(i); if (ttlIndexEntryPlain == nullptr) { - auto ttlIndex = dynamic_cast> *>(i); + auto ttlIndex = dynamic_cast>*>(i); if (ttlIndex == nullptr) { throw Error(errLogic, "Incorrect ttl index type"); } @@ -15,8 +15,8 @@ void UpdateExpireAfter(Index *i, int64_t v) { } } -std::unique_ptr TtlIndex_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr TtlIndex_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { if (idef.opts_.IsPK() || idef.opts_.IsDense()) { return std::make_unique>>(idef, std::move(payloadType), std::move(fields), cacheCfg); diff --git a/cpp_src/core/index/ttlindex.h b/cpp_src/core/index/ttlindex.h index b59b6947c..48899cafe 100644 --- a/cpp_src/core/index/ttlindex.h +++ b/cpp_src/core/index/ttlindex.h @@ -10,9 +10,9 @@ namespace reindexer { template class TtlIndex : public IndexOrdered { public: - TtlIndex(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, const NamespaceCacheConfigData &cacheCfg) + TtlIndex(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, const NamespaceCacheConfigData& cacheCfg) : IndexOrdered(idef, std::move(payloadType), std::move(fields), cacheCfg), expireAfter_(idef.expireAfter_) {} - TtlIndex(const TtlIndex &other) : IndexOrdered(other), expireAfter_(other.expireAfter_) {} + TtlIndex(const TtlIndex& other) : IndexOrdered(other), expireAfter_(other.expireAfter_) {} int64_t GetTTLValue() const noexcept override { return expireAfter_; } std::unique_ptr Clone() const override { return std::make_unique>(*this); } void UpdateExpireAfter(int64_t v) noexcept { expireAfter_ = v; } @@ -22,8 +22,8 @@ class TtlIndex : public IndexOrdered { int64_t expireAfter_ = 0; }; -std::unique_ptr TtlIndex_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg); -void UpdateExpireAfter(Index *i, int64_t v); +std::unique_ptr TtlIndex_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg); +void UpdateExpireAfter(Index* i, int64_t v); } // namespace reindexer diff --git a/cpp_src/core/index/updatetracker.h b/cpp_src/core/index/updatetracker.h index ee870dea4..78ff6ed86 100644 --- a/cpp_src/core/index/updatetracker.h +++ b/cpp_src/core/index/updatetracker.h @@ -18,17 +18,17 @@ class UpdateTracker { template struct hash_ptr { - size_t operator()(const T1 &obj) const noexcept { return std::hash()(reinterpret_cast(obj.get())); } + size_t operator()(const T1& obj) const noexcept { return std::hash()(reinterpret_cast(obj.get())); } }; template struct equal_ptr { - bool operator()(const T1 &lhs, const T1 &rhs) const noexcept { + bool operator()(const T1& lhs, const T1& rhs) const noexcept { return reinterpret_cast(lhs.get()) == reinterpret_cast(rhs.get()); } }; template struct less_ptr { - bool operator()(const T1 &lhs, const T1 &rhs) const noexcept { + bool operator()(const T1& lhs, const T1& rhs) const noexcept { return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); } }; @@ -46,21 +46,25 @@ class UpdateTracker { typename std::conditional_t>; UpdateTracker() = default; - UpdateTracker(const UpdateTracker &other) + UpdateTracker(const UpdateTracker& other) : completeUpdate_(other.updated_.size() || other.completeUpdate_), simpleCounting_(other.simpleCounting_), updatesCounter_(other.updatesCounter_) { updatesBuckets_.store(updated_.bucket_count(), std::memory_order_relaxed); } - UpdateTracker &operator=(const UpdateTracker &other) = delete; + UpdateTracker& operator=(const UpdateTracker& other) = delete; - void markUpdated(T &idx_map, typename T::iterator &k, bool skipCommited = true) { - if (skipCommited && k->second.Unsorted().IsCommited()) return; + void markUpdated(T& idx_map, typename T::iterator& k, bool skipCommited = true) { + if (skipCommited && k->second.Unsorted().IsCommited()) { + return; + } if (simpleCounting_) { ++updatesCounter_; return; } - if (completeUpdate_) return; + if (completeUpdate_) { + return; + } if (updated_.size() > static_cast(idx_map.size() / 8) || updated_.size() > 10000000) { completeUpdate_ = true; clearUpdates(); @@ -69,8 +73,8 @@ class UpdateTracker { emplaceUpdate(k); } - void commitUpdated(T &idx_map) { - for (const auto &valIt : updated_) { + void commitUpdated(T& idx_map) { + for (const auto& valIt : updated_) { auto keyIt = idx_map.find(valIt); assertrx(keyIt != idx_map.end()); keyIt->second.Unsorted().Commit(); @@ -78,7 +82,7 @@ class UpdateTracker { } } - void markDeleted(typename T::iterator &k) { + void markDeleted(typename T::iterator& k) { if (simpleCounting_) { ++updatesCounter_; } else { @@ -92,8 +96,8 @@ class UpdateTracker { updatesCounter_ = 0; clearUpdates(); } - hash_map &updated() { return updated_; } - const hash_map &updated() const { return updated_; } + hash_map& updated() { return updated_; } + const hash_map& updated() const { return updated_; } uint32_t updatesSize() const noexcept { return updatesSize_.load(std::memory_order_relaxed); } uint32_t updatesBuckets() const noexcept { return updatesBuckets_.load(std::memory_order_relaxed); } uint32_t allocated() const noexcept { return allocatedMem_.load(std::memory_order_relaxed); } @@ -113,14 +117,14 @@ class UpdateTracker { } protected: - void eraseUpdate(typename T::iterator &k) { + void eraseUpdate(typename T::iterator& k) { updated_.erase(k->first); updatesSize_.store(updated_.size(), std::memory_order_relaxed); updatesBuckets_.store(updated_.bucket_count(), std::memory_order_relaxed); allocatedMem_.store(getMapAllocatedMemSize(), std::memory_order_relaxed); overflowSize_.store(getMapOverflowSize(), std::memory_order_relaxed); } - void emplaceUpdate(typename T::iterator &k) { + void emplaceUpdate(typename T::iterator& k) { updated_.emplace(k->first); updatesSize_.store(updated_.size(), std::memory_order_relaxed); updatesBuckets_.store(updated_.bucket_count(), std::memory_order_relaxed); diff --git a/cpp_src/core/index/uuid_index.cc b/cpp_src/core/index/uuid_index.cc index 7622020d3..dafac6a15 100644 --- a/cpp_src/core/index/uuid_index.cc +++ b/cpp_src/core/index/uuid_index.cc @@ -2,7 +2,7 @@ namespace reindexer { -void UuidIndex::Upsert(VariantArray &result, const VariantArray &keys, IdType id, bool &clearCache) { +void UuidIndex::Upsert(VariantArray& result, const VariantArray& keys, IdType id, bool& clearCache) { if (keys.empty() && !Opts().IsArray()) { result = {Upsert(Variant{Uuid{}}, id, clearCache)}; } else { @@ -10,8 +10,8 @@ void UuidIndex::Upsert(VariantArray &result, const VariantArray &keys, IdType id } } -std::unique_ptr IndexUuid_New(const IndexDef &idef, PayloadType &&payloadType, FieldsSet &&fields, - const NamespaceCacheConfigData &cacheCfg) { +std::unique_ptr IndexUuid_New(const IndexDef& idef, PayloadType&& payloadType, FieldsSet&& fields, + const NamespaceCacheConfigData& cacheCfg) { return std::make_unique(idef, std::move(payloadType), std::move(fields), cacheCfg); } diff --git a/cpp_src/core/indexdef.cc b/cpp_src/core/indexdef.cc index 74eab7234..ad79f4b96 100644 --- a/cpp_src/core/indexdef.cc +++ b/cpp_src/core/indexdef.cc @@ -11,22 +11,22 @@ namespace { using namespace std::string_view_literals; -static const std::vector &condsUsual() { +static const std::vector& condsUsual() { static const std::vector data{"SET"sv, "EQ"sv, "ANY"sv, "EMPTY"sv, "LT"sv, "LE"sv, "GT"sv, "GE"sv, "RANGE"sv}; return data; } -static const std::vector &condsText() { +static const std::vector& condsText() { static const std::vector data{"MATCH"sv}; return data; } -static const std::vector &condsBool() { +static const std::vector& condsBool() { static const std::vector data{"SET"sv, "EQ"sv, "ANY"sv, "EMPTY"sv}; return data; } -static const std::vector &condsGeom() { +static const std::vector& condsGeom() { static const std::vector data{"DWITHIN"sv}; return data; } @@ -35,11 +35,11 @@ enum Caps { CapComposite = 0x1, CapSortable = 0x2, CapFullText = 0x4 }; struct IndexInfo { const std::string_view fieldType, indexType; - const std::vector &conditions; + const std::vector& conditions; int caps; }; -static const std::unordered_map, std::equal_to> &availableIndexes() { +static const std::unordered_map, std::equal_to>& availableIndexes() { // clang-format off static const std::unordered_map, std::equal_to> data { {IndexIntHash, {"int"sv, "hash"sv, condsUsual(), CapSortable}}, @@ -112,7 +112,7 @@ IndexDef::IndexDef(std::string name, JsonPaths jsonPaths, IndexType type, IndexO this->FromType(type); } -bool IndexDef::IsEqual(const IndexDef &other, IndexComparison cmpType) const { +bool IndexDef::IsEqual(const IndexDef& other, IndexComparison cmpType) const { return name_ == other.name_ && jsonPaths_ == other.jsonPaths_ && Type() == other.Type() && fieldType_ == other.fieldType_ && opts_.IsEqual(other.opts_, cmpType) && expireAfter_ == other.expireAfter_; } @@ -130,20 +130,22 @@ IndexType IndexDef::Type() const { iType = "hash"; } } - for (const auto &it : availableIndexes()) { - if (fieldType_ == it.second.fieldType && iType == it.second.indexType) return it.first; + for (const auto& it : availableIndexes()) { + if (fieldType_ == it.second.fieldType && iType == it.second.indexType) { + return it.first; + } } throw Error(errParams, "Unsupported combination of field '%s' type '%s' and index type '%s'", name_, fieldType_, indexType_); } void IndexDef::FromType(IndexType type) { - const auto &it = availableIndexes().at(type); + const auto& it = availableIndexes().at(type); fieldType_ = it.fieldType; indexType_ = it.indexType; } -const std::vector &IndexDef::Conditions() const noexcept { +const std::vector& IndexDef::Conditions() const noexcept { const auto it{availableIndexes().find(Type())}; assertrx(it != availableIndexes().cend()); return it->second.conditions; @@ -159,18 +161,18 @@ bool isStore(IndexType type) noexcept { Error IndexDef::FromJSON(span json) { try { IndexDef::FromJSON(gason::JsonParser().Parse(json)); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "IndexDef: %s", ex.what()); - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; } -void IndexDef::FromJSON(const gason::JsonNode &root) { +void IndexDef::FromJSON(const gason::JsonNode& root) { name_ = root["name"].As(); jsonPaths_.clear(); - for (auto &subElem : root["json_paths"]) { + for (auto& subElem : root["json_paths"]) { jsonPaths_.push_back(subElem.As()); } fieldType_ = root["field_type"].As(); @@ -206,8 +208,10 @@ void IndexDef::FromJSON(const gason::JsonNode &root) { auto collateStr = root["collate_mode"].As(); if (!collateStr.empty()) { auto collateIt = find_if(begin(kAvailableCollates), end(kAvailableCollates), - [&collateStr](const std::pair &p) { return collateStr == p.second; }); - if (collateIt == end(kAvailableCollates)) throw Error(errParams, "Unknown collate mode %s", collateStr); + [&collateStr](const std::pair& p) { return collateStr == p.second; }); + if (collateIt == end(kAvailableCollates)) { + throw Error(errParams, "Unknown collate mode %s", collateStr); + } CollateMode collateValue = collateIt->first; opts_.SetCollateMode(collateValue); if (collateValue == CollateCustom) { @@ -216,7 +220,7 @@ void IndexDef::FromJSON(const gason::JsonNode &root) { } } -void IndexDef::GetJSON(WrSerializer &ser, int formatFlags) const { +void IndexDef::GetJSON(WrSerializer& ser, int formatFlags) const { JsonBuilder builder(ser); builder.Put("name", name_) @@ -256,13 +260,13 @@ void IndexDef::GetJSON(WrSerializer &ser, int formatFlags) const { builder.Put("is_sortable", isSortable(Type())); builder.Put("is_fulltext", IsFullText(Type())); auto arr = builder.Array("conditions"); - for (auto &cond : Conditions()) { + for (auto& cond : Conditions()) { arr.Put(nullptr, cond); } } auto arrNode = builder.Array("json_paths"); - for (auto &jsonPath : jsonPaths_) { + for (auto& jsonPath : jsonPaths_) { arrNode.Put(nullptr, jsonPath); } } diff --git a/cpp_src/core/indexdef.h b/cpp_src/core/indexdef.h index 91e8eb3e0..b621b6ee6 100644 --- a/cpp_src/core/indexdef.h +++ b/cpp_src/core/indexdef.h @@ -26,13 +26,13 @@ struct IndexDef { IndexDef(std::string name, JsonPaths jsonPaths, std::string indexType, std::string fieldType, IndexOpts opts, int64_t expireAfter); IndexDef(std::string name, std::string indexType, std::string fieldType, IndexOpts opts); IndexDef(std::string name, JsonPaths jsonPaths, IndexType type, IndexOpts opts); - bool IsEqual(const IndexDef &other, IndexComparison cmpType) const; + bool IsEqual(const IndexDef& other, IndexComparison cmpType) const; IndexType Type() const; - const std::vector &Conditions() const noexcept; + const std::vector& Conditions() const noexcept; void FromType(IndexType type); Error FromJSON(span json); - void FromJSON(const gason::JsonNode &jvalue); - void GetJSON(WrSerializer &ser, int formatFlags = 0) const; + void FromJSON(const gason::JsonNode& jvalue); + void GetJSON(WrSerializer& ser, int formatFlags = 0) const; public: std::string name_; diff --git a/cpp_src/core/indexopts.cc b/cpp_src/core/indexopts.cc index e41e9631a..b103a6b8c 100644 --- a/cpp_src/core/indexopts.cc +++ b/cpp_src/core/indexopts.cc @@ -68,21 +68,29 @@ void IndexOpts::Dump(T& os) const { needComma = true; } if (IsArray()) { - if (needComma) os << ", "; + if (needComma) { + os << ", "; + } os << "Array"; needComma = true; } if (IsDense()) { - if (needComma) os << ", "; + if (needComma) { + os << ", "; + } os << "Dense"; needComma = true; } if (IsSparse()) { - if (needComma) os << ", "; + if (needComma) { + os << ", "; + } os << "Sparse"; needComma = true; } - if (needComma) os << ", "; + if (needComma) { + os << ", "; + } os << RTreeType(); if (HasConfig()) { os << ", config: " << config; diff --git a/cpp_src/core/item.cc b/cpp_src/core/item.cc index 4454c7778..cee925eb2 100644 --- a/cpp_src/core/item.cc +++ b/cpp_src/core/item.cc @@ -7,7 +7,7 @@ namespace reindexer { -Item &Item::operator=(Item &&other) noexcept { +Item& Item::operator=(Item&& other) noexcept { if (&other != this) { if (impl_) { auto ns = impl_->GetNamespace(); @@ -45,10 +45,11 @@ Point Item::FieldRef::As() const { Item::FieldRef::operator Variant() const { VariantArray kr; - if (field_ >= 0) + if (field_ >= 0) { itemImpl_->GetPayload().Get(field_, kr); - else + } else { kr = itemImpl_->GetValueByJSONPath(jsonPath_); + } if (kr.size() != 1) { throw Error(errParams, "Invalid array access"); @@ -65,7 +66,7 @@ Item::FieldRef::operator VariantArray() const { return itemImpl_->GetValueByJSONPath(jsonPath_); } -Item::FieldRef &Item::FieldRef::operator=(Variant kr) { +Item::FieldRef& Item::FieldRef::operator=(Variant kr) { if (field_ >= 0) { itemImpl_->SetField(field_, VariantArray{std::move(kr)}); } else { @@ -75,10 +76,10 @@ Item::FieldRef &Item::FieldRef::operator=(Variant kr) { return *this; } -Item::FieldRef &Item::FieldRef::operator=(const char *str) { return operator=(p_string(str)); } -Item::FieldRef &Item::FieldRef::operator=(const std::string &str) { return operator=(p_string(&str)); } +Item::FieldRef& Item::FieldRef::operator=(const char* str) { return operator=(p_string(str)); } +Item::FieldRef& Item::FieldRef::operator=(const std::string& str) { return operator=(p_string(&str)); } -Item::FieldRef &Item::FieldRef::operator=(const VariantArray &krs) { +Item::FieldRef& Item::FieldRef::operator=(const VariantArray& krs) { if (field_ >= 0) { itemImpl_->SetField(field_, krs); } else { @@ -88,14 +89,14 @@ Item::FieldRef &Item::FieldRef::operator=(const VariantArray &krs) { } template -Item::FieldRef &Item::FieldRef::operator=(span arr) { +Item::FieldRef& Item::FieldRef::operator=(span arr) { constexpr static bool kIsStr = std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v; + std::is_same_v || std::is_same_v; if (field_ < 0) { VariantArray krs; krs.MarkArray(); krs.reserve(arr.size()); - std::transform(arr.begin(), arr.end(), std::back_inserter(krs), [](const T &t) { return Variant(t); }); + std::transform(arr.begin(), arr.end(), std::back_inserter(krs), [](const T& t) { return Variant(t); }); itemImpl_->SetField(jsonPath_, krs); return *this; } @@ -105,12 +106,14 @@ Item::FieldRef &Item::FieldRef::operator=(span arr) { if constexpr (kIsStr) { if (itemImpl_->IsUnsafe() || itemImpl_->Type()->Field(field_).Type().Is()) { - for (auto &elem : arr) { + for (auto& elem : arr) { pl.Set(field_, pos++, Variant(elem)); } } else { - if (!itemImpl_->holder_) itemImpl_->holder_ = std::make_unique>(); - for (auto &elem : arr) { + if (!itemImpl_->holder_) { + itemImpl_->holder_ = std::make_unique>(); + } + for (auto& elem : arr) { if constexpr (std::is_same_v) { itemImpl_->holder_->push_back(elem.toString()); } else { @@ -120,7 +123,7 @@ Item::FieldRef &Item::FieldRef::operator=(span arr) { } } } else { - for (auto &elem : arr) { + for (auto& elem : arr) { pl.Set(field_, pos++, Variant(elem)); } } @@ -138,7 +141,7 @@ Item::~Item() { } } -Error Item::FromJSON(std::string_view slice, char **endp, bool pkOnly) & noexcept { +Error Item::FromJSON(std::string_view slice, char** endp, bool pkOnly) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->FromJSON(slice, endp, pkOnly)); } @@ -154,15 +157,15 @@ void Item::FromCJSONImpl(std::string_view slice, bool pkOnly) & { impl_->FromCJS std::string_view Item::GetCJSON() { return impl_->GetCJSON(); } std::string_view Item::GetJSON() { return impl_->GetJSON(); } -Error Item::FromMsgPack(std::string_view buf, size_t &offset) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->FromMsgPack(buf, offset)); } +Error Item::FromMsgPack(std::string_view buf, size_t& offset) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->FromMsgPack(buf, offset)); } Error Item::FromProtobuf(std::string_view sbuf) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->FromProtobuf(sbuf)); } -Error Item::GetMsgPack(WrSerializer &wrser) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->GetMsgPack(wrser)); } +Error Item::GetMsgPack(WrSerializer& wrser) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->GetMsgPack(wrser)); } std::string_view Item::GetMsgPack() & { return impl_->GetMsgPack(); } -Error Item::GetProtobuf(WrSerializer &wrser) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->GetProtobuf(wrser)); } +Error Item::GetProtobuf(WrSerializer& wrser) & noexcept { RETURN_RESULT_NOEXCEPT(impl_->GetProtobuf(wrser)); } int Item::NumFields() const { return impl_->Type().NumFields(); } @@ -173,18 +176,18 @@ Item::FieldRef Item::operator[](int field) const { return FieldRef(field, impl_); } -Item::FieldRef Item::FieldRefByName(std::string_view name, ItemImpl &impl) { +Item::FieldRef Item::FieldRefByName(std::string_view name, ItemImpl& impl) { int field = 0; return (impl.Type().FieldByName(name, field)) ? FieldRef(field, &impl) : FieldRef(name, &impl); } int Item::GetFieldTag(std::string_view name) const { return impl_->NameTag(name); } FieldsSet Item::PkFields() const { return impl_->PkFields(); } -void Item::SetPrecepts(const std::vector &precepts) & { impl_->SetPrecepts(precepts); } +void Item::SetPrecepts(const std::vector& precepts) & { impl_->SetPrecepts(precepts); } bool Item::IsTagsUpdated() const noexcept { return impl_->tagsMatcher().isUpdated(); } int Item::GetStateToken() const noexcept { return impl_->tagsMatcher().stateToken(); } -Item &Item::Unsafe(bool enable) & noexcept { +Item& Item::Unsafe(bool enable) & noexcept { impl_->Unsafe(enable); return *this; } @@ -192,10 +195,10 @@ Item &Item::Unsafe(bool enable) & noexcept { int64_t Item::GetLSN() { return impl_->Value().GetLSN(); } void Item::setLSN(int64_t lsn) { impl_->Value().SetLSN(lsn); } -template Item::FieldRef &Item::FieldRef::operator=(span arr); -template Item::FieldRef &Item::FieldRef::operator=(span arr); -template Item::FieldRef &Item::FieldRef::operator=(span arr); -template Item::FieldRef &Item::FieldRef::operator=(span); -template Item::FieldRef &Item::FieldRef::operator=(span); +template Item::FieldRef& Item::FieldRef::operator=(span arr); +template Item::FieldRef& Item::FieldRef::operator=(span arr); +template Item::FieldRef& Item::FieldRef::operator=(span arr); +template Item::FieldRef& Item::FieldRef::operator=(span); +template Item::FieldRef& Item::FieldRef::operator=(span); } // namespace reindexer diff --git a/cpp_src/core/item.h b/cpp_src/core/item.h index 6234a2f60..90f6fa42f 100644 --- a/cpp_src/core/item.h +++ b/cpp_src/core/item.h @@ -28,10 +28,10 @@ class Item { Item() noexcept : impl_(nullptr), status_(errNotValid) {} /// Destroy Item ~Item(); - Item(const Item &) = delete; - Item(Item &&other) noexcept : impl_(other.impl_), status_(std::move(other.status_)), id_(other.id_) { other.impl_ = nullptr; } - Item &operator=(const Item &) = delete; - Item &operator=(Item &&) noexcept; + Item(const Item&) = delete; + Item(Item&& other) noexcept : impl_(other.impl_), status_(std::move(other.status_)), id_(other.id_) { other.impl_ = nullptr; } + Item& operator=(const Item&) = delete; + Item& operator=(Item&&) noexcept; /// Reference to field. Interface for field data manipulation class [[nodiscard]] FieldRef { @@ -60,12 +60,12 @@ class Item { /// @tparam T - type. Must be one of: int, int64_t, double /// @param val - value, which will be setted to field template - FieldRef &operator=(const T &val) { + FieldRef& operator=(const T& val) { return operator=(Variant(val)); } /// Set single point type value /// @param p - point value, which will be setted to field - FieldRef &operator=(Point p) { + FieldRef& operator=(Point p) { double arr[]{p.X(), p.Y()}; return operator=(span(arr, 2)); } @@ -74,24 +74,24 @@ class Item { /// @tparam T - type. Must be one of: int, int64_t, double /// @param arr - std::vector of T values, which will be setted to field template - FieldRef &operator=(span arr); + FieldRef& operator=(span arr); /// Set array of values to field /// @tparam T - type. Must be one of: int, int64_t, double /// @param arr - std::vector of T values, which will be setted to field template - FieldRef &operator=(const std::vector &arr) { + FieldRef& operator=(const std::vector& arr) { return operator=(span>(arr)); } /// Set string value to field /// If Item is in Unsafe Mode, then Item will not store str, but just keep pointer to str, /// application *MUST* hold str until end of life of Item /// @param str - pointer to C null-terminated string, which will be setted to field - FieldRef &operator=(const char *str); + FieldRef& operator=(const char* str); /// Set string value
/// If Item is in Unsafe Mode, then Item will not store str, but just keep pointer to str, /// application *MUST* hold str until end of life of Item /// @param str - std::string, which will be setted to field - FieldRef &operator=(const std::string &str); + FieldRef& operator=(const std::string& str); /// Get field index name std::string_view Name() const; @@ -105,15 +105,15 @@ class Item { operator VariantArray() const; /// Set field value /// @param kr - key reference object, which will be set to field - FieldRef &operator=(Variant kr); + FieldRef& operator=(Variant kr); /// Set field value /// @param krs - key reference object, which will be set to field - FieldRef &operator=(const VariantArray &krs); + FieldRef& operator=(const VariantArray& krs); private: - FieldRef(int field, ItemImpl *itemImpl) noexcept : itemImpl_(itemImpl), field_(field) {} - FieldRef(std::string_view jsonPath, ItemImpl *itemImpl) noexcept : itemImpl_(itemImpl), jsonPath_(jsonPath), field_(-1) {} - ItemImpl *itemImpl_; + FieldRef(int field, ItemImpl* itemImpl) noexcept : itemImpl_(itemImpl), field_(field) {} + FieldRef(std::string_view jsonPath, ItemImpl* itemImpl) noexcept : itemImpl_(itemImpl), jsonPath_(jsonPath), field_(-1) {} + ItemImpl* itemImpl_; std::string_view jsonPath_; int field_; }; @@ -124,7 +124,7 @@ class Item { /// @param slice - data slice with Json. /// @param endp - pointer to end of parsed part of slice /// @param pkOnly - if TRUE, that mean a JSON string will be parse only primary key fields - Error FromJSON(std::string_view slice, char **endp = nullptr, bool pkOnly = false) & noexcept; + Error FromJSON(std::string_view slice, char** endp = nullptr, bool pkOnly = false) & noexcept; /// Build item from JSON
/// If Item is in *Unsafe Mode*, then Item will not store slice, but just keep pointer to data in slice, @@ -137,7 +137,7 @@ class Item { /// Builds item from msgpack::object. /// @param buf - msgpack encoded data buffer. /// @param offset - position to start from. - Error FromMsgPack(std::string_view buf, size_t &offset) & noexcept; + Error FromMsgPack(std::string_view buf, size_t& offset) & noexcept; /// Builds item from Protobuf /// @param sbuf - Protobuf encoded data @@ -145,14 +145,14 @@ class Item { /// Packs data in msgpack format /// @param wrser - buffer to serialize data to - Error GetMsgPack(WrSerializer &wrser) & noexcept; + Error GetMsgPack(WrSerializer& wrser) & noexcept; /// Packs data in msgpack format /// @return data slice with MsgPack [[nodiscard]] std::string_view GetMsgPack() &; /// Packs item data to Protobuf /// @param wrser - buffer to serialize data to - Error GetProtobuf(WrSerializer &wrser) & noexcept; + Error GetProtobuf(WrSerializer& wrser) & noexcept; /// Serialize item to CJSON.
/// If Item is in *Unsafe Mode*, then returned slice is allocated in temporary buffer, and can be invalidated by any next operation @@ -192,7 +192,7 @@ class Item { [[nodiscard]] FieldsSet PkFields() const; /// Set additional percepts for modify operation /// @param precepts - strings in format "fieldName=Func()" - void SetPrecepts(const std::vector &precepts) &; + void SetPrecepts(const std::vector& precepts) &; /// Check was names tags updated while modify operation /// @return true: tags was updated. [[nodiscard]] bool IsTagsUpdated() const noexcept; @@ -206,7 +206,7 @@ class Item { /// The advantage of unsafe mode is speed. It does not call extra memory allocation from heap and copying data.
/// The disadvantage of unsafe mode is potentially danger code. Most of C++ stl containters in many cases invalidates references - /// and in unsafe mode caller is responsibe to guarantee, that all resources passed to Item will keep valid - Item &Unsafe(bool enable = true) & noexcept; + Item& Unsafe(bool enable = true) & noexcept; /// Get index type by field id /// @return either index type or Undefined (if index with this number does not exist or PayloadType is not available) KeyValueType GetIndexType(int field) const noexcept; @@ -214,15 +214,15 @@ class Item { /// @param name - field name /// @param itemImpl - item /// @return field's ref - static FieldRef FieldRefByName(std::string_view name, ItemImpl &itemImpl); + static FieldRef FieldRefByName(std::string_view name, ItemImpl& itemImpl); private: - explicit Item(ItemImpl *impl) : impl_(impl) {} - explicit Item(const Error &err) : impl_(nullptr), status_(err) {} + explicit Item(ItemImpl* impl) : impl_(impl) {} + explicit Item(const Error& err) : impl_(nullptr), status_(err) {} void setID(int id) { id_ = id; } void setLSN(int64_t lsn); - ItemImpl *impl_; + ItemImpl* impl_; Error status_; int id_ = -1; friend class NamespaceImpl; diff --git a/cpp_src/core/itemimpl.cc b/cpp_src/core/itemimpl.cc index e96d2c75f..2755900bb 100644 --- a/cpp_src/core/itemimpl.cc +++ b/cpp_src/core/itemimpl.cc @@ -12,7 +12,7 @@ namespace reindexer { -void ItemImpl::SetField(int field, const VariantArray &krs) { +void ItemImpl::SetField(int field, const VariantArray& krs) { validateModifyArray(krs); cjson_ = std::string_view(); payloadValue_.Clone(); @@ -20,8 +20,10 @@ void ItemImpl::SetField(int field, const VariantArray &krs) { !payloadType_.Field(field).Type().Is()) { VariantArray krsCopy; krsCopy.reserve(krs.size()); - if (!holder_) holder_ = std::make_unique>(); - for (auto &kr : krs) { + if (!holder_) { + holder_ = std::make_unique>(); + } + for (auto& kr : krs) { holder_->push_back(kr.As()); krsCopy.emplace_back(p_string{&holder_->back()}); } @@ -31,11 +33,11 @@ void ItemImpl::SetField(int field, const VariantArray &krs) { } } -void ItemImpl::ModifyField(std::string_view jsonPath, const VariantArray &keys, FieldModifyMode mode) { +void ItemImpl::ModifyField(std::string_view jsonPath, const VariantArray& keys, FieldModifyMode mode) { ModifyField(tagsMatcher_.path2indexedtag(jsonPath, mode != FieldModeDrop), keys, mode); } -void ItemImpl::ModifyField(const IndexedTagsPath &tagsPath, const VariantArray &keys, FieldModifyMode mode) { +void ItemImpl::ModifyField(const IndexedTagsPath& tagsPath, const VariantArray& keys, FieldModifyMode mode) { validateModifyArray(keys); payloadValue_.Clone(); Payload pl = GetPayload(); @@ -66,22 +68,22 @@ void ItemImpl::ModifyField(const IndexedTagsPath &tagsPath, const VariantArray & case FieldModeArrayPushFront: throw Error(errLogic, "Update mode is not supported: %d", mode); } - } catch (const Error &e) { + } catch (const Error& e) { throw Error(e.code(), "Error modifying field value: '%s'", e.what()); - } catch (std::exception &e) { + } catch (std::exception& e) { throw Error(errLogic, "Error modifying field value: '%s'", e.what()); } tupleData_ = ser_.DetachLStr(); - pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); + pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); } -void ItemImpl::SetField(std::string_view jsonPath, const VariantArray &keys) { ModifyField(jsonPath, keys, FieldModeSet); } +void ItemImpl::SetField(std::string_view jsonPath, const VariantArray& keys) { ModifyField(jsonPath, keys, FieldModeSet); } void ItemImpl::DropField(std::string_view jsonPath) { ModifyField(jsonPath, {}, FieldModeDrop); } Variant ItemImpl::GetField(int field) { return GetPayload().Get(field, 0); } -void ItemImpl::GetField(int field, VariantArray &values) { GetPayload().Get(field, values); } +void ItemImpl::GetField(int field, VariantArray& values) { GetPayload().Get(field, values); } -Error ItemImpl::FromMsgPack(std::string_view buf, size_t &offset) { +Error ItemImpl::FromMsgPack(std::string_view buf, size_t& offset) { payloadValue_.Clone(); Payload pl = GetPayload(); if (!msgPackDecoder_) { @@ -94,7 +96,7 @@ Error ItemImpl::FromMsgPack(std::string_view buf, size_t &offset) { Error err = msgPackDecoder_->Decode(buf, pl, ser_, offset); if (err.ok()) { tupleData_ = ser_.DetachLStr(); - pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); + pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); } return err; } @@ -111,17 +113,17 @@ Error ItemImpl::FromProtobuf(std::string_view buf) { Error err = decoder.Decode(buf, pl, ser_); if (err.ok()) { tupleData_ = ser_.DetachLStr(); - pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); + pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); } return err; } -Error ItemImpl::GetMsgPack(WrSerializer &wrser) { +Error ItemImpl::GetMsgPack(WrSerializer& wrser) { int startTag = 0; ConstPayload pl = GetConstPayload(); MsgPackEncoder msgpackEncoder(&tagsMatcher_); - const TagsLengths &tagsLengths = msgpackEncoder.GetTagsMeasures(pl); + const TagsLengths& tagsLengths = msgpackEncoder.GetTagsMeasures(pl); MsgPackBuilder msgpackBuilder(wrser, &tagsLengths, &startTag, ObjType::TypePlain, &tagsMatcher_); msgpackEncoder.Encode(pl, msgpackBuilder); @@ -137,7 +139,7 @@ std::string_view ItemImpl::GetMsgPack() { return ser_.Slice(); } -Error ItemImpl::GetProtobuf(WrSerializer &wrser) { +Error ItemImpl::GetProtobuf(WrSerializer& wrser) { assertrx(ns_); ConstPayload pl = GetConstPayload(); ProtobufBuilder protobufBuilder(&wrser, ObjType::TypePlain, schema_.get(), &tagsMatcher_); @@ -147,7 +149,7 @@ Error ItemImpl::GetProtobuf(WrSerializer &wrser) { } // Construct item from compressed json -void ItemImpl::FromCJSON(std::string_view slice, bool pkOnly, Recoder *recoder) { +void ItemImpl::FromCJSON(std::string_view slice, bool pkOnly, Recoder* recoder) { payloadValue_.Clone(); std::string_view data = slice; if (!unsafe_) { @@ -170,7 +172,9 @@ void ItemImpl::FromCJSON(std::string_view slice, bool pkOnly, Recoder *recoder) Payload pl = GetPayload(); pl.Reset(); - if (!holder_) holder_ = std::make_unique>(); + if (!holder_) { + holder_ = std::make_unique>(); + } CJsonDecoder decoder(tagsMatcher_, *holder_); ser_.Reset(); @@ -188,13 +192,15 @@ void ItemImpl::FromCJSON(std::string_view slice, bool pkOnly, Recoder *recoder) } } - if (!rdser.Eof()) throw Error(errParseJson, "Internal error - left unparsed data %d", rdser.Pos()); + if (!rdser.Eof()) { + throw Error(errParseJson, "Internal error - left unparsed data %d", rdser.Pos()); + } tupleData_ = ser_.DetachLStr(); - pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); + pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); } -Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool pkOnly) { +Error ItemImpl::FromJSON(std::string_view slice, char** endp, bool pkOnly) { payloadValue_.Clone(); std::string_view data = slice; cjson_ = std::string_view(); @@ -205,11 +211,11 @@ Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool pkOnly) { try { gason::JsonParser parser(nullptr); parser.Parse(data, &len); - *endp = const_cast(data.data()) + len; + *endp = const_cast(data.data()) + len; sourceData_.reset(new char[len]); std::copy(data.begin(), data.begin() + len, sourceData_.get()); data = std::string_view(sourceData_.get(), len); - } catch (const gason::Exception &e) { + } catch (const gason::Exception& e) { return Error(errParseJson, "Error parsing json: '%s'", e.what()); } } else { @@ -224,11 +230,13 @@ Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool pkOnly) { gason::JsonParser parser(&largeJSONStrings_); try { node = parser.Parse(giftStr(data), &len); - if (node.value.getTag() != gason::JSON_OBJECT) return Error(errParseJson, "Expected json object"); + if (node.value.getTag() != gason::JSON_OBJECT) { + return Error(errParseJson, "Expected json object"); + } if (unsafe_ && endp) { - *endp = const_cast(data.data()) + len; + *endp = const_cast(data.data()) + len; } - } catch (gason::Exception &e) { + } catch (gason::Exception& e) { return Error(errParseJson, "Error parsing json: '%s', pos: %d", e.what(), len); } @@ -243,11 +251,11 @@ Error ItemImpl::FromJSON(std::string_view slice, char **endp, bool pkOnly) { // Put tuple to field[0] tupleData_ = ser_.DetachLStr(); - pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); + pl.Set(0, Variant(p_string(reinterpret_cast(tupleData_.get())), Variant::no_hold_t{})); return err; } -void ItemImpl::FromCJSON(ItemImpl &other, Recoder *recoder) { +void ItemImpl::FromCJSON(ItemImpl& other, Recoder* recoder) { FromCJSON(other.GetCJSON(), false, recoder); cjson_ = {}; } @@ -267,12 +275,14 @@ std::string_view ItemImpl::GetJSON() { std::string_view ItemImpl::GetCJSON(bool withTagsMatcher) { withTagsMatcher = withTagsMatcher && tagsMatcher_.isUpdated(); - if (cjson_.size() && !withTagsMatcher) return cjson_; + if (cjson_.size() && !withTagsMatcher) { + return cjson_; + } ser_.Reset(); return GetCJSON(ser_, withTagsMatcher); } -std::string_view ItemImpl::GetCJSON(WrSerializer &ser, bool withTagsMatcher) { +std::string_view ItemImpl::GetCJSON(WrSerializer& ser, bool withTagsMatcher) { withTagsMatcher = withTagsMatcher && tagsMatcher_.isUpdated(); if (cjson_.size() && !withTagsMatcher) { @@ -307,8 +317,8 @@ VariantArray ItemImpl::GetValueByJSONPath(std::string_view jsonPath) { return krefs; } -void ItemImpl::validateModifyArray(const VariantArray &values) { - for (const auto &v : values) { +void ItemImpl::validateModifyArray(const VariantArray& values) { + for (const auto& v : values) { v.Type().EvaluateOneOf([](OneOf) {}, [](KeyValueType::Tuple) { diff --git a/cpp_src/core/itemimpl.h b/cpp_src/core/itemimpl.h index 18fe391db..999602087 100644 --- a/cpp_src/core/itemimpl.h +++ b/cpp_src/core/itemimpl.h @@ -15,10 +15,10 @@ namespace reindexer { struct ItemImplRawData { ItemImplRawData() = default; explicit ItemImplRawData(PayloadValue v) : payloadValue_(std::move(v)) {} - ItemImplRawData(const ItemImplRawData &) = delete; - ItemImplRawData(ItemImplRawData &&) = default; - ItemImplRawData &operator=(const ItemImplRawData &) = delete; - ItemImplRawData &operator=(ItemImplRawData &&) = default; + ItemImplRawData(const ItemImplRawData&) = delete; + ItemImplRawData(ItemImplRawData&&) = default; + ItemImplRawData& operator=(const ItemImplRawData&) = delete; + ItemImplRawData& operator=(ItemImplRawData&&) = default; PayloadValue payloadValue_; std::unique_ptr tupleData_; @@ -38,7 +38,7 @@ class ItemImpl : public ItemImplRawData { ItemImpl() = default; // Construct empty item - ItemImpl(PayloadType type, const TagsMatcher &tagsMatcher, const FieldsSet &pkFields = {}, std::shared_ptr schema = {}) + ItemImpl(PayloadType type, const TagsMatcher& tagsMatcher, const FieldsSet& pkFields = {}, std::shared_ptr schema = {}) : ItemImplRawData(PayloadValue(type.TotalSize(), nullptr, type.TotalSize() + 0x100)), payloadType_(std::move(type)), tagsMatcher_(tagsMatcher), @@ -48,64 +48,64 @@ class ItemImpl : public ItemImplRawData { } // Construct empty item - ItemImpl(PayloadType type, const TagsMatcher &tagsMatcher, const FieldsSet &pkFields, std::shared_ptr schema, - ItemImplRawData &&rawData) + ItemImpl(PayloadType type, const TagsMatcher& tagsMatcher, const FieldsSet& pkFields, std::shared_ptr schema, + ItemImplRawData&& rawData) : ItemImplRawData(std::move(rawData)), payloadType_(std::move(type)), tagsMatcher_(tagsMatcher), pkFields_(pkFields), schema_(std::move(schema)) {} - ItemImpl(PayloadType type, PayloadValue v, const TagsMatcher &tagsMatcher, std::shared_ptr schema = {}) + ItemImpl(PayloadType type, PayloadValue v, const TagsMatcher& tagsMatcher, std::shared_ptr schema = {}) : ItemImplRawData(std::move(v)), payloadType_(std::move(type)), tagsMatcher_(tagsMatcher), schema_{std::move(schema)} { tagsMatcher_.clearUpdated(); } - ItemImpl(const ItemImpl &) = delete; - ItemImpl(ItemImpl &&) = default; - ItemImpl &operator=(ItemImpl &&) = default; - ItemImpl &operator=(const ItemImpl &) = delete; + ItemImpl(const ItemImpl&) = delete; + ItemImpl(ItemImpl&&) = default; + ItemImpl& operator=(ItemImpl&&) = default; + ItemImpl& operator=(const ItemImpl&) = delete; - void ModifyField(std::string_view jsonPath, const VariantArray &keys, FieldModifyMode mode); - void ModifyField(const IndexedTagsPath &tagsPath, const VariantArray &keys, FieldModifyMode mode); - void SetField(int field, const VariantArray &krs); - void SetField(std::string_view jsonPath, const VariantArray &keys); + void ModifyField(std::string_view jsonPath, const VariantArray& keys, FieldModifyMode mode); + void ModifyField(const IndexedTagsPath& tagsPath, const VariantArray& keys, FieldModifyMode mode); + void SetField(int field, const VariantArray& krs); + void SetField(std::string_view jsonPath, const VariantArray& keys); void DropField(std::string_view jsonPath); Variant GetField(int field); - void GetField(int field, VariantArray &); + void GetField(int field, VariantArray&); FieldsSet PkFields() const { return pkFields_; } int NameTag(std::string_view name) const { return tagsMatcher_.name2tag(name); } VariantArray GetValueByJSONPath(std::string_view jsonPath); std::string_view GetJSON(); - Error FromJSON(std::string_view slice, char **endp = nullptr, bool pkOnly = false); - void FromCJSON(ItemImpl &other, Recoder *); + Error FromJSON(std::string_view slice, char** endp = nullptr, bool pkOnly = false); + void FromCJSON(ItemImpl& other, Recoder*); std::string_view GetCJSON(bool withTagsMatcher = false); - std::string_view GetCJSON(WrSerializer &ser, bool withTagsMatcher = false); - void FromCJSON(std::string_view slice, bool pkOnly = false, Recoder * = nullptr); - Error FromMsgPack(std::string_view sbuf, size_t &offset); + std::string_view GetCJSON(WrSerializer& ser, bool withTagsMatcher = false); + void FromCJSON(std::string_view slice, bool pkOnly = false, Recoder* = nullptr); + Error FromMsgPack(std::string_view sbuf, size_t& offset); Error FromProtobuf(std::string_view sbuf); - Error GetMsgPack(WrSerializer &wrser); + Error GetMsgPack(WrSerializer& wrser); std::string_view GetMsgPack(); - Error GetProtobuf(WrSerializer &wrser); + Error GetProtobuf(WrSerializer& wrser); - const PayloadType &Type() const noexcept { return payloadType_; } - PayloadValue &Value() noexcept { return payloadValue_; } - PayloadValue &RealValue() noexcept { return realValue_; } + const PayloadType& Type() const noexcept { return payloadType_; } + PayloadValue& Value() noexcept { return payloadValue_; } + PayloadValue& RealValue() noexcept { return realValue_; } Payload GetPayload() noexcept { return Payload(payloadType_, payloadValue_); } ConstPayload GetConstPayload() const noexcept { return ConstPayload(payloadType_, payloadValue_); } std::shared_ptr GetSchema() const noexcept { return schema_; } - TagsMatcher &tagsMatcher() noexcept { return tagsMatcher_; } - std::shared_ptr &schema() noexcept { return schema_; } + TagsMatcher& tagsMatcher() noexcept { return tagsMatcher_; } + std::shared_ptr& schema() noexcept { return schema_; } - void SetPrecepts(const std::vector &precepts) { + void SetPrecepts(const std::vector& precepts) { precepts_ = precepts; cjson_ = std::string_view(); } - const std::vector &GetPrecepts() const noexcept { return precepts_; } + const std::vector& GetPrecepts() const noexcept { return precepts_; } void Unsafe(bool enable) noexcept { unsafe_ = enable; } bool IsUnsafe() const noexcept { return unsafe_; } void Clear() { @@ -128,7 +128,7 @@ class ItemImpl : public ItemImplRawData { } void SetNamespace(std::shared_ptr ns) noexcept { ns_ = std::move(ns); } std::shared_ptr GetNamespace() const noexcept { return ns_; } - static void validateModifyArray(const VariantArray &values); + static void validateModifyArray(const VariantArray& values); private: // Index fields payload data diff --git a/cpp_src/core/itemmodifier.cc b/cpp_src/core/itemmodifier.cc index 3676bff56..07cdf12ae 100644 --- a/cpp_src/core/itemmodifier.cc +++ b/cpp_src/core/itemmodifier.cc @@ -9,7 +9,7 @@ namespace reindexer { std::string_view ItemModifier::FieldData::Name() const noexcept { return entry_.Column(); } -void ItemModifier::FieldData::appendAffectedIndexes(const NamespaceImpl &ns, CompositeFlags &affectedComposites) const { +void ItemModifier::FieldData::appendAffectedIndexes(const NamespaceImpl& ns, CompositeFlags& affectedComposites) const { const auto firstCompositePos = ns.indexes_.firstCompositePos(); const auto firstSparsePos = ns.indexes_.firstSparsePos(); const auto totalIndexes = ns.indexes_.totalSize(); @@ -29,8 +29,8 @@ void ItemModifier::FieldData::appendAffectedIndexes(const NamespaceImpl &ns, Com affected.set(Index()); } else { for (int i = 0; i < firstSparsePos; ++i) { - const auto &ptField = ns.payloadType_.Field(i); - for (const auto &jpath : ptField.JsonPaths()) { + const auto& ptField = ns.payloadType_.Field(i); + for (const auto& jpath : ptField.JsonPaths()) { auto tp = ns.tagsMatcher_.path2tag(jpath); if (Tagspath().IsNestedOrEqualTo(tp)) { affected.set(i); @@ -41,11 +41,13 @@ void ItemModifier::FieldData::appendAffectedIndexes(const NamespaceImpl &ns, Com } for (int i = firstCompositePos; i < totalIndexes; ++i) { - const auto &fields = ns.indexes_[i]->Fields(); + const auto& fields = ns.indexes_[i]->Fields(); const auto idxId = i - firstCompositePos; for (const auto f : fields) { - if (f == IndexValueType::SetByJsonPath) continue; + if (f == IndexValueType::SetByJsonPath) { + continue; + } if (affected.test(f)) { affectedComposites[idxId] = true; break; @@ -69,16 +71,18 @@ void ItemModifier::FieldData::appendAffectedIndexes(const NamespaceImpl &ns, Com class ItemModifier::RollBack_ModifiedPayload final : private RollBackBase { public: - RollBack_ModifiedPayload(ItemModifier &modifier, IdType id) noexcept : modifier_{modifier}, itemId_{id} {} - RollBack_ModifiedPayload(RollBack_ModifiedPayload &&) noexcept = default; + RollBack_ModifiedPayload(ItemModifier& modifier, IdType id) noexcept : modifier_{modifier}, itemId_{id} {} + RollBack_ModifiedPayload(RollBack_ModifiedPayload&&) noexcept = default; ~RollBack_ModifiedPayload() override { RollBack(); } void RollBack() { - if (IsDisabled()) return; + if (IsDisabled()) { + return; + } auto indexesCacheCleaner{modifier_.ns_.GetIndexesCacheCleaner()}; - const std::vector &data = modifier_.rollBackIndexData_.IndexStatus(); - PayloadValue &plValue = modifier_.ns_.items_[itemId_]; - NamespaceImpl::IndexesStorage &indexes = modifier_.ns_.indexes_; + const std::vector& data = modifier_.rollBackIndexData_.IndexStatus(); + PayloadValue& plValue = modifier_.ns_.items_[itemId_]; + NamespaceImpl::IndexesStorage& indexes = modifier_.ns_.indexes_; Payload plSave(modifier_.ns_.payloadType_, modifier_.rollBackIndexData_.GetPayloadValueBackup()); @@ -106,7 +110,7 @@ class ItemModifier::RollBack_ModifiedPayload final : private RollBackBase { if (indexes[i]->Opts().IsSparse()) { try { cpl.GetByJsonPath(indexes[i]->Fields().getTagsPath(0), vals, indexes[i]->KeyType()); - } catch (const Error &) { + } catch (const Error&) { vals.resize(0); } modifier_.rollBackIndexData_.CjsonChanged(); @@ -122,7 +126,7 @@ class ItemModifier::RollBack_ModifiedPayload final : private RollBackBase { if (indexes[i]->Opts().IsSparse()) { try { plSave.GetByJsonPath(indexes[i]->Fields().getTagsPath(0), oldData, indexes[i]->KeyType()); - } catch (const Error &) { + } catch (const Error&) { oldData.resize(0); } } else { @@ -140,7 +144,7 @@ class ItemModifier::RollBack_ModifiedPayload final : private RollBackBase { } } if (modifier_.rollBackIndexData_.IsCjsonChanged()) { - const Variant &v = cjsonKref.front(); + const Variant& v = cjsonKref.front(); bool needClearCache{false}; indexes[0]->Delete(v, itemId_, *modifier_.ns_.strHolder(), needClearCache); VariantArray keys; @@ -161,20 +165,20 @@ class ItemModifier::RollBack_ModifiedPayload final : private RollBackBase { } using RollBackBase::Disable; - RollBack_ModifiedPayload(const RollBack_ModifiedPayload &) = delete; - RollBack_ModifiedPayload operator=(const RollBack_ModifiedPayload &) = delete; - RollBack_ModifiedPayload operator=(RollBack_ModifiedPayload &&) = delete; + RollBack_ModifiedPayload(const RollBack_ModifiedPayload&) = delete; + RollBack_ModifiedPayload operator=(const RollBack_ModifiedPayload&) = delete; + RollBack_ModifiedPayload operator=(RollBack_ModifiedPayload&&) = delete; private: - ItemModifier &modifier_; + ItemModifier& modifier_; IdType itemId_; }; -ItemModifier::FieldData::FieldData(const UpdateEntry &entry, NamespaceImpl &ns, CompositeFlags &affectedComposites) +ItemModifier::FieldData::FieldData(const UpdateEntry& entry, NamespaceImpl& ns, CompositeFlags& affectedComposites) : entry_(entry), tagsPathWithLastIndex_{std::nullopt}, arrayIndex_(IndexValueType::NotSet), isIndex_(false) { if (ns.tryGetIndexByName(entry_.Column(), fieldIndex_)) { isIndex_ = true; - const auto &idx = *ns.indexes_[fieldIndex_]; + const auto& idx = *ns.indexes_[fieldIndex_]; auto jsonPathsSize = (idx.Opts().IsSparse() || static_cast(fieldIndex_) >= ns.payloadType_.NumFields()) ? idx.Fields().size() : ns.payloadType_.Field(fieldIndex_).JsonPaths().size(); @@ -183,7 +187,7 @@ ItemModifier::FieldData::FieldData(const UpdateEntry &entry, NamespaceImpl &ns, throw Error(errParams, "Ambiguity when updating field with several json paths by index name: '%s'", entry_.Column()); } - const auto &fields{idx.Fields()}; + const auto& fields{idx.Fields()}; if (fields.size() != 1) { throw Error(errParams, "Cannot update composite index: '%s'", entry_.Column()); } @@ -215,7 +219,9 @@ ItemModifier::FieldData::FieldData(const UpdateEntry &entry, NamespaceImpl &ns, IndexedTagsPath tagsPath = ns.tagsMatcher_.path2indexedtag(entry_.Column(), true); std::string jsonPath; for (size_t i = 0; i < tagsPath.size(); ++i) { - if (i) jsonPath += '.'; + if (i) { + jsonPath += '.'; + } const auto tagName = tagsPath[i].NameTag(); tp.emplace_back(tagName); jsonPath += ns.tagsMatcher_.tag2name(tagName); @@ -232,7 +238,7 @@ ItemModifier::FieldData::FieldData(const UpdateEntry &entry, NamespaceImpl &ns, throw Error(errParams, "Cannot find field by json: '%s'", entry_.Column()); } if (isIndex_) { - auto &lastTag = tagsPath_.back(); + auto& lastTag = tagsPath_.back(); if (lastTag.IsWithIndex()) { tagsPathWithLastIndex_ = tagsPath_; arrayIndex_ = lastTag.Index(); @@ -243,13 +249,13 @@ ItemModifier::FieldData::FieldData(const UpdateEntry &entry, NamespaceImpl &ns, appendAffectedIndexes(ns, affectedComposites); } -ItemModifier::ItemModifier(const std::vector &updateEntries, NamespaceImpl &ns) +ItemModifier::ItemModifier(const std::vector& updateEntries, NamespaceImpl& ns) : ns_(ns), updateEntries_(updateEntries), rollBackIndexData_(ns_.indexes_.totalSize()), affectedComposites_(ns_.indexes_.totalSize() - ns_.indexes_.firstCompositePos(), false) { - for (const UpdateEntry &updateField : updateEntries_) { - for (const auto &v : updateField.Values()) { + for (const UpdateEntry& updateField : updateEntries_) { + for (const auto& v : updateField.Values()) { v.Type().EvaluateOneOf([](OneOf) {}, [](KeyValueType::Tuple) { @@ -268,8 +274,8 @@ ItemModifier::ItemModifier(const std::vector &updateEntries, Namesp } } -[[nodiscard]] bool ItemModifier::Modify(IdType itemId, const NsContext &ctx) { - PayloadValue &pv = ns_.items_[itemId]; +[[nodiscard]] bool ItemModifier::Modify(IdType itemId, const NsContext& ctx) { + PayloadValue& pv = ns_.items_[itemId]; Payload pl(ns_.payloadType_, pv); pv.Clone(pl.RealSize()); @@ -281,7 +287,7 @@ ItemModifier::ItemModifier(const std::vector &updateEntries, Namesp deleteItemFromComposite(itemId); try { VariantArray values; - for (FieldData &field : fieldsToModify_) { + for (FieldData& field : fieldsToModify_) { // values must be assigned a value in if else below if (field.Details().IsExpression()) { assertrx(field.Details().Values().size() > 0); @@ -315,14 +321,14 @@ ItemModifier::ItemModifier(const std::vector &updateEntries, Namesp return rollBackIndexData_.IsPkModified(); } -void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values) { - PayloadValue &plData = ns_.items_[id]; +void ItemModifier::modifyCJSON(IdType id, FieldData& field, VariantArray& values) { + PayloadValue& plData = ns_.items_[id]; Payload pl(*ns_.payloadType_.get(), plData); VariantArray cjsonKref; pl.Get(0, cjsonKref); cjsonCache_.Reset(); - const Variant &v = cjsonKref.front(); + const Variant& v = cjsonKref.front(); if (v.Type().Is()) { cjsonCache_.Assign(std::string_view(p_string(v))); } @@ -338,7 +344,7 @@ void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values } item.setID(id); - ItemImpl *impl = item.impl_; + ItemImpl* impl = item.impl_; ns_.setFieldsBasedOnPrecepts(impl); ns_.updateTagsMatcherFromItem(impl); @@ -353,7 +359,7 @@ void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values do { // update the indexes, and then tuple (1,2,...,0) fieldIdx %= ns_.indexes_.firstCompositePos(); - Index &index = *(ns_.indexes_[fieldIdx]); + Index& index = *(ns_.indexes_[fieldIdx]); bool isIndexSparse = index.Opts().IsSparse(); assertrx(!isIndexSparse || (isIndexSparse && index.Fields().getTagsPathsLength() > 0)); @@ -361,7 +367,7 @@ void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values assertrx(index.Fields().getTagsPathsLength() > 0); try { plNew.GetByJsonPath(index.Fields().getTagsPath(0), ns_.skrefs, index.KeyType()); - } catch (const Error &) { + } catch (const Error&) { ns_.skrefs.resize(0); } } else { @@ -369,19 +375,23 @@ void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values } if (index.Opts().GetCollateMode() == CollateUTF8) { - for (auto &key : ns_.skrefs) key.EnsureUTF8(); + for (auto& key : ns_.skrefs) { + key.EnsureUTF8(); + } } if ((fieldIdx == 0) && (cjsonCache_.Size() > 0)) { bool needClearCache{false}; rollBackIndexData_.CjsonChanged(); index.Delete(Variant(cjsonCache_.Get()), id, *strHolder, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } else { if (isIndexSparse) { try { pl.GetByJsonPath(index.Fields().getTagsPath(0), ns_.krefs, index.KeyType()); - } catch (const Error &) { + } catch (const Error&) { ns_.krefs.resize(0); } } else if (index.Opts().IsArray()) { @@ -389,18 +399,24 @@ void ItemModifier::modifyCJSON(IdType id, FieldData &field, VariantArray &values } else { pl.Get(fieldIdx, ns_.krefs); } - if (ns_.krefs == ns_.skrefs) continue; + if (ns_.krefs == ns_.skrefs) { + continue; + } bool needClearCache{false}; rollBackIndexData_.IndexChanged(fieldIdx, index.Opts().IsPK()); index.Delete(ns_.krefs, id, *strHolder, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } ns_.krefs.resize(0); bool needClearCache{false}; rollBackIndexData_.IndexChanged(fieldIdx, index.Opts().IsPK()); index.Upsert(ns_.krefs, ns_.skrefs, id, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } if (!isIndexSparse) { pl.Set(fieldIdx, ns_.krefs); @@ -418,7 +434,7 @@ void ItemModifier::deleteItemFromComposite(IdType itemId) { for (int i = firstCompositePos; i < totalIndexes; ++i) { if (affectedComposites_[i - firstCompositePos]) { bool needClearCache{false}; - const auto &compositeIdx = ns_.indexes_[i]; + const auto& compositeIdx = ns_.indexes_[i]; rollBackIndexData_.IndexAndCJsonChanged(i, compositeIdx->Opts().IsPK()); compositeIdx->Delete(Variant(ns_.items_[itemId]), itemId, *strHolder, needClearCache); if (needClearCache && compositeIdx->IsOrdered()) { @@ -434,7 +450,7 @@ void ItemModifier::insertItemIntoComposite(IdType itemId) { for (int i = firstCompositePos; i < totalIndexes; ++i) { if (affectedComposites_[i - firstCompositePos]) { bool needClearCache{false}; - auto &compositeIdx = ns_.indexes_[i]; + auto& compositeIdx = ns_.indexes_[i]; rollBackIndexData_.IndexChanged(i, compositeIdx->Opts().IsPK()); compositeIdx->Upsert(Variant(ns_.items_[itemId]), itemId, needClearCache); if (needClearCache && compositeIdx->IsOrdered()) { @@ -444,9 +460,9 @@ void ItemModifier::insertItemIntoComposite(IdType itemId) { } } -void ItemModifier::modifyField(IdType itemId, FieldData &field, Payload &pl, VariantArray &values) { +void ItemModifier::modifyField(IdType itemId, FieldData& field, Payload& pl, VariantArray& values) { assertrx_throw(field.IsIndex()); - Index &index = *(ns_.indexes_[field.Index()]); + Index& index = *(ns_.indexes_[field.Index()]); if (!index.Opts().IsSparse() && field.Details().Mode() == FieldModeDrop /*&& !(field.arrayIndex() != IndexValueType::NotSet || field.tagspath().back().IsArrayNode())*/) { // TODO #1218 allow to drop array fields throw Error(errLogic, "It's only possible to drop sparse or non-index fields via UPDATE statement!"); @@ -458,7 +474,9 @@ void ItemModifier::modifyField(IdType itemId, FieldData &field, Payload &pl, Var } if (index.Opts().GetCollateMode() == CollateUTF8) { - for (const Variant &key : values) key.EnsureUTF8(); + for (const Variant& key : values) { + key.EnsureUTF8(); + } } auto strHolder = ns_.strHolder(); @@ -473,7 +491,7 @@ void ItemModifier::modifyField(IdType itemId, FieldData &field, Payload &pl, Var Variant oldTupleValue = item.GetField(0); oldTupleValue.EnsureHold(); bool needClearCache{false}; - auto &tupleIdx = ns_.indexes_[0]; + auto& tupleIdx = ns_.indexes_[0]; tupleIdx->Delete(oldTupleValue, itemId, *strHolder, needClearCache); Variant tupleValue; std::exception_ptr exception; @@ -483,7 +501,9 @@ void ItemModifier::modifyField(IdType itemId, FieldData &field, Payload &pl, Var exception = std::current_exception(); } tupleValue = tupleIdx->Upsert(item.GetField(0), itemId, needClearCache); - if (needClearCache && tupleIdx->IsOrdered()) indexesCacheCleaner.Add(tupleIdx->SortId()); + if (needClearCache && tupleIdx->IsOrdered()) { + indexesCacheCleaner.Add(tupleIdx->SortId()); + } pl.Set(0, std::move(tupleValue)); if (exception) { std::rethrow_exception(exception); @@ -491,8 +511,8 @@ void ItemModifier::modifyField(IdType itemId, FieldData &field, Payload &pl, Var } } -void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, VariantArray &values, Payload &pl) { - Index &index = *(ns_.indexes_[field.Index()]); +void ItemModifier::modifyIndexValues(IdType itemId, const FieldData& field, VariantArray& values, Payload& pl) { + Index& index = *(ns_.indexes_[field.Index()]); if (values.IsNullValue() && !index.Opts().IsArray()) { throw Error(errParams, "Non-array index fields cannot be set to null!"); } @@ -500,7 +520,7 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari auto indexesCacheCleaner{ns_.GetIndexesCacheCleaner()}; bool updateArrayPart = field.ArrayIndex() >= 0; bool isForAllItems = false; - for (const auto &tag : field.Tagspath()) { + for (const auto& tag : field.Tagspath()) { if (tag.IsArrayNode()) { updateArrayPart = true; } @@ -514,7 +534,7 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari } ns_.krefs.resize(0); - for (Variant &key : values) { + for (Variant& key : values) { key.convert(index.KeyType()); } @@ -524,7 +544,7 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari } int offset = -1, length = -1; isForAllItems = false; - for (const auto &tag : field.Tagspath()) { // TODO: Move to FieldEntry? + for (const auto& tag : field.Tagspath()) { // TODO: Move to FieldEntry? if (tag.IsForAllItems()) { isForAllItems = true; continue; @@ -536,9 +556,9 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari ns_.skrefs = pl.GetIndexedArrayData(field.TagspathWithLastIndex(), field.Index(), offset, length); if (offset < 0 || length < 0) { - const auto &path = field.TagspathWithLastIndex(); + const auto& path = field.TagspathWithLastIndex(); std::string indexesStr; - for (auto &p : path) { + for (auto& p : path) { if (p.Index() >= 0) { if (indexesStr.size()) { indexesStr.append(","); @@ -556,13 +576,17 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari bool needClearCache{false}; rollBackIndexData_.IndexChanged(field.Index(), index.Opts().IsPK()); index.Delete(ns_.skrefs.front(), itemId, *strHolder, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } bool needClearCache{false}; rollBackIndexData_.IndexChanged(field.Index(), index.Opts().IsPK()); index.Upsert(ns_.krefs, values, itemId, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } if (isForAllItems) { for (int i = offset, end = offset + length; i < end; ++i) { @@ -609,13 +633,17 @@ void ItemModifier::modifyIndexValues(IdType itemId, const FieldData &field, Vari bool needClearCache{false}; rollBackIndexData_.IndexChanged(field.Index(), index.Opts().IsPK()); index.Delete(ns_.skrefs, itemId, *strHolder, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } bool needClearCache{false}; rollBackIndexData_.IndexChanged(field.Index(), index.Opts().IsPK()); index.Upsert(ns_.krefs, kConcatIndexValues ? concatValues : values, itemId, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } if (!index.Opts().IsSparse()) { pl.Set(field.Index(), ns_.krefs); } diff --git a/cpp_src/core/itemmodifier.h b/cpp_src/core/itemmodifier.h index ea14afbd3..9cd09ab6d 100644 --- a/cpp_src/core/itemmodifier.h +++ b/cpp_src/core/itemmodifier.h @@ -12,23 +12,23 @@ class UpdateEntry; class ItemModifier { public: - ItemModifier(const std::vector &, NamespaceImpl &ns); - ItemModifier(const ItemModifier &) = delete; - ItemModifier &operator=(const ItemModifier &) = delete; - ItemModifier(ItemModifier &&) = delete; - ItemModifier &operator=(ItemModifier &&) = delete; + ItemModifier(const std::vector&, NamespaceImpl& ns); + ItemModifier(const ItemModifier&) = delete; + ItemModifier& operator=(const ItemModifier&) = delete; + ItemModifier(ItemModifier&&) = delete; + ItemModifier& operator=(ItemModifier&&) = delete; - [[nodiscard]] bool Modify(IdType itemId, const NsContext &ctx); - PayloadValue &GetPayloadValueBackup() { return rollBackIndexData_.GetPayloadValueBackup(); } + [[nodiscard]] bool Modify(IdType itemId, const NsContext& ctx); + PayloadValue& GetPayloadValueBackup() { return rollBackIndexData_.GetPayloadValueBackup(); } private: using CompositeFlags = h_vector; class FieldData { public: - FieldData(const UpdateEntry &entry, NamespaceImpl &ns, CompositeFlags &affectedComposites); - const UpdateEntry &Details() const noexcept { return entry_; } - const IndexedTagsPath &Tagspath() const noexcept { return tagsPath_; } - const IndexedTagsPath &TagspathWithLastIndex() const noexcept { + FieldData(const UpdateEntry& entry, NamespaceImpl& ns, CompositeFlags& affectedComposites); + const UpdateEntry& Details() const noexcept { return entry_; } + const IndexedTagsPath& Tagspath() const noexcept { return tagsPath_; } + const IndexedTagsPath& TagspathWithLastIndex() const noexcept { return tagsPathWithLastIndex_ ? *tagsPathWithLastIndex_ : tagsPath_; } int ArrayIndex() const noexcept { return arrayIndex_; } @@ -37,9 +37,9 @@ class ItemModifier { std::string_view Name() const noexcept; private: - void appendAffectedIndexes(const NamespaceImpl &ns, CompositeFlags &affectedComposites) const; + void appendAffectedIndexes(const NamespaceImpl& ns, CompositeFlags& affectedComposites) const; - const UpdateEntry &entry_; + const UpdateEntry& entry_; IndexedTagsPath tagsPath_; std::optional tagsPathWithLastIndex_; int fieldIndex_{IndexValueType::SetByJsonPath}; @@ -65,15 +65,15 @@ class ItemModifier { std::string_view cjson_; }; - void modifyField(IdType itemId, FieldData &field, Payload &pl, VariantArray &values); - void modifyCJSON(IdType itemId, FieldData &field, VariantArray &values); - void modifyIndexValues(IdType itemId, const FieldData &field, VariantArray &values, Payload &pl); + void modifyField(IdType itemId, FieldData& field, Payload& pl, VariantArray& values); + void modifyCJSON(IdType itemId, FieldData& field, VariantArray& values); + void modifyIndexValues(IdType itemId, const FieldData& field, VariantArray& values, Payload& pl); void deleteItemFromComposite(IdType itemId); void insertItemIntoComposite(IdType itemId); - NamespaceImpl &ns_; - const std::vector &updateEntries_; + NamespaceImpl& ns_; + const std::vector& updateEntries_; std::vector fieldsToModify_; CJsonCache cjsonCache_; @@ -82,7 +82,7 @@ class ItemModifier { class IndexRollBack { public: IndexRollBack(int indexCount) { data_.resize(indexCount); } - void Reset(PayloadValue &pv) { + void Reset(PayloadValue& pv) { pvSave_ = pv; pvSave_.Clone(); std::fill(data_.begin(), data_.end(), false); @@ -99,8 +99,8 @@ class ItemModifier { pkModified_ = pkModified_ || isPk; } void CjsonChanged() noexcept { cjsonChanged_ = true; } - PayloadValue &GetPayloadValueBackup() noexcept { return pvSave_; } - const std::vector &IndexStatus() const noexcept { return data_; } + PayloadValue& GetPayloadValueBackup() noexcept { return pvSave_; } + const std::vector& IndexStatus() const noexcept { return data_; } bool IsCjsonChanged() const noexcept { return cjsonChanged_; } bool IsPkModified() const noexcept { return pkModified_; } diff --git a/cpp_src/core/joincache.h b/cpp_src/core/joincache.h index 07fa4275c..63314f8d0 100644 --- a/cpp_src/core/joincache.h +++ b/cpp_src/core/joincache.h @@ -10,17 +10,17 @@ namespace reindexer { struct JoinCacheKey { JoinCacheKey() = default; - JoinCacheKey(JoinCacheKey &&other) = default; - JoinCacheKey(const JoinCacheKey &other) = default; - JoinCacheKey &operator=(JoinCacheKey &&other) = default; - JoinCacheKey &operator=(const JoinCacheKey &other) = delete; - void SetData(const Query &q) { + JoinCacheKey(JoinCacheKey&& other) = default; + JoinCacheKey(const JoinCacheKey& other) = default; + JoinCacheKey& operator=(JoinCacheKey&& other) = default; + JoinCacheKey& operator=(const JoinCacheKey& other) = delete; + void SetData(const Query& q) { WrSerializer ser; q.Serialize(ser, (SkipJoinQueries | SkipMergeQueries)); buf_.reserve(buf_.size() + ser.Len()); buf_.insert(buf_.end(), ser.Buf(), ser.Buf() + ser.Len()); } - void SetData(const Query &q1, const Query &q2) { + void SetData(const Query& q1, const Query& q2) { WrSerializer ser; q1.Serialize(ser, (SkipJoinQueries | SkipMergeQueries)); q2.Serialize(ser, (SkipJoinQueries | SkipMergeQueries)); @@ -32,12 +32,12 @@ struct JoinCacheKey { h_vector buf_; }; struct equal_join_cache_key { - bool operator()(const JoinCacheKey &lhs, const JoinCacheKey &rhs) const { + bool operator()(const JoinCacheKey& lhs, const JoinCacheKey& rhs) const { return (lhs.buf_.size() == rhs.buf_.size() && memcmp(lhs.buf_.data(), rhs.buf_.data(), lhs.buf_.size()) == 0); } }; struct hash_join_cache_key { - size_t operator()(const JoinCacheKey &cache) const { + size_t operator()(const JoinCacheKey& cache) const { uint64_t hash[2]; MurmurHash3_x64_128(cache.buf_.data(), cache.buf_.size(), 0, &hash); return hash[0]; diff --git a/cpp_src/core/keyvalue/key_string.h b/cpp_src/core/keyvalue/key_string.h index dd70626e2..94b678fec 100644 --- a/cpp_src/core/keyvalue/key_string.h +++ b/cpp_src/core/keyvalue/key_string.h @@ -17,19 +17,19 @@ class base_key_string : public std::string { bind(); } template - base_key_string(Args &&...args) : std::string(std::forward(args)...) { + base_key_string(Args&&... args) : std::string(std::forward(args)...) { export_hdr_.refcounter.store(0, std::memory_order_release); bind(); } template - void assign(Args &&...args) { + void assign(Args&&... args) { const_string::assign(std::forward(args)...); bind(); } static ptrdiff_t export_hdr_offset() noexcept { static base_key_string sample; - return ptrdiff_t(reinterpret_cast(&sample.export_hdr_) - reinterpret_cast(&sample)); + return ptrdiff_t(reinterpret_cast(&sample.export_hdr_) - reinterpret_cast(&sample)); } size_t heap_size() noexcept { // Check for SSO (small string optimization) @@ -42,38 +42,38 @@ class base_key_string : public std::string { // delete all modification methods - to be sure, that base_key_string is mutable, and export will not invalidate after construction iterator begin() = delete; iterator end() = delete; - char &operator[](int) = delete; + char& operator[](int) = delete; template - void insert(Args &&...args) = delete; + void insert(Args&&... args) = delete; template - void append(Args &&...args) = delete; + void append(Args&&... args) = delete; template - void copy(Args &&...args) = delete; + void copy(Args&&... args) = delete; template - void replace(Args &&...args) = delete; + void replace(Args&&... args) = delete; void push_back(char c) = delete; template - void erase(Args &&...args) = delete; + void erase(Args&&... args) = delete; template - void reserve(Args &&...args) = delete; + void reserve(Args&&... args) = delete; template - void resize(Args &&...args) = delete; + void resize(Args&&... args) = delete; void at(int) = delete; void shrink_to_fit() = delete; void clear() = delete; protected: - friend void intrusive_ptr_add_ref(base_key_string *x) noexcept { + friend void intrusive_ptr_add_ref(base_key_string* x) noexcept { if (x) { x->export_hdr_.refcounter.fetch_add(1, std::memory_order_relaxed); } } - friend void intrusive_ptr_release(base_key_string *x) noexcept { + friend void intrusive_ptr_release(base_key_string* x) noexcept { if (x && x->export_hdr_.refcounter.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete x; // NOLINT(*.NewDelete) False positive } } - friend bool intrusive_ptr_is_unique(base_key_string *x) noexcept { + friend bool intrusive_ptr_is_unique(base_key_string* x) noexcept { // std::memory_order_acquire - is essential for COW constructions based on intrusive_ptr return !x || (x->export_hdr_.refcounter.load(std::memory_order_acquire) == 1); } @@ -84,7 +84,7 @@ class base_key_string : public std::string { } struct export_hdr { - const void *cstr; + const void* cstr; int32_t len; std::atomic refcounter; } export_hdr_; @@ -99,16 +99,16 @@ class key_string : public intrusive_ptr { }; template -key_string make_key_string(Args &&...args) { +key_string make_key_string(Args&&... args) { return key_string(new base_key_string(std::forward(args)...)); } -inline static bool operator==(const key_string &rhs, const key_string &lhs) noexcept { return *rhs == *lhs; } +inline static bool operator==(const key_string& rhs, const key_string& lhs) noexcept { return *rhs == *lhs; } // Unchecked cast to derived class! // It assumes, that all strings in payload are intrusive_ptr -inline void key_string_add_ref(std::string *str) noexcept { intrusive_ptr_add_ref(reinterpret_cast(str)); } -inline void key_string_release(std::string *str) noexcept { intrusive_ptr_release(reinterpret_cast(str)); } +inline void key_string_add_ref(std::string* str) noexcept { intrusive_ptr_add_ref(reinterpret_cast(str)); } +inline void key_string_release(std::string* str) noexcept { intrusive_ptr_release(reinterpret_cast(str)); } template <> struct is_recommends_sc_hash_map { @@ -120,13 +120,13 @@ namespace std { template <> struct hash { public: - size_t operator()(const reindexer::base_key_string &obj) const { return hash()(obj); } + size_t operator()(const reindexer::base_key_string& obj) const { return hash()(obj); } }; template <> struct hash { public: - size_t operator()(const reindexer::key_string &obj) const { return hash()(*obj); } + size_t operator()(const reindexer::key_string& obj) const { return hash()(*obj); } }; } // namespace std diff --git a/cpp_src/core/keyvalue/p_string.cc b/cpp_src/core/keyvalue/p_string.cc index f36990497..e63b07dae 100644 --- a/cpp_src/core/keyvalue/p_string.cc +++ b/cpp_src/core/keyvalue/p_string.cc @@ -3,14 +3,16 @@ #include namespace reindexer { -void p_string::Dump(std::ostream &os) const { +void p_string::Dump(std::ostream& os) const { os << "{p: " << std::hex << v << std::dec; if (v) { const auto l = length(); os << ", length: " << l << ", [" << std::hex; - const char *d = data(); + const char* d = data(); for (size_t i = 0; i < l; ++i) { - if (i != 0) os << ' '; + if (i != 0) { + os << ' '; + } os << static_cast(d[i]); } os << std::dec << ']'; diff --git a/cpp_src/core/keyvalue/p_string.h b/cpp_src/core/keyvalue/p_string.h index d4c76bebe..985a3df9b 100644 --- a/cpp_src/core/keyvalue/p_string.h +++ b/cpp_src/core/keyvalue/p_string.h @@ -20,11 +20,11 @@ struct v_string_hdr { struct l_msgpack_hdr { uint32_t size; - const char *ptr; + const char* ptr; }; struct json_string_ftr { - const char *data; + const char* data; }; // Dark @@ -49,67 +49,67 @@ struct p_string { constexpr static uint64_t tagShift = 59ULL; constexpr static uint64_t tagMask = 0x7ULL << tagShift; - explicit p_string(const l_string_hdr *lstr) noexcept : v((uintptr_t(lstr) & ~tagMask) | (tagLstr << tagShift)) {} - explicit p_string(const v_string_hdr *vstr) noexcept : v((uintptr_t(vstr) & ~tagMask) | (tagVstr << tagShift)) {} - explicit p_string(const l_msgpack_hdr *mstr) noexcept : v((uintptr_t(mstr) & ~tagMask) | (tagMsgPackStr << tagShift)) {} - explicit p_string(const char *cstr) noexcept : v((uintptr_t(cstr) & ~tagMask) | (tagCstr << tagShift)) {} + explicit p_string(const l_string_hdr* lstr) noexcept : v((uintptr_t(lstr) & ~tagMask) | (tagLstr << tagShift)) {} + explicit p_string(const v_string_hdr* vstr) noexcept : v((uintptr_t(vstr) & ~tagMask) | (tagVstr << tagShift)) {} + explicit p_string(const l_msgpack_hdr* mstr) noexcept : v((uintptr_t(mstr) & ~tagMask) | (tagMsgPackStr << tagShift)) {} + explicit p_string(const char* cstr) noexcept : v((uintptr_t(cstr) & ~tagMask) | (tagCstr << tagShift)) {} explicit p_string(const json_string_ftr jstr) noexcept : v((uintptr_t(jstr.data) & ~tagMask) | (tagJsonStr << tagShift)) {} - explicit p_string(const std::string *str) noexcept : v((uintptr_t(str) & ~tagMask) | (tagCxxstr << tagShift)) {} - explicit p_string(const key_string &str) noexcept : v((uintptr_t(str.get()) & ~tagMask) | (tagKeyString << tagShift)) {} - explicit p_string(const std::string_view *ptr) noexcept : v((uintptr_t(ptr) & ~tagMask) | (tagSlice << tagShift)) {} + explicit p_string(const std::string* str) noexcept : v((uintptr_t(str) & ~tagMask) | (tagCxxstr << tagShift)) {} + explicit p_string(const key_string& str) noexcept : v((uintptr_t(str.get()) & ~tagMask) | (tagKeyString << tagShift)) {} + explicit p_string(const std::string_view* ptr) noexcept : v((uintptr_t(ptr) & ~tagMask) | (tagSlice << tagShift)) {} p_string() noexcept : v(0) {} operator std::string_view() const noexcept { switch (type()) { case tagCstr: { - const auto str = reinterpret_cast(ptr()); + const auto str = reinterpret_cast(ptr()); return std::string_view(str, strlen(str)); } case tagMsgPackStr: { - const auto &str = *reinterpret_cast(ptr()); + const auto& str = *reinterpret_cast(ptr()); return std::string_view(str.ptr, str.size); } case tagCxxstr: case tagKeyString: - return std::string_view(*reinterpret_cast(ptr())); + return std::string_view(*reinterpret_cast(ptr())); case tagSlice: - return *reinterpret_cast(ptr()); + return *reinterpret_cast(ptr()); case tagLstr: { - const auto &str = *reinterpret_cast(ptr()); + const auto& str = *reinterpret_cast(ptr()); return std::string_view(&str.data[0], str.length); } case tagVstr: { - auto p = reinterpret_cast(ptr()); + auto p = reinterpret_cast(ptr()); auto l = scan_varint(10, p); - return std::string_view(reinterpret_cast(p) + l, parse_uint32(l, p)); + return std::string_view(reinterpret_cast(p) + l, parse_uint32(l, p)); } case tagJsonStr: { - return json_string::to_string_view(reinterpret_cast(ptr())); + return json_string::to_string_view(reinterpret_cast(ptr())); } default: abort(); } } - const char *data() const noexcept { + const char* data() const noexcept { switch (type()) { case tagCstr: - return reinterpret_cast(ptr()); + return reinterpret_cast(ptr()); case tagCxxstr: case tagKeyString: - return (reinterpret_cast(ptr()))->data(); + return (reinterpret_cast(ptr()))->data(); case tagMsgPackStr: - return (reinterpret_cast(ptr()))->ptr; + return (reinterpret_cast(ptr()))->ptr; case tagSlice: - return (reinterpret_cast(ptr()))->data(); + return (reinterpret_cast(ptr()))->data(); case tagLstr: - return &(reinterpret_cast(ptr()))->data[0]; + return &(reinterpret_cast(ptr()))->data[0]; case tagVstr: { - auto p = reinterpret_cast(ptr()); + auto p = reinterpret_cast(ptr()); auto l = scan_varint(10, p); - return reinterpret_cast(p) + l; + return reinterpret_cast(p) + l; } case tagJsonStr: { - const auto sv = json_string::to_string_view(reinterpret_cast(ptr())); + const auto sv = json_string::to_string_view(reinterpret_cast(ptr())); return sv.data(); } default: @@ -121,23 +121,23 @@ struct p_string { if (v) { switch (type()) { case tagCstr: - return strlen(reinterpret_cast(ptr())); + return strlen(reinterpret_cast(ptr())); case tagCxxstr: case tagKeyString: - return (reinterpret_cast(ptr()))->length(); + return (reinterpret_cast(ptr()))->length(); case tagSlice: - return (reinterpret_cast(ptr()))->size(); + return (reinterpret_cast(ptr()))->size(); case tagLstr: - return (reinterpret_cast(ptr()))->length; + return (reinterpret_cast(ptr()))->length; case tagMsgPackStr: - return (reinterpret_cast(ptr()))->size; + return (reinterpret_cast(ptr()))->size; case tagVstr: { - auto p = reinterpret_cast(ptr()); + auto p = reinterpret_cast(ptr()); auto l = scan_varint(10, p); return parse_uint32(l, p); } case tagJsonStr: { - return json_string::length(reinterpret_cast(ptr())); + return json_string::length(reinterpret_cast(ptr())); } default: abort(); @@ -156,23 +156,23 @@ struct p_string { bool operator==(p_string other) const noexcept { return compare(other) == 0; } bool operator>=(p_string other) const noexcept { return compare(other) >= 0; } bool operator<=(p_string other) const noexcept { return compare(other) <= 0; } - const std::string *getCxxstr() const noexcept { + const std::string* getCxxstr() const noexcept { assertrx(type() == tagCxxstr || type() == tagKeyString); - return reinterpret_cast(ptr()); + return reinterpret_cast(ptr()); } key_string getKeyString() const noexcept { assertrx(type() == tagKeyString); - auto str = reinterpret_cast(const_cast(ptr())); + auto str = reinterpret_cast(const_cast(ptr())); return key_string(str); } int type() const noexcept { return (v & tagMask) >> tagShift; } std::string toString() const { return std::string(data(), length()); } - void Dump(std::ostream &os) const; + void Dump(std::ostream& os) const; protected: - const void *ptr() const noexcept { return v ? reinterpret_cast(v & ~tagMask) : ""; } + const void* ptr() const noexcept { return v ? reinterpret_cast(v & ~tagMask) : ""; } uint64_t v; }; @@ -182,10 +182,10 @@ inline span giftStr(p_string s) noexcept { if (s.type() == p_string::tagCxxstr) { // Trying to avoid COW-string problems auto strPtr = s.getCxxstr(); - return span(const_cast(strPtr)->data(), strPtr->size()); + return span(const_cast(strPtr)->data(), strPtr->size()); } #endif // _GLIBCXX_USE_CXX11_ABI - return span(const_cast(s.data()), s.size()); + return span(const_cast(s.data()), s.size()); } } // namespace reindexer @@ -193,7 +193,7 @@ namespace std { template <> struct hash { public: - size_t operator()(const reindexer::p_string &str) const noexcept { return reindexer::_Hash_bytes(str.data(), str.length()); } + size_t operator()(const reindexer::p_string& str) const noexcept { return reindexer::_Hash_bytes(str.data(), str.length()); } }; } // namespace std diff --git a/cpp_src/core/keyvalue/relaxed_variant_hash.h b/cpp_src/core/keyvalue/relaxed_variant_hash.h index 3fa3d6ea2..95df74da1 100644 --- a/cpp_src/core/keyvalue/relaxed_variant_hash.h +++ b/cpp_src/core/keyvalue/relaxed_variant_hash.h @@ -7,7 +7,7 @@ namespace reindexer { template struct RelaxedComparator { - static bool equal(const Variant &lhs, const Variant &rhs) { + static bool equal(const Variant& lhs, const Variant& rhs) { return lhs.RelaxCompare(rhs) == ComparationResult::Eq; } }; @@ -15,26 +15,14 @@ struct RelaxedComparator { template struct RelaxedHasher { constexpr static size_t indexesCount = notComparable == NotComparable::Return ? 7 : 6; - static std::pair hash(const Variant &v) noexcept(notComparable == NotComparable::Return) { + static std::pair hash(const Variant& v) noexcept(notComparable == NotComparable::Return) { return v.Type().EvaluateOneOf( - overloaded{[&v](KeyValueType::Bool) noexcept { - return std::pair{0, v.Hash()}; - }, - [&v](KeyValueType::Int) noexcept { - return std::pair{1, v.Hash()}; - }, - [&v](KeyValueType::Int64) noexcept { - return std::pair{2, v.Hash()}; - }, - [&v](KeyValueType::Double) noexcept { - return std::pair{3, v.Hash()}; - }, - [&v](KeyValueType::String) noexcept { - return std::pair{4, v.Hash()}; - }, - [&v](KeyValueType::Uuid) noexcept { - return std::pair{5, v.Hash()}; - }, + overloaded{[&v](KeyValueType::Bool) noexcept { return std::pair{0, v.Hash()}; }, + [&v](KeyValueType::Int) noexcept { return std::pair{1, v.Hash()}; }, + [&v](KeyValueType::Int64) noexcept { return std::pair{2, v.Hash()}; }, + [&v](KeyValueType::Double) noexcept { return std::pair{3, v.Hash()}; }, + [&v](KeyValueType::String) noexcept { return std::pair{4, v.Hash()}; }, + [&v](KeyValueType::Uuid) noexcept { return std::pair{5, v.Hash()}; }, [&v](OneOf) noexcept( notComparable == NotComparable::Return) -> std::pair { if constexpr (notComparable == NotComparable::Return) { @@ -44,7 +32,7 @@ struct RelaxedHasher { } }}); } - static size_t hash(size_t i, const Variant &v) { + static size_t hash(size_t i, const Variant& v) { switch (i) { case 0: return v.Type().EvaluateOneOf( diff --git a/cpp_src/core/keyvalue/uuid.h b/cpp_src/core/keyvalue/uuid.h index 01c3ad81d..731450ad8 100644 --- a/cpp_src/core/keyvalue/uuid.h +++ b/cpp_src/core/keyvalue/uuid.h @@ -3,9 +3,9 @@ #include #include #include +#include "estl/comparation_result.h" #include "tools/assertrx.h" #include "variant.h" -#include "estl/comparation_result.h" namespace reindexer { class Uuid; @@ -62,7 +62,8 @@ class Uuid { [[nodiscard]] explicit operator std::string() const; [[nodiscard]] ComparationResult Compare(const Uuid& other) const noexcept { if (data_[0] == other.data_[0]) { - return data_[1] == other.data_[1] ? ComparationResult::Eq : (data_[1] < other.data_[1] ? ComparationResult::Lt : ComparationResult::Gt); + return data_[1] == other.data_[1] ? ComparationResult::Eq + : (data_[1] < other.data_[1] ? ComparationResult::Lt : ComparationResult::Gt); } else { return data_[0] < other.data_[0] ? ComparationResult::Lt : ComparationResult::Gt; } diff --git a/cpp_src/core/keyvalue/variant.cc b/cpp_src/core/keyvalue/variant.cc index 81616bbc0..5005ef5dd 100644 --- a/cpp_src/core/keyvalue/variant.cc +++ b/cpp_src/core/keyvalue/variant.cc @@ -21,10 +21,10 @@ Variant::Variant(p_string v, hold_t) : variant_{0, 0, KeyValueType::String{}} { *cast() = v; } } -Variant::Variant(const VariantArray &values) : variant_{0, 1, KeyValueType::Tuple{}} { +Variant::Variant(const VariantArray& values) : variant_{0, 1, KeyValueType::Tuple{}} { WrSerializer ser; ser.PutVarUint(values.size()); - for (const Variant &kv : values) { + for (const Variant& kv : values) { ser.PutVariant(kv); } new (cast()) key_string(make_key_string(ser.Slice())); @@ -44,23 +44,23 @@ Variant::Variant(Uuid uuid) noexcept : uuid_() { } } -static void serialize(WrSerializer &, const std::tuple<> &) noexcept {} +static void serialize(WrSerializer&, const std::tuple<>&) noexcept {} template -void serialize(WrSerializer &ser, const std::tuple &v) { +void serialize(WrSerializer& ser, const std::tuple& v) { ser.PutVariant(Variant{std::get<0>(v)}); serialize(ser, tail(v)); } template -Variant::Variant(const std::tuple &values) : variant_{0, 1, KeyValueType::Tuple{}} { +Variant::Variant(const std::tuple& values) : variant_{0, 1, KeyValueType::Tuple{}} { WrSerializer ser; ser.PutVarUint(sizeof...(Ts)); serialize(ser, values); new (cast()) key_string(make_key_string(ser.Slice())); } -template Variant::Variant(const std::tuple &); -template Variant::Variant(const std::tuple &); +template Variant::Variant(const std::tuple&); +template Variant::Variant(const std::tuple&); template inline static void assertKeyType([[maybe_unused]] KeyValueType got) noexcept { @@ -95,12 +95,16 @@ Variant::operator Point() const { return static_cast(getCompositeValues() template <> Point Variant::As() const { assertrx(!isUuid()); - if (!variant_.type.Is()) throw Error(errParams, "Can't convert %s to Point", variant_.type.Name()); + if (!variant_.type.Is()) { + throw Error(errParams, "Can't convert %s to Point", variant_.type.Name()); + } return static_cast(getCompositeValues()); } template <> Uuid Variant::As() const { - if (isUuid()) return Uuid{*this}; + if (isUuid()) { + return Uuid{*this}; + } return variant_.type.EvaluateOneOf( [&](KeyValueType::Uuid) { return Uuid{*this}; }, [&](KeyValueType::String) { return Uuid{this->As()}; }, [&](OneOf) noexcept {}); } -Variant &Variant::EnsureHold() & { - if (isUuid() || variant_.hold == 1) return *this; +Variant& Variant::EnsureHold() & { + if (isUuid() || variant_.hold == 1) { + return *this; + } variant_.type.EvaluateOneOf([&](OneOf) { *this = Variant(this->operator key_string()); }, - [&](KeyValueType::Composite) { *this = Variant(this->operator const PayloadValue &()); }, + [&](KeyValueType::Composite) { *this = Variant(this->operator const PayloadValue&()); }, [](OneOf) noexcept {}); return *this; @@ -180,9 +186,9 @@ p_string Variant::As() const { } template <> -std::string Variant::As(const PayloadType &pt, const FieldsSet &fields) const { +std::string Variant::As(const PayloadType& pt, const FieldsSet& fields) const { if (!isUuid() && variant_.type.Is()) { - ConstPayload pl(pt, operator const PayloadValue &()); + ConstPayload pl(pt, operator const PayloadValue&()); VariantArray va; size_t tagsPathIdx = 0; for (auto field : fields) { @@ -226,7 +232,9 @@ std::optional tryParseAs(std::string_view str) noexcept { template <> std::optional tryParseAs(std::string_view str) noexcept { - if (str.empty()) return 0.0; + if (str.empty()) { + return 0.0; + } using namespace double_conversion; static const StringToDoubleConverter converter{StringToDoubleConverter::ALLOW_LEADING_SPACES | StringToDoubleConverter::ALLOW_TRAILING_SPACES | @@ -272,7 +280,7 @@ int Variant::As() const { [&](KeyValueType::Uuid) -> int { throw Error(errParams, "Can't convert '%s' to number", std::string{Uuid{*this}}); }); } -static std::optional tryConvertToBool(const p_string &str) { +static std::optional tryConvertToBool(const p_string& str) { using namespace std::string_view_literals; if (iequals(str, "true"sv)) { return true; @@ -354,7 +362,7 @@ double Variant::As() const { } template -ComparationResult Variant::Compare(const Variant &other, const CollateOpts &collateOpts) const { +ComparationResult Variant::Compare(const Variant& other, const CollateOpts& collateOpts) const { if (isUuid()) { assertrx(other.Type().Is()); return Uuid{*this}.Compare(Uuid{other}); @@ -403,8 +411,8 @@ ComparationResult Variant::Compare(const Variant &other, const CollateOpts &coll [](OneOf) noexcept -> ComparationResult { abort(); }); } } -template ComparationResult Variant::Compare(const Variant &, const CollateOpts &) const; -template ComparationResult Variant::Compare(const Variant &, const CollateOpts &) const; +template ComparationResult Variant::Compare(const Variant&, const CollateOpts&) const; +template ComparationResult Variant::Compare(const Variant&, const CollateOpts&) const; template ComparationResult Variant::relaxCompareWithString(std::string_view str) const noexcept(notComparable == NotComparable::Return) { @@ -507,7 +515,7 @@ ComparationResult Variant::relaxCompareWithString(std::string_view str) const no class Comparator { public: - explicit Comparator(const Variant &v1, const Variant &v2) noexcept : v1_{v1}, v2_{v2} {} + explicit Comparator(const Variant& v1, const Variant& v2) noexcept : v1_{v1}, v2_{v2} {} RX_ALWAYS_INLINE ComparationResult operator()(KeyValueType::Bool, KeyValueType::Bool) const noexcept { return compare(v1_.As(), v2_.As()); } @@ -578,12 +586,12 @@ class Comparator { } private: - const Variant &v1_; - const Variant &v2_; + const Variant& v1_; + const Variant& v2_; }; template -ComparationResult Variant::RelaxCompare(const Variant &other, const CollateOpts &collateOpts) const { +ComparationResult Variant::RelaxCompare(const Variant& other, const CollateOpts& collateOpts) const { thread_local char uuidStrBuf[Uuid::kStrFormLen]; thread_local const std::string_view uuidStrBufView{uuidStrBuf, Uuid::kStrFormLen}; thread_local const p_string uuidStrBufPString{&uuidStrBufView}; @@ -653,10 +661,10 @@ ComparationResult Variant::RelaxCompare(const Variant &other, const CollateOpts } } -template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; +template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; size_t Variant::Hash() const noexcept { if (isUuid()) { @@ -689,7 +697,7 @@ void Variant::EnsureUTF8() const { } } -Variant Variant::convert(KeyValueType type, const PayloadType *payloadType, const FieldsSet *fields) const & { +Variant Variant::convert(KeyValueType type, const PayloadType* payloadType, const FieldsSet* fields) const& { if (Type().IsSame(type)) { return *this; } @@ -698,7 +706,7 @@ Variant Variant::convert(KeyValueType type, const PayloadType *payloadType, cons return dst; } -Variant &Variant::convert(KeyValueType type, const PayloadType *payloadType, const FieldsSet *fields) & { +Variant& Variant::convert(KeyValueType type, const PayloadType* payloadType, const FieldsSet* fields) & { if (isUuid()) { type.EvaluateOneOf([&](KeyValueType::Uuid) noexcept {}, [&](KeyValueType::String) { *this = Variant{std::string{Uuid{*this}}}; }, [&](KeyValueType::Composite) { @@ -714,7 +722,9 @@ Variant &Variant::convert(KeyValueType type, const PayloadType *payloadType, con }); return *this; } - if (type.IsSame(variant_.type) || type.Is() || variant_.type.Is()) return *this; + if (type.IsSame(variant_.type) || type.Is() || variant_.type.Is()) { + return *this; + } type.EvaluateOneOf( [&](KeyValueType::Int) { *this = Variant(As()); }, [&](KeyValueType::Bool) { *this = Variant(As()); }, [&](KeyValueType::Int64) { *this = Variant(As()); }, [&](KeyValueType::Double) { *this = Variant(As()); }, @@ -744,7 +754,7 @@ Variant &Variant::convert(KeyValueType type, const PayloadType *payloadType, con return *this; } -std::optional Variant::tryConvert(KeyValueType type, const PayloadType *payloadType, const FieldsSet *fields) const & { +std::optional Variant::tryConvert(KeyValueType type, const PayloadType* payloadType, const FieldsSet* fields) const& { if (Type().IsSame(type)) { return *this; } else { @@ -757,7 +767,7 @@ std::optional Variant::tryConvert(KeyValueType type, const PayloadType } } -bool Variant::tryConvert(KeyValueType type, const PayloadType *payloadType, const FieldsSet *fields) & { +bool Variant::tryConvert(KeyValueType type, const PayloadType* payloadType, const FieldsSet* fields) & { using namespace std::string_view_literals; if (isUuid()) { return type.EvaluateOneOf([&](KeyValueType::Uuid) noexcept { return true; }, @@ -972,20 +982,22 @@ bool Variant::tryConvert(KeyValueType type, const PayloadType *payloadType, cons return res; } -void Variant::convertToComposite(const PayloadType &payloadType, const FieldsSet &fields) { +void Variant::convertToComposite(const PayloadType& payloadType, const FieldsSet& fields) { assertrx(!isUuid()); assertrx(variant_.type.Is() && variant_.hold == 1); key_string val = *cast(); - if (variant_.hold == 1) free(); + if (variant_.hold == 1) { + free(); + } // Alloc usual payloadvalue + extra memory for hold string - auto &pv = *new (cast()) PayloadValue(payloadType.TotalSize() + val->size()); + auto& pv = *new (cast()) PayloadValue(payloadType.TotalSize() + val->size()); variant_.hold = 1; variant_.type = KeyValueType::Composite{}; // Copy serializer buffer with strings to extra payloadvalue memory - char *data = reinterpret_cast(pv.Ptr() + payloadType.TotalSize()); + char* data = reinterpret_cast(pv.Ptr() + payloadType.TotalSize()); memcpy(data, val->data(), val->size()); Serializer ser(std::string_view(data, val->size())); @@ -1046,7 +1058,7 @@ Variant::operator std::string_view() const noexcept { assertKeyType(variant_.type); return (variant_.hold == 1) ? std::string_view(**cast()) : *cast(); } -Variant::operator const PayloadValue &() const noexcept { +Variant::operator const PayloadValue&() const noexcept { assertrx(!isUuid()); assertKeyType(variant_.type); assertrx(variant_.hold == 1); @@ -1054,7 +1066,7 @@ Variant::operator const PayloadValue &() const noexcept { } template -void Variant::Dump(T &os, CheckIsStringPrintable checkPrintableString) const { +void Variant::Dump(T& os, CheckIsStringPrintable checkPrintableString) const { if (isUuid()) { os << Uuid{*this}; } else { @@ -1074,23 +1086,25 @@ void Variant::Dump(T &os, CheckIsStringPrintable checkPrintableString) const { } } -template void Variant::Dump(WrSerializer &, CheckIsStringPrintable) const; -template void Variant::Dump(std::ostream &, CheckIsStringPrintable) const; -template void Variant::Dump(std::stringstream &, CheckIsStringPrintable) const; +template void Variant::Dump(WrSerializer&, CheckIsStringPrintable) const; +template void Variant::Dump(std::ostream&, CheckIsStringPrintable) const; +template void Variant::Dump(std::stringstream&, CheckIsStringPrintable) const; template -void VariantArray::Dump(T &os, CheckIsStringPrintable checkPrintableString) const { +void VariantArray::Dump(T& os, CheckIsStringPrintable checkPrintableString) const { os << '{'; - for (auto &arg : *this) { - if (&arg != &at(0)) os << ", "; + for (auto& arg : *this) { + if (&arg != &at(0)) { + os << ", "; + } arg.Dump(os, checkPrintableString); } os << '}'; } -template void VariantArray::Dump(WrSerializer &, CheckIsStringPrintable) const; -template void VariantArray::Dump(std::ostream &, CheckIsStringPrintable) const; -template void VariantArray::Dump(std::stringstream &, CheckIsStringPrintable) const; +template void VariantArray::Dump(WrSerializer&, CheckIsStringPrintable) const; +template void VariantArray::Dump(std::ostream&, CheckIsStringPrintable) const; +template void VariantArray::Dump(std::stringstream&, CheckIsStringPrintable) const; VariantArray::operator Point() const { if (size() != 2) { @@ -1100,28 +1114,29 @@ VariantArray::operator Point() const { } template -ComparationResult VariantArray::RelaxCompare(const VariantArray &other, const CollateOpts &collateOpts) const { +ComparationResult VariantArray::RelaxCompare(const VariantArray& other, const CollateOpts& collateOpts) const { auto lhsIt{cbegin()}, rhsIt{other.cbegin()}; - auto const lhsEnd{cend()}, rhsEnd{other.cend()}; + const auto lhsEnd{cend()}, rhsEnd{other.cend()}; for (; lhsIt != lhsEnd && rhsIt != rhsEnd; ++lhsIt, ++rhsIt) { const auto res = lhsIt->RelaxCompare(*rhsIt, collateOpts); - if (res != ComparationResult::Eq) return res; + if (res != ComparationResult::Eq) { + return res; + } } if (lhsIt == lhsEnd) { - if (rhsIt == rhsEnd) return ComparationResult::Eq; + if (rhsIt == rhsEnd) { + return ComparationResult::Eq; + } return ComparationResult::Lt; } else { return ComparationResult::Gt; } } -template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; +template ComparationResult VariantArray::RelaxCompare(const VariantArray&, + const CollateOpts&) const; +template ComparationResult VariantArray::RelaxCompare(const VariantArray&, const CollateOpts&) const; +template ComparationResult VariantArray::RelaxCompare(const VariantArray&, const CollateOpts&) const; +template ComparationResult VariantArray::RelaxCompare(const VariantArray&, const CollateOpts&) const; } // namespace reindexer diff --git a/cpp_src/core/keyvalue/variant.h b/cpp_src/core/keyvalue/variant.h index 5c29f3e06..22c586620 100644 --- a/cpp_src/core/keyvalue/variant.h +++ b/cpp_src/core/keyvalue/variant.h @@ -35,24 +35,24 @@ class Variant { explicit Variant(bool v) noexcept : variant_{0, 0, KeyValueType::Bool{}, v} {} explicit Variant(int64_t v) noexcept : variant_{0, 0, KeyValueType::Int64{}, v} {} explicit Variant(double v) noexcept : variant_{0, 0, KeyValueType::Double{}, v} {} - explicit Variant(const char *v) noexcept : Variant(p_string(v), Variant::no_hold_t{}) {} + explicit Variant(const char* v) noexcept : Variant(p_string(v), Variant::no_hold_t{}) {} Variant(p_string v, no_hold_t) noexcept : variant_{0, 0, KeyValueType::String{}} { *cast() = v; } Variant(p_string v, hold_t); explicit Variant(p_string v) noexcept : Variant(v, no_hold_t{}) {} - explicit Variant(const std::string &v) : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(make_key_string(v)); } - explicit Variant(std::string &&v) : variant_{0, 1, KeyValueType::String{}} { + explicit Variant(const std::string& v) : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(make_key_string(v)); } + explicit Variant(std::string&& v) : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(make_key_string(std::move(v))); } - explicit Variant(const key_string &v) noexcept : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(v); } - explicit Variant(key_string &&v) noexcept : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(std::move(v)); } - explicit Variant(const PayloadValue &v) noexcept : variant_{0, 1, KeyValueType::Composite{}} { new (cast()) PayloadValue(v); } - explicit Variant(PayloadValue &&v) noexcept : variant_{0, 1, KeyValueType::Composite{}} { + explicit Variant(const key_string& v) noexcept : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(v); } + explicit Variant(key_string&& v) noexcept : variant_{0, 1, KeyValueType::String{}} { new (cast()) key_string(std::move(v)); } + explicit Variant(const PayloadValue& v) noexcept : variant_{0, 1, KeyValueType::Composite{}} { new (cast()) PayloadValue(v); } + explicit Variant(PayloadValue&& v) noexcept : variant_{0, 1, KeyValueType::Composite{}} { new (cast()) PayloadValue(std::move(v)); } - explicit Variant(const VariantArray &values); + explicit Variant(const VariantArray& values); explicit Variant(Point); explicit Variant(Uuid) noexcept; - Variant(const Variant &other) : uuid_{other.uuid_} { + Variant(const Variant& other) : uuid_{other.uuid_} { if (!isUuid()) { uuid_.~UUID(); new (&variant_) Var{other.variant_}; @@ -61,7 +61,7 @@ class Variant { } } } - Variant(Variant &&other) noexcept : uuid_{other.uuid_} { + Variant(Variant&& other) noexcept : uuid_{other.uuid_} { if (!isUuid()) { uuid_.~UUID(); new (&variant_) Var{other.variant_}; @@ -69,13 +69,17 @@ class Variant { } } ~Variant() { - if (!isUuid() && variant_.hold != 0) free(); + if (!isUuid() && variant_.hold != 0) { + free(); + } } template - Variant(const std::tuple &); + Variant(const std::tuple&); - Variant &operator=(Variant &&other) & noexcept { - if (this == &other) return *this; + Variant& operator=(Variant&& other) & noexcept { + if (this == &other) { + return *this; + } if (isUuid()) { if (other.isUuid()) { uuid_ = other.uuid_; @@ -85,7 +89,9 @@ class Variant { other.variant_.hold = 0; } } else { - if (variant_.hold != 0) free(); + if (variant_.hold != 0) { + free(); + } if (other.isUuid()) { variant_.~Var(); new (&uuid_) UUID{other.uuid_}; @@ -96,7 +102,7 @@ class Variant { } return *this; } - Variant &operator=(const Variant &other) & { + Variant& operator=(const Variant& other) & { if (this != &other) { Variant tmp{other}; operator=(std::move(tmp)); @@ -111,7 +117,7 @@ class Variant { explicit operator p_string() const noexcept; explicit operator std::string_view() const noexcept; - explicit operator const PayloadValue &() const noexcept; + explicit operator const PayloadValue&() const noexcept; explicit operator key_string() const; explicit operator Point() const; @@ -119,24 +125,24 @@ class Variant { [[nodiscard]] T As() const; template - [[nodiscard]] T As(const PayloadType &, const FieldsSet &) const; + [[nodiscard]] T As(const PayloadType&, const FieldsSet&) const; - bool operator==(const Variant &other) const { + bool operator==(const Variant& other) const { return Type().IsSame(other.Type()) && Compare(other) == ComparationResult::Eq; } - bool operator!=(const Variant &other) const { return !operator==(other); } - bool operator<(const Variant &other) const { return Compare(other) == ComparationResult::Lt; } - bool operator>(const Variant &other) const { return Compare(other) == ComparationResult::Gt; } - bool operator>=(const Variant &other) const { return Compare(other) & ComparationResult::Ge; } - bool operator<=(const Variant &other) const { return Compare(other) & ComparationResult::Le; } + bool operator!=(const Variant& other) const { return !operator==(other); } + bool operator<(const Variant& other) const { return Compare(other) == ComparationResult::Lt; } + bool operator>(const Variant& other) const { return Compare(other) == ComparationResult::Gt; } + bool operator>=(const Variant& other) const { return Compare(other) & ComparationResult::Ge; } + bool operator<=(const Variant& other) const { return Compare(other) & ComparationResult::Le; } template - ComparationResult Compare(const Variant &other, const CollateOpts &collateOpts = CollateOpts()) const; + ComparationResult Compare(const Variant& other, const CollateOpts& collateOpts = CollateOpts()) const; template - ComparationResult RelaxCompare(const Variant &other, const CollateOpts &collateOpts = CollateOpts()) const; + ComparationResult RelaxCompare(const Variant& other, const CollateOpts& collateOpts = CollateOpts()) const; size_t Hash() const noexcept; void EnsureUTF8() const; - Variant &EnsureHold() &; + Variant& EnsureHold() &; Variant EnsureHold() && { return std::move(EnsureHold()); } KeyValueType Type() const noexcept { @@ -146,57 +152,57 @@ class Variant { return variant_.type; } - Variant &convert(KeyValueType type, const PayloadType * = nullptr, const FieldsSet * = nullptr) &; - [[nodiscard]] Variant convert(KeyValueType type, const PayloadType *pt = nullptr, const FieldsSet *fs = nullptr) && { + Variant& convert(KeyValueType type, const PayloadType* = nullptr, const FieldsSet* = nullptr) &; + [[nodiscard]] Variant convert(KeyValueType type, const PayloadType* pt = nullptr, const FieldsSet* fs = nullptr) && { return std::move(convert(type, pt, fs)); } - [[nodiscard]] Variant convert(KeyValueType type, const PayloadType * = nullptr, const FieldsSet * = nullptr) const &; - [[nodiscard]] std::optional tryConvert(KeyValueType type, const PayloadType * = nullptr, const FieldsSet * = nullptr) const &; - [[nodiscard]] bool tryConvert(KeyValueType type, const PayloadType * = nullptr, const FieldsSet * = nullptr) &; - auto tryConvert(KeyValueType type, const PayloadType * = nullptr, const FieldsSet * = nullptr) const && = delete; + [[nodiscard]] Variant convert(KeyValueType type, const PayloadType* = nullptr, const FieldsSet* = nullptr) const&; + [[nodiscard]] std::optional tryConvert(KeyValueType type, const PayloadType* = nullptr, const FieldsSet* = nullptr) const&; + [[nodiscard]] bool tryConvert(KeyValueType type, const PayloadType* = nullptr, const FieldsSet* = nullptr) &; + auto tryConvert(KeyValueType type, const PayloadType* = nullptr, const FieldsSet* = nullptr) const&& = delete; VariantArray getCompositeValues() const; bool IsNullValue() const noexcept { return Type().Is(); } template - void Dump(T &os, CheckIsStringPrintable checkPrintableString = CheckIsStringPrintable::Yes) const; + void Dump(T& os, CheckIsStringPrintable checkPrintableString = CheckIsStringPrintable::Yes) const; class Less { public: - Less(const CollateOpts &collate) noexcept : collate_{&collate} {} - [[nodiscard]] bool operator()(const Variant &lhs, const Variant &rhs) const { + Less(const CollateOpts& collate) noexcept : collate_{&collate} {} + [[nodiscard]] bool operator()(const Variant& lhs, const Variant& rhs) const { return lhs.Compare(rhs, *collate_) == ComparationResult::Lt; } private: - const CollateOpts *collate_; + const CollateOpts* collate_; }; class EqualTo { public: - EqualTo(const CollateOpts &collate) noexcept : collate_{&collate} {} - [[nodiscard]] bool operator()(const Variant &lhs, const Variant &rhs) const { + EqualTo(const CollateOpts& collate) noexcept : collate_{&collate} {} + [[nodiscard]] bool operator()(const Variant& lhs, const Variant& rhs) const { return lhs.Compare(rhs, *collate_) == ComparationResult::Eq; } private: - const CollateOpts *collate_; + const CollateOpts* collate_; }; private: bool isUuid() const noexcept { return uuid_.isUuid != 0; } - void convertToComposite(const PayloadType &, const FieldsSet &); + void convertToComposite(const PayloadType&, const FieldsSet&); void free() noexcept; - void copy(const Variant &other); + void copy(const Variant& other); template - const T *cast() const noexcept { + const T* cast() const noexcept { assertrx(!isUuid()); - return reinterpret_cast(&variant_.value_uint64); + return reinterpret_cast(&variant_.value_uint64); } template - T *cast() noexcept { + T* cast() noexcept { assertrx(!isUuid()); - return reinterpret_cast(&variant_.value_uint64); + return reinterpret_cast(&variant_.value_uint64); } template ComparationResult relaxCompareWithString(std::string_view) const noexcept(notComparable == NotComparable::Return); @@ -240,12 +246,12 @@ class Variant { static_assert(sizeof(Variant) == 16); -extern template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -extern template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -extern template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -extern template ComparationResult Variant::RelaxCompare(const Variant &, const CollateOpts &) const; -extern template ComparationResult Variant::Compare(const Variant &, const CollateOpts &) const; -extern template ComparationResult Variant::Compare(const Variant &, const CollateOpts &) const; +extern template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +extern template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +extern template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +extern template ComparationResult Variant::RelaxCompare(const Variant&, const CollateOpts&) const; +extern template ComparationResult Variant::Compare(const Variant&, const CollateOpts&) const; +extern template ComparationResult Variant::Compare(const Variant&, const CollateOpts&) const; template <> int Variant::As() const; @@ -268,11 +274,11 @@ class VariantArray : public h_vector { emplace_back(p.Y()); } explicit operator Point() const; - VariantArray &MarkArray(bool v = true) & noexcept { + VariantArray& MarkArray(bool v = true) & noexcept { isArrayValue = v; return *this; } - VariantArray &&MarkArray(bool v = true) && noexcept { + VariantArray&& MarkArray(bool v = true) && noexcept { isArrayValue = v; return std::move(*this); } @@ -287,7 +293,9 @@ class VariantArray : public h_vector { } size_t Hash() const noexcept { size_t ret = this->size(); - for (size_t i = 0; i < this->size(); ++i) ret = (ret * 127) ^ this->at(i).Hash(); + for (size_t i = 0; i < this->size(); ++i) { + ret = (ret * 127) ^ this->at(i).Hash(); + } return ret; } bool IsArrayValue() const noexcept { return isArrayValue || (!isObjectValue && size() > 1); } @@ -295,21 +303,23 @@ class VariantArray : public h_vector { bool IsNullValue() const noexcept { return size() == 1 && front().IsNullValue(); } KeyValueType ArrayType() const noexcept { return empty() ? KeyValueType::Null{} : front().Type(); } template - void Dump(T &os, CheckIsStringPrintable checkPrintableString = CheckIsStringPrintable::Yes) const; + void Dump(T& os, CheckIsStringPrintable checkPrintableString = CheckIsStringPrintable::Yes) const; template - ComparationResult RelaxCompare(const VariantArray &other, const CollateOpts & = CollateOpts{}) const; + ComparationResult RelaxCompare(const VariantArray& other, const CollateOpts& = CollateOpts{}) const; void EnsureHold() { - for (Variant &v : *this) v.EnsureHold(); + for (Variant& v : *this) { + v.EnsureHold(); + } } template - static VariantArray Create(Ts &&...vs) { + static VariantArray Create(Ts&&... vs) { return VariantArray{Variant{std::forward(vs)}...}; } template static VariantArray Create(std::initializer_list vs) { VariantArray res; res.reserve(vs.size()); - for (auto &v : vs) { + for (auto& v : vs) { res.emplace_back(std::move(v)); } return res; @@ -329,19 +339,19 @@ class VariantArray : public h_vector { // Current implementation requires 3 allocations for each point inline Variant::Variant(Point p) : Variant{VariantArray{p}} {} -extern template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -extern template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -extern template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; -extern template ComparationResult VariantArray::RelaxCompare(const VariantArray &, - const CollateOpts &) const; +extern template ComparationResult VariantArray::RelaxCompare(const VariantArray&, + const CollateOpts&) const; +extern template ComparationResult VariantArray::RelaxCompare(const VariantArray&, + const CollateOpts&) const; +extern template ComparationResult VariantArray::RelaxCompare(const VariantArray&, + const CollateOpts&) const; +extern template ComparationResult VariantArray::RelaxCompare(const VariantArray&, + const CollateOpts&) const; } // namespace reindexer namespace std { template <> struct hash { - size_t operator()(const reindexer::Variant &kv) const { return kv.Hash(); } + size_t operator()(const reindexer::Variant& kv) const { return kv.Hash(); } }; } // namespace std diff --git a/cpp_src/core/lrucache.cc b/cpp_src/core/lrucache.cc index 5091c07e6..9170122f7 100644 --- a/cpp_src/core/lrucache.cc +++ b/cpp_src/core/lrucache.cc @@ -10,8 +10,10 @@ namespace reindexer { constexpr uint32_t kMaxHitCountToCache = 1024; template -typename LRUCache::Iterator LRUCache::Get(const K &key) { - if rx_unlikely (cacheSizeLimit_ == 0) return Iterator(); +typename LRUCache::Iterator LRUCache::Get(const K& key) { + if rx_unlikely (cacheSizeLimit_ == 0) { + return Iterator(); + } std::lock_guard lk(lock_); @@ -31,25 +33,24 @@ typename LRUCache::Iterator LRUCache::Get( return Iterator(); } ++getCount_; - - // logPrintf(LogInfo, "Cache::Get (cond=%d,sortId=%d,keys=%d), total in cache items=%d,size=%d", key.cond, key.sort, - // (int)key.keys.size(), items_.size(), totalCacheSize_); return Iterator(true, it->second.val); } template -void LRUCache::Put(const K &key, V &&v) { - if rx_unlikely (cacheSizeLimit_ == 0) return; +void LRUCache::Put(const K& key, V&& v) { + if rx_unlikely (cacheSizeLimit_ == 0) { + return; + } std::lock_guard lk(lock_); auto it = items_.find(key); - if (it == items_.end()) return; + if (it == items_.end()) { + return; + } totalCacheSize_ += v.Size() - it->second.val.Size(); it->second.val = std::move(v); - // logPrintf(LogInfo, "IdSetCache::Put () add %d,left %d,fwdCnt=%d,sz=%d", endIt - begIt, left, it->second.fwdCount, - // it->second.ids->size()); ++putCount_; eraseLRU(); diff --git a/cpp_src/core/lrucache.h b/cpp_src/core/lrucache.h index 4cac5b979..3acfb7dca 100644 --- a/cpp_src/core/lrucache.h +++ b/cpp_src/core/lrucache.h @@ -17,11 +17,11 @@ class LRUCache { using Key = K; LRUCache(size_t sizeLimit, uint32_t hitCount) noexcept : totalCacheSize_(0), cacheSizeLimit_(sizeLimit), hitCountToCache_(hitCount) {} struct Iterator { - Iterator(bool k = false, const V &v = V()) : valid(k), val(v) {} - Iterator(const Iterator &other) = delete; - Iterator &operator=(const Iterator &other) = delete; - Iterator(Iterator &&other) noexcept : valid(other.valid), val(std::move(other.val)) { other.valid = false; } - Iterator &operator=(Iterator &&other) noexcept { + Iterator(bool k = false, const V& v = V()) : valid(k), val(v) {} + Iterator(const Iterator& other) = delete; + Iterator& operator=(const Iterator& other) = delete; + Iterator(Iterator&& other) noexcept : valid(other.valid), val(std::move(other.val)) { other.valid = false; } + Iterator& operator=(Iterator&& other) noexcept { if (this != &other) { valid = other.valid; val = std::move(other.val); @@ -33,9 +33,9 @@ class LRUCache { V val; }; // Get cached val. Create new entry in cache if unexists - Iterator Get(const K &k); + Iterator Get(const K& k); // Put cached val - void Put(const K &k, V &&v); + void Put(const K& k, V&& v); LRUCacheMemStat GetMemStat(); @@ -45,7 +45,7 @@ class LRUCache { } template - void Dump(T &os, std::string_view step, std::string_view offset) const { + void Dump(T& os, std::string_view step, std::string_view offset) const { std::string newOffset{offset}; newOffset += step; os << "{\n" << newOffset << "totalCacheSize: "; @@ -59,7 +59,9 @@ class LRUCache { << newOffset << "items: ["; if (!items_.empty()) { for (auto b = items_.begin(), it = b, e = items_.end(); it != e; ++it) { - if (it != b) os << ','; + if (it != b) { + os << ','; + } os << '\n' << newOffset << '{' << it->first << ": "; it->second.Dump(os); os << '}'; @@ -68,14 +70,16 @@ class LRUCache { } os << "],\n" << newOffset << "lruList: ["; for (auto b = lru_.begin(), it = b, e = lru_.end(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << **it; } os << "]\n" << offset << '}'; } template - void Clear(const F &cond) { + void Clear(const F& cond) { std::lock_guard lock(lock_); for (auto it = lru_.begin(); it != lru_.end();) { if (!cond(**it)) { @@ -97,13 +101,13 @@ class LRUCache { } protected: - typedef std::list LRUList; + typedef std::list LRUList; struct Entry { V val; typename LRUList::iterator lruPos; int hitCount = 0; template - void Dump(T &os) const { + void Dump(T& os) const { os << "{val: " << val << ", hitCount: " << hitCount << '}'; } }; diff --git a/cpp_src/core/lsn.h b/cpp_src/core/lsn.h index 174540da4..75e1fbdb7 100644 --- a/cpp_src/core/lsn.h +++ b/cpp_src/core/lsn.h @@ -21,19 +21,19 @@ struct lsn_t { static constexpr int64_t kDefaultCounter = kMaxCounter - 1; public: - void GetJSON(JsonBuilder &builder) const; + void GetJSON(JsonBuilder& builder) const; - void FromJSON(const gason::JsonNode &root) { + void FromJSON(const gason::JsonNode& root) { const int server = root["server_id"].As(0); const int64_t counter = root["counter"].As(kDefaultCounter); payload_ = int64_t(lsn_t(counter, server)); } lsn_t() noexcept = default; - lsn_t(const lsn_t &) noexcept = default; - lsn_t(lsn_t &&) noexcept = default; - lsn_t &operator=(const lsn_t &) noexcept = default; - lsn_t &operator=(lsn_t &&) noexcept = default; + lsn_t(const lsn_t&) noexcept = default; + lsn_t(lsn_t&&) noexcept = default; + lsn_t& operator=(const lsn_t&) noexcept = default; + lsn_t& operator=(lsn_t&&) noexcept = default; explicit lsn_t(int64_t v) : lsn_t(v % kMaxCounter, v / kMaxCounter) {} lsn_t(int64_t counter, int16_t server) { validateCounter(counter); @@ -60,11 +60,14 @@ struct lsn_t { bool isEmpty() const noexcept { return Counter() == kDefaultCounter; } int compare(lsn_t o) const { - if (Server() != o.Server()) throw Error(errLogic, "Compare lsn from different server"); - if (Counter() < o.Counter()) + if (Server() != o.Server()) { + throw Error(errLogic, "Compare lsn from different server"); + } + if (Counter() < o.Counter()) { return -1; - else if (Counter() > o.Counter()) + } else if (Counter() > o.Counter()) { return 1; + } return 0; } @@ -89,7 +92,7 @@ struct lsn_t { } } - [[noreturn]] static void throwValidation(ErrorCode, const char *, int64_t); + [[noreturn]] static void throwValidation(ErrorCode, const char*, int64_t); }; struct LSNPair { @@ -99,8 +102,4 @@ struct LSNPair { lsn_t originLSN_; }; -inline static std::ostream &operator<<(std::ostream &o, const reindexer::lsn_t &sv) { - o << sv.Server() << ":" << sv.Counter(); - return o; -} } // namespace reindexer diff --git a/cpp_src/core/namespace/asyncstorage.cc b/cpp_src/core/namespace/asyncstorage.cc index 73e3d4759..14058e446 100644 --- a/cpp_src/core/namespace/asyncstorage.cc +++ b/cpp_src/core/namespace/asyncstorage.cc @@ -125,7 +125,9 @@ void AsyncStorage::InheritUpdatesFrom(AsyncStorage& src, AsyncStorage::FullLockT totalUpdatesCount_.fetch_add(src.curUpdatesChunck_.updatesCount, std::memory_order_release); src.totalUpdatesCount_.fetch_sub(src.curUpdatesChunck_.updatesCount, std::memory_order_release); finishedUpdateChuncks_.push_front(std::move(src.curUpdatesChunck_)); - if (lastBatchWithSyncUpdates_ >= 0) ++lastBatchWithSyncUpdates_; + if (lastBatchWithSyncUpdates_ >= 0) { + ++lastBatchWithSyncUpdates_; + } } while (src.finishedUpdateChuncks_.size()) { auto& upd = src.finishedUpdateChuncks_.back(); @@ -133,7 +135,9 @@ void AsyncStorage::InheritUpdatesFrom(AsyncStorage& src, AsyncStorage::FullLockT src.totalUpdatesCount_.fetch_sub(upd.updatesCount, std::memory_order_release); finishedUpdateChuncks_.push_front(std::move(upd)); src.finishedUpdateChuncks_.pop_back(); - if (lastBatchWithSyncUpdates_ >= 0) ++lastBatchWithSyncUpdates_; + if (lastBatchWithSyncUpdates_ >= 0) { + ++lastBatchWithSyncUpdates_; + } } src.storage_.reset(); // Do not update lockfree status here to avoid status flickering on ns copying diff --git a/cpp_src/core/namespace/asyncstorage.h b/cpp_src/core/namespace/asyncstorage.h index 541e969f3..a9a08e36a 100644 --- a/cpp_src/core/namespace/asyncstorage.h +++ b/cpp_src/core/namespace/asyncstorage.h @@ -164,12 +164,10 @@ class AsyncStorage { void flush(const StorageFlushOpts& opts); void beginNewUpdatesChunk(); void write(bool fromSyncCall, std::string_view key, std::string_view value) { - asyncOp( - fromSyncCall, [this](std::string_view k, std::string_view v) { curUpdatesChunck_->Put(k, v); }, key, value); + asyncOp(fromSyncCall, [this](std::string_view k, std::string_view v) { curUpdatesChunck_->Put(k, v); }, key, value); } void remove(bool fromSyncCall, std::string_view key) { - asyncOp( - fromSyncCall, [this](std::string_view k) { curUpdatesChunck_->Remove(k); }, key); + asyncOp(fromSyncCall, [this](std::string_view k) { curUpdatesChunck_->Remove(k); }, key); } template void asyncOp(bool fromSyncCall, StorageCall&& call, const Args&... args) { diff --git a/cpp_src/core/namespace/bgnamespacedeleter.h b/cpp_src/core/namespace/bgnamespacedeleter.h index 77e0cfd3b..8f1ab5bcd 100644 --- a/cpp_src/core/namespace/bgnamespacedeleter.h +++ b/cpp_src/core/namespace/bgnamespacedeleter.h @@ -29,4 +29,4 @@ class BackgroundNamespaceDeleter { std::list namespaces_; }; -} +} // namespace reindexer diff --git a/cpp_src/core/namespace/itemsloader.cc b/cpp_src/core/namespace/itemsloader.cc index ec97275b9..1a7f59b44 100644 --- a/cpp_src/core/namespace/itemsloader.cc +++ b/cpp_src/core/namespace/itemsloader.cc @@ -64,7 +64,7 @@ void ItemsLoader::reading() { } // Read LSN - int64_t lsn = *reinterpret_cast(dataSlice.data()); + int64_t lsn = *reinterpret_cast(dataSlice.data()); if (lsn < 0) { lastErr = Error(errParseBin, "Ivalid LSN value: %d", lsn); logPrintf(LogTrace, "Error load item to '%s' from storage: '%s'", ns_.name_, lastErr.what()); @@ -89,10 +89,10 @@ void ItemsLoader::reading() { if (terminated_) { return; } - auto &item = items_.PlaceItem(); + auto& item = items_.PlaceItem(); lck.unlock(); - auto &sliceStorageP = slices_[sliceId]; + auto& sliceStorageP = slices_[sliceId]; if (sliceStorageP.len < dataSlice.size()) { sliceStorageP.len = dataSlice.size() * 1.1; sliceStorageP.data.reset(new char[sliceStorageP.len]); @@ -103,7 +103,7 @@ void ItemsLoader::reading() { item.impl.Unsafe(true); try { item.impl.FromCJSON(dataSlice); - } catch (const Error &err) { + } catch (const Error& err) { logPrintf(LogTrace, "Error load item to '%s' from storage: '%s'", ns_.name_, err.what()); ++errCount; lastErr = err; @@ -179,7 +179,7 @@ void ItemsLoader::insertion() { for (unsigned i = 0; i < items.size(); ++i) { const auto id = i + startId; - auto &plData = ns_.items_[id]; + auto& plData = ns_.items_[id]; Payload pl(ns_.payloadType_, plData); Payload plNew(items[i].impl.GetPayload()); // Index [0] must be inserted after all other simple indexes @@ -190,7 +190,7 @@ void ItemsLoader::insertion() { indexInserters.BuildCompositeIndexesAsync(); } for (unsigned i = 0; i < items.size(); ++i) { - auto &plData = ns_.items_[i + startId]; + auto& plData = ns_.items_[i + startId]; Payload pl(ns_.payloadType_, plData); plData.SetLSN(items[i].impl.Value().GetLSN()); ns_.repl_.dataHash ^= pl.GetHash(); @@ -206,30 +206,33 @@ void ItemsLoader::insertion() { } void ItemsLoader::clearIndexCache() { - for (auto &idx : ns_.indexes_) { + for (auto& idx : ns_.indexes_) { idx->DestroyCache(); idx->Commit(); } } template -void ItemsLoader::doInsertField(NamespaceImpl::IndexesStorage &indexes, unsigned field, IdType id, Payload &pl, Payload &plNew, - VariantArray &krefs, VariantArray &skrefs, MutexT &mtx) { - Index &index = *indexes[field]; +void ItemsLoader::doInsertField(NamespaceImpl::IndexesStorage& indexes, unsigned field, IdType id, Payload& pl, Payload& plNew, + VariantArray& krefs, VariantArray& skrefs, MutexT& mtx) { + Index& index = *indexes[field]; const bool isIndexSparse = index.Opts().IsSparse(); if (isIndexSparse) { assertrx(index.Fields().getTagsPathsLength() > 0); try { plNew.GetByJsonPath(index.Fields().getTagsPath(0), skrefs, index.KeyType()); - } catch (const Error &) { + } catch (const Error&) { skrefs.resize(0); } } else { plNew.Get(field, skrefs); } - if (index.Opts().GetCollateMode() == CollateUTF8) - for (auto &key : skrefs) key.EnsureUTF8(); + if (index.Opts().GetCollateMode() == CollateUTF8) { + for (auto& key : skrefs) { + key.EnsureUTF8(); + } + } // Put value to index krefs.resize(0); @@ -252,7 +255,7 @@ void ItemsLoader::doInsertField(NamespaceImpl::IndexesStorage &indexes, unsigned } } -IndexInserters::IndexInserters(NamespaceImpl::IndexesStorage &indexes, PayloadType pt) : indexes_(indexes), pt_(std::move(pt)) { +IndexInserters::IndexInserters(NamespaceImpl::IndexesStorage& indexes, PayloadType pt) : indexes_(indexes), pt_(std::move(pt)) { for (int i = 1; i < indexes_.firstCompositePos(); ++i) { if (indexes_[i]->Opts().IsArray()) { hasArrayIndexes_ = true; @@ -277,7 +280,7 @@ void IndexInserters::Stop() { shared_.terminate = true; cvReady_.notify_all(); } - for (auto &th : threads_) { + for (auto& th : threads_) { th.join(); } threads_.clear(); @@ -332,7 +335,7 @@ void IndexInserters::insertionLoop(unsigned threadId) noexcept { if (shared_.composite) { for (unsigned i = 0; i < shared_.newItems.size(); ++i) { const auto id = startId + i; - const auto &plData = shared_.nsItems[i]; + const auto& plData = shared_.nsItems[i]; for (unsigned field = firstCompositeIndex + threadId - kTIDOffset; field < totalIndexes; field += threadsCnt) { bool needClearCache{false}; indexes_[field]->Upsert(Variant{plData}, id, needClearCache); @@ -342,8 +345,8 @@ void IndexInserters::insertionLoop(unsigned threadId) noexcept { if (hasArrayIndexes_) { for (unsigned i = 0; i < shared_.newItems.size(); ++i) { const auto id = startId + i; - auto &item = shared_.newItems[i].impl; - auto &plData = shared_.nsItems[i]; + auto& item = shared_.newItems[i].impl; + auto& plData = shared_.nsItems[i]; Payload pl(pt_, plData); Payload plNew = item.GetPayload(); for (unsigned field = threadId - kTIDOffset + 1; field < firstCompositeIndex; field += threadsCnt) { @@ -355,8 +358,8 @@ void IndexInserters::insertionLoop(unsigned threadId) noexcept { dummy_mutex dummyMtx; for (unsigned i = 0; i < shared_.newItems.size(); ++i) { const auto id = startId + i; - auto &item = shared_.newItems[i].impl; - auto &plData = shared_.nsItems[i]; + auto& item = shared_.newItems[i].impl; + auto& plData = shared_.nsItems[i]; Payload pl(pt_, plData); Payload plNew = item.GetPayload(); for (unsigned field = threadId - kTIDOffset + 1; field < firstCompositeIndex; field += threadsCnt) { @@ -366,7 +369,7 @@ void IndexInserters::insertionLoop(unsigned threadId) noexcept { } } onItemsHandled(); - } catch (Error &e) { + } catch (Error& e) { onException(e); } catch (...) { onException(Error(errLogic, "Unknown exception in insertion loop")); diff --git a/cpp_src/core/namespace/namespace.h b/cpp_src/core/namespace/namespace.h index c7e4eeb90..e1b0d4ee1 100644 --- a/cpp_src/core/namespace/namespace.h +++ b/cpp_src/core/namespace/namespace.h @@ -10,7 +10,7 @@ namespace reindexer { class Namespace { template - auto nsFuncWrapper(Args &&...args) const { + auto nsFuncWrapper(Args&&... args) const { while (true) { try { auto ns = atomicLoadMainNs(); @@ -18,7 +18,7 @@ class Namespace { throw Error(errLogic, "Ns is nullptr"); } return (*ns.*fn)(std::forward(args)...); - } catch (const Error &e) { + } catch (const Error& e) { if (e.code() != errNamespaceInvalidated) { throw; } else { @@ -28,18 +28,18 @@ class Namespace { } } - template - void nsFuncWrapper(Item &item, QueryResults &qr, NsContext ctx) const { + template + void nsFuncWrapper(Item& item, QueryResults& qr, NsContext ctx) const { nsFuncWrapper(item, qr, ctx); } - template - void nsFuncWrapper(const Query &query, QueryResults &qr, NsContext ctx) const { + template + void nsFuncWrapper(const Query& query, QueryResults& qr, NsContext ctx) const { nsFuncWrapper(query, qr, ctx); } template - void nsFuncWrapper(T &v, QueryResults &qr, NsContext ctx) const { + void nsFuncWrapper(T& v, QueryResults& qr, NsContext ctx) const { while (true) { NamespaceImpl::Ptr ns; bool added = false; @@ -73,11 +73,13 @@ class Namespace { static_assert(std::is_same_v || std::is_same_v); } return; - } catch (const Error &e) { + } catch (const Error& e) { if (e.code() != errNamespaceInvalidated) { throw; } else { - if (added) qr.RemoveNamespace(ns.get()); + if (added) { + qr.RemoveNamespace(ns.get()); + } std::this_thread::yield(); } } @@ -87,65 +89,65 @@ class Namespace { public: using Ptr = shared_ptr; - Namespace(const std::string &name, UpdatesObservers &observers, BackgroundNamespaceDeleter &bgDeleter) + Namespace(const std::string& name, UpdatesObservers& observers, BackgroundNamespaceDeleter& bgDeleter) : ns_(make_intrusive(name, observers)), bgDeleter_(bgDeleter) {} - void CommitTransaction(Transaction &tx, QueryResults &result, const RdxContext &ctx); - std::string GetName(const RdxContext &ctx) const { return nsFuncWrapper<&NamespaceImpl::GetName>(ctx); } - bool IsSystem(const RdxContext &ctx) const { return nsFuncWrapper<&NamespaceImpl::IsSystem>(ctx); } - bool IsTemporary(const RdxContext &ctx) const { return nsFuncWrapper<&NamespaceImpl::IsTemporary>(ctx); } - void EnableStorage(const std::string &path, StorageOpts opts, StorageType storageType, const RdxContext &ctx) { + void CommitTransaction(Transaction& tx, QueryResults& result, const RdxContext& ctx); + std::string GetName(const RdxContext& ctx) const { return nsFuncWrapper<&NamespaceImpl::GetName>(ctx); } + bool IsSystem(const RdxContext& ctx) const { return nsFuncWrapper<&NamespaceImpl::IsSystem>(ctx); } + bool IsTemporary(const RdxContext& ctx) const { return nsFuncWrapper<&NamespaceImpl::IsTemporary>(ctx); } + void EnableStorage(const std::string& path, StorageOpts opts, StorageType storageType, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::EnableStorage>(path, opts, storageType, ctx); } - void LoadFromStorage(unsigned threadsCount, const RdxContext &ctx) { + void LoadFromStorage(unsigned threadsCount, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::LoadFromStorage>(threadsCount, ctx); } - void DeleteStorage(const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::DeleteStorage>(ctx); } + void DeleteStorage(const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::DeleteStorage>(ctx); } uint32_t GetItemsCount() { return nsFuncWrapper<&NamespaceImpl::GetItemsCount>(); } - void AddIndex(const IndexDef &indexDef, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::AddIndex>(indexDef, ctx); } - void UpdateIndex(const IndexDef &indexDef, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::UpdateIndex>(indexDef, ctx); } - void DropIndex(const IndexDef &indexDef, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::DropIndex>(indexDef, ctx); } - void SetSchema(std::string_view schema, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::SetSchema>(schema, ctx); } - std::string GetSchema(int format, const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetSchema>(format, ctx); } - std::shared_ptr GetSchemaPtr(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetSchemaPtr>(ctx); } - void Insert(Item &item, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Insert>(item, ctx); } - void Insert(Item &item, QueryResults &qr, const RdxContext &ctx) { + void AddIndex(const IndexDef& indexDef, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::AddIndex>(indexDef, ctx); } + void UpdateIndex(const IndexDef& indexDef, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::UpdateIndex>(indexDef, ctx); } + void DropIndex(const IndexDef& indexDef, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::DropIndex>(indexDef, ctx); } + void SetSchema(std::string_view schema, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::SetSchema>(schema, ctx); } + std::string GetSchema(int format, const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetSchema>(format, ctx); } + std::shared_ptr GetSchemaPtr(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetSchemaPtr>(ctx); } + void Insert(Item& item, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Insert>(item, ctx); } + void Insert(Item& item, QueryResults& qr, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::modifyItem, ItemModifyMode::ModeInsert>(item, qr, ctx); } - void Update(Item &item, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Update>(item, ctx); } - void Update(Item &item, QueryResults &qr, const RdxContext &ctx) { + void Update(Item& item, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Update>(item, ctx); } + void Update(Item& item, QueryResults& qr, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::modifyItem, ItemModifyMode::ModeUpdate>(item, qr, ctx); } - void Update(const Query &query, QueryResults &result, const RdxContext &ctx) { + void Update(const Query& query, QueryResults& result, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::doUpdate, QueryType::QueryUpdate>(query, result, ctx); } - void Upsert(Item &item, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Upsert>(item, ctx); } - void Upsert(Item &item, QueryResults &qr, const RdxContext &ctx) { + void Upsert(Item& item, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Upsert>(item, ctx); } + void Upsert(Item& item, QueryResults& qr, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::modifyItem, ItemModifyMode::ModeUpsert>(item, qr, ctx); } - void Delete(Item &item, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Delete>(item, ctx); } - void Delete(Item &item, QueryResults &qr, const RdxContext &ctx) { + void Delete(Item& item, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Delete>(item, ctx); } + void Delete(Item& item, QueryResults& qr, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::modifyItem, ItemModifyMode::ModeDelete>(item, qr, ctx); } - void Delete(const Query &query, QueryResults &result, const RdxContext &ctx) { + void Delete(const Query& query, QueryResults& result, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::doDelete, QueryType::QueryDelete>(query, result, ctx); } - void Truncate(const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Truncate>(ctx); } + void Truncate(const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Truncate>(ctx); } template - void Select(QueryResults &result, SelectCtxWithJoinPreSelect ¶ms, const RdxContext &ctx) { + void Select(QueryResults& result, SelectCtxWithJoinPreSelect& params, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Select>(result, params, ctx); } - NamespaceDef GetDefinition(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetDefinition>(ctx); } - NamespaceMemStat GetMemStat(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetMemStat>(ctx); } - NamespacePerfStat GetPerfStat(const RdxContext &ctx); - void ResetPerfStat(const RdxContext &ctx) { + NamespaceDef GetDefinition(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetDefinition>(ctx); } + NamespaceMemStat GetMemStat(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetMemStat>(ctx); } + NamespacePerfStat GetPerfStat(const RdxContext& ctx); + void ResetPerfStat(const RdxContext& ctx) { txStatsCounter_.Reset(); commitStatsCounter_.Reset(); copyStatsCounter_.Reset(); nsFuncWrapper<&NamespaceImpl::ResetPerfStat>(ctx); } - std::vector EnumMeta(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::EnumMeta>(ctx); } - void BackgroundRoutine(RdxActivityContext *ctx) { + std::vector EnumMeta(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::EnumMeta>(ctx); } + void BackgroundRoutine(RdxActivityContext* ctx) { if (hasCopy_.load(std::memory_order_acquire)) { return; } @@ -157,45 +159,45 @@ class Namespace { } nsFuncWrapper<&NamespaceImpl::StorageFlushingRoutine>(); } - void CloseStorage(const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::CloseStorage>(ctx); } - Transaction NewTransaction(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::NewTransaction>(ctx); } + void CloseStorage(const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::CloseStorage>(ctx); } + Transaction NewTransaction(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::NewTransaction>(ctx); } - Item NewItem(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::NewItem>(ctx); } - void ToPool(ItemImpl *item) { nsFuncWrapper<&NamespaceImpl::ToPool>(item); } - std::string GetMeta(const std::string &key, const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetMeta>(key, ctx); } - void PutMeta(const std::string &key, std::string_view data, const RdxContext &ctx) { + Item NewItem(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::NewItem>(ctx); } + void ToPool(ItemImpl* item) { nsFuncWrapper<&NamespaceImpl::ToPool>(item); } + std::string GetMeta(const std::string& key, const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetMeta>(key, ctx); } + void PutMeta(const std::string& key, std::string_view data, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::PutMeta>(key, data, ctx); } - void DeleteMeta(const std::string &key, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::DeleteMeta>(key, ctx); } - int64_t GetSerial(const std::string &field) { return nsFuncWrapper<&NamespaceImpl::GetSerial>(field); } + void DeleteMeta(const std::string& key, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::DeleteMeta>(key, ctx); } + int64_t GetSerial(const std::string& field) { return nsFuncWrapper<&NamespaceImpl::GetSerial>(field); } int getIndexByName(std::string_view index) const { return nsFuncWrapper<&NamespaceImpl::getIndexByName>(index); } - bool getIndexByName(std::string_view name, int &index) const { return nsFuncWrapper<&NamespaceImpl::tryGetIndexByName>(name, index); } - void FillResult(QueryResults &result, const IdSet &ids) const { nsFuncWrapper<&NamespaceImpl::FillResult>(result, ids); } + bool getIndexByName(std::string_view name, int& index) const { return nsFuncWrapper<&NamespaceImpl::tryGetIndexByName>(name, index); } + void FillResult(QueryResults& result, const IdSet& ids) const { nsFuncWrapper<&NamespaceImpl::FillResult>(result, ids); } void EnablePerfCounters(bool enable = true) { nsFuncWrapper<&NamespaceImpl::EnablePerfCounters>(enable); } - ReplicationState GetReplState(const RdxContext &ctx) const { return nsFuncWrapper<&NamespaceImpl::GetReplState>(ctx); } - void SetReplLSNs(LSNPair LSNs, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::SetReplLSNs>(LSNs, ctx); } - void SetSlaveReplStatus(ReplicationState::Status status, const Error &error, const RdxContext &ctx) { + ReplicationState GetReplState(const RdxContext& ctx) const { return nsFuncWrapper<&NamespaceImpl::GetReplState>(ctx); } + void SetReplLSNs(LSNPair LSNs, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::SetReplLSNs>(LSNs, ctx); } + void SetSlaveReplStatus(ReplicationState::Status status, const Error& error, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::SetSlaveReplStatus>(status, error, ctx); } - void SetSlaveReplMasterState(MasterState state, const RdxContext &ctx) { + void SetSlaveReplMasterState(MasterState state, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::SetSlaveReplMasterState>(state, ctx); } - Error ReplaceTagsMatcher(const TagsMatcher &tm, const RdxContext &ctx) { + Error ReplaceTagsMatcher(const TagsMatcher& tm, const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::ReplaceTagsMatcher>(tm, ctx); } - void Rename(const Namespace::Ptr &dst, const std::string &storagePath, const RdxContext &ctx) { + void Rename(const Namespace::Ptr& dst, const std::string& storagePath, const RdxContext& ctx) { if (this == dst.get() || dst == nullptr) { return; } doRename(dst, std::string(), storagePath, ctx); } - void Rename(const std::string &newName, const std::string &storagePath, const RdxContext &ctx) { + void Rename(const std::string& newName, const std::string& storagePath, const RdxContext& ctx) { if (newName.empty()) { return; } doRename(nullptr, newName, storagePath, ctx); } - void OnConfigUpdated(DBConfigProvider &configProvider, const RdxContext &ctx) { + void OnConfigUpdated(DBConfigProvider& configProvider, const RdxContext& ctx) { NamespaceConfigData configData; const auto nsName = GetName(ctx); std::string_view realNsName(nsName); @@ -210,11 +212,11 @@ class Namespace { longUpdDelLoggingParams_.store(configProvider.GetUpdDelLoggingParams(), std::memory_order_relaxed); nsFuncWrapper<&NamespaceImpl::OnConfigUpdated>(configProvider, ctx); } - StorageOpts GetStorageOpts(const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::GetStorageOpts>(ctx); } - void Refill(std::vector &items, const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::Refill>(items, ctx); } - void MergeTagsMatcher(const TagsMatcher &tm, const RdxContext &ctx) { return nsFuncWrapper<&NamespaceImpl::MergeTagsMatcher>(tm, ctx); } + StorageOpts GetStorageOpts(const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::GetStorageOpts>(ctx); } + void Refill(std::vector& items, const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::Refill>(items, ctx); } + void MergeTagsMatcher(const TagsMatcher& tm, const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::MergeTagsMatcher>(tm, ctx); } - void DumpIndex(std::ostream &os, std::string_view index, const RdxContext &ctx) { + void DumpIndex(std::ostream& os, std::string_view index, const RdxContext& ctx) { return nsFuncWrapper<&NamespaceImpl::DumpIndex>(os, index, ctx); } @@ -222,9 +224,9 @@ class Namespace { friend class ReindexerImpl; friend class QueryResults; void updateSelectTime() const { nsFuncWrapper<&NamespaceImpl::updateSelectTime>(); } - void setSlaveMode(const RdxContext &ctx) { nsFuncWrapper<&NamespaceImpl::setSlaveMode>(ctx); } + void setSlaveMode(const RdxContext& ctx) { nsFuncWrapper<&NamespaceImpl::setSlaveMode>(ctx); } NamespaceImpl::Ptr getMainNs() const { return atomicLoadMainNs(); } - NamespaceImpl::Ptr awaitMainNs(const RdxContext &ctx) const { + NamespaceImpl::Ptr awaitMainNs(const RdxContext& ctx) const { if (hasCopy_.load(std::memory_order_acquire)) { contexted_unique_lock lck(clonerMtx_, ctx); assertrx(!hasCopy_.load(std::memory_order_acquire)); @@ -234,14 +236,14 @@ class Namespace { } private: - bool needNamespaceCopy(const NamespaceImpl::Ptr &ns, const Transaction &tx) const noexcept; - bool isExpectingSelectsOnNamespace(const NamespaceImpl::Ptr &ns, const RdxContext &ctx); - void doRename(const Namespace::Ptr &dst, const std::string &newName, const std::string &storagePath, const RdxContext &ctx); + bool needNamespaceCopy(const NamespaceImpl::Ptr& ns, const Transaction& tx) const noexcept; + bool isExpectingSelectsOnNamespace(const NamespaceImpl::Ptr& ns, const RdxContext& ctx); + void doRename(const Namespace::Ptr& dst, const std::string& newName, const std::string& storagePath, const RdxContext& ctx); NamespaceImpl::Ptr atomicLoadMainNs() const { std::lock_guard lck(nsPtrSpinlock_); return ns_; } - void atomicStoreMainNs(NamespaceImpl *ns) { + void atomicStoreMainNs(NamespaceImpl* ns) { std::lock_guard lck(nsPtrSpinlock_); ns_.reset(ns); } @@ -260,7 +262,7 @@ class Namespace { PerfStatCounterMT copyStatsCounter_; std::atomic longTxLoggingParams_; std::atomic longUpdDelLoggingParams_; - BackgroundNamespaceDeleter &bgDeleter_; + BackgroundNamespaceDeleter& bgDeleter_; }; } // namespace reindexer diff --git a/cpp_src/core/namespace/namespaceimpl.cc b/cpp_src/core/namespace/namespaceimpl.cc index e71e2f1a3..e7257c26c 100644 --- a/cpp_src/core/namespace/namespaceimpl.cc +++ b/cpp_src/core/namespace/namespaceimpl.cc @@ -6,6 +6,7 @@ #include "core/cjson/defaultvaluecoder.h" #include "core/cjson/jsonbuilder.h" #include "core/cjson/uuid_recoders.h" +#include "core/formatters/lsn_fmt.h" #include "core/index/index.h" #include "core/index/ttlindex.h" #include "core/itemimpl.h" @@ -98,7 +99,9 @@ NamespaceImpl::NamespaceImpl(const NamespaceImpl& src, AsyncStorage::FullLockT& strHolder_{makeStringsHolder()}, nsUpdateSortedContextMemory_{0}, dbDestroyed_(false) { - for (auto& idxIt : src.indexes_) indexes_.push_back(idxIt->Clone()); + for (auto& idxIt : src.indexes_) { + indexes_.push_back(idxIt->Clone()); + } markUpdated(IndexOptimization::Full); logPrintf(LogInfo, "Namespace::CopyContentsFrom (%s).Workers: %d, timeout: %d, tm: { state_token: 0x%08X, version: %d }", name_, @@ -140,7 +143,7 @@ NamespaceImpl::NamespaceImpl(const std::string& name, UpdatesObservers& observer NamespaceImpl::~NamespaceImpl() { const unsigned int kMaxItemCountNoThread = 1'000'000; - const bool allowLeak = rxAllowNamespaceLeak.load(std::memory_order::memory_order_relaxed); + const bool allowLeak = rxAllowNamespaceLeak.load(std::memory_order_relaxed); unsigned int threadsCount = 0; ThreadTaskQueueImpl tasks; @@ -285,7 +288,9 @@ void NamespaceImpl::OnConfigUpdated(DBConfigProvider& configProvider, const RdxC logPrintf(LogInfo, "[%s] WAL has been resized lsn #%s, max size %ld", name_, repl_.lastLsn, wal_.Capacity()); } - if (isSystem()) return; + if (isSystem()) { + return; + } if (serverId_ != replicationConf.serverId) { serverId_ = replicationConf.serverId; @@ -293,7 +298,9 @@ void NamespaceImpl::OnConfigUpdated(DBConfigProvider& configProvider, const RdxC replStateUpdates_.fetch_add(1, std::memory_order_release); } - if (repl_.temporary) return; + if (repl_.temporary) { + return; + } ReplicationRole curRole; if (repl_.slaveMode && !repl_.replicatorEnabled) { // read only @@ -310,9 +317,15 @@ void NamespaceImpl::OnConfigUpdated(DBConfigProvider& configProvider, const RdxC if (!replicationConf.namespaces.empty() && replicationConf.namespaces.find(name_) == replicationConf.namespaces.end()) { newRole = ReplicationMaster; } - if (newRole == curRole) return; - if (newRole == ReplicationNone && curRole == ReplicationMaster) return; - if (curRole == ReplicationReadOnly && serverIdChanged_) return; + if (newRole == curRole) { + return; + } + if (newRole == ReplicationNone && curRole == ReplicationMaster) { + return; + } + if (curRole == ReplicationReadOnly && serverIdChanged_) { + return; + } // switch slave -> master // switch master -> slave @@ -359,7 +372,9 @@ class NamespaceImpl::RollBack_recreateCompositeIndexes final : private RollBackB } } void RollBack() noexcept { - if (IsDisabled()) return; + if (IsDisabled()) { + return; + } for (size_t i = 0, s = indexes_.size(); i < s; ++i) { std::swap(ns_.indexes_[i + startIdx_], indexes_[i]); } @@ -435,7 +450,9 @@ class NamespaceImpl::RollBack_updateItems final : private RollBackBase { RollBackBase::Disable(); } void RollBack() noexcept { - if (IsDisabled()) return; + if (IsDisabled()) { + return; + } if (!items_.empty()) { ns_.repl_.dataHash = dataHash_; ns_.itemsDataSize_ = itemsDataSize_; @@ -483,7 +500,6 @@ std::vector NamespaceImpl::pickJsonPath(const PayloadFieldType& fld) { std::swap(result.front(), result.back()); } } - return result; } @@ -573,8 +589,8 @@ NamespaceImpl::RollBack_updateItems NamespaceImpl::updateItems(con itemsDataSize_ = 0; auto indexesCacheCleaner{GetIndexesCacheCleaner()}; - auto &tuple = *indexes_[0]; - auto &index = *indexes_[changedField]; + auto& tuple = *indexes_[0]; + auto& index = *indexes_[changedField]; WrSerializer pk, data; for (size_t rowId = 0; rowId < items_.size(); ++rowId) { @@ -627,7 +643,7 @@ NamespaceImpl::RollBack_updateItems NamespaceImpl::updateItems(con for (int fieldIdx = compositeStartIdx; fieldIdx < compositeEndIdx; ++fieldIdx) { needClearCache = false; - auto &fieldIndex = *indexes_[fieldIdx]; + auto& fieldIndex = *indexes_[fieldIdx]; fieldIndex.Upsert(Variant(plNew), rowId, needClearCache); if (needClearCache && fieldIndex.IsOrdered()) { indexesCacheCleaner.Add(fieldIndex.SortId()); @@ -737,7 +753,9 @@ void NamespaceImpl::SetSchema(std::string_view schema, const RdxContext& ctx) { "0x%08X, version: %d }", name_, serverId_, tagsMatcher_.stateToken(), initTmVer, tagsMatcher_.stateToken(), tagsMatcher_.version()); const lsn_t lsn(wal_.Add(WALRecord(WalEmpty), lsn_t()), serverId_); - if (!ctx.fromReplication_) repl_.lastSelfLSN = lsn; + if (!ctx.fromReplication_) { + repl_.lastSelfLSN = lsn; + } if (!repl_.temporary) { WrSerializer wser; wser.PutVarint(tagsMatcher_.version()); @@ -759,7 +777,9 @@ std::string NamespaceImpl::GetSchema(int format, const RdxContext& ctx) { schema_->GetJSON(ser); } else if (format == ProtobufSchemaType) { Error err = schema_->GetProtobufSchema(ser); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } } else { throw Error(errParams, "Unknown schema type: %d", format); } @@ -792,12 +812,15 @@ void NamespaceImpl::dropIndex(const IndexDef& index) { int fieldIdx = itIdxName->second; std::unique_ptr& indexToRemove = indexes_[fieldIdx]; - if (!IsComposite(indexToRemove->Type()) && indexToRemove->Opts().IsSparse()) --sparseIndexesCount_; + if (!IsComposite(indexToRemove->Type()) && indexToRemove->Opts().IsSparse()) { + --sparseIndexesCount_; + } // Check, that index to remove is not a part of composite index for (int i = indexes_.firstCompositePos(); i < indexes_.totalSize(); ++i) { - if (indexes_[i]->Fields().contains(fieldIdx)) + if (indexes_[i]->Fields().contains(fieldIdx)) { throw Error(errLogic, "Cannot remove index %s : it's a part of a composite index %s", index.name_, indexes_[i]->Name()); + } } for (auto& namePair : indexesNames_) { if (namePair.second >= fieldIdx) { @@ -863,7 +886,9 @@ static void verifyConvertTypes(KeyValueType from, KeyValueType to, const Payload [&](KeyValueType::Bool) noexcept { value = Variant(false); }, [](KeyValueType::Null) noexcept {}, [&](KeyValueType::Int) noexcept { value = Variant(0); }, [&](KeyValueType::Uuid) noexcept { value = Variant{Uuid{}}; }, [&](OneOf) { - if (!to.IsSame(from)) throw Error(errParams, "Cannot convert key from type %s to %s", from.Name(), to.Name()); + if (!to.IsSame(from)) { + throw Error(errParams, "Cannot convert key from type %s to %s", from.Name(), to.Name()); + } }); value.convert(to, &payloadType, &fields); } @@ -1006,7 +1031,9 @@ class NamespaceImpl::RollBack_insertIndex final : private RollBackBase { RollBack_insertIndex(RollBack_insertIndex&&) noexcept = default; ~RollBack_insertIndex() override { RollBack(); } void RollBack() noexcept { - if (IsDisabled()) return; + if (IsDisabled()) { + return; + } if (insertedIdxName_) { try { ns_.indexesNames_.erase(*insertedIdxName_); @@ -1081,19 +1108,35 @@ class NamespaceImpl::RollBack_addIndex final : private RollBackBase { RollBack_addIndex(const RollBack_addIndex&) = delete; ~RollBack_addIndex() override { RollBack(); } void RollBack() noexcept { - if (IsDisabled()) return; - if (oldPayloadType_) ns_.payloadType_ = std::move(*oldPayloadType_); - if (needDecreaseSparseIndexCount_) --ns_.sparseIndexesCount_; - if (rollbacker_updateItems_) rollbacker_updateItems_->RollBack(); - if (rollbacker_insertIndex_) rollbacker_insertIndex_->RollBack(); - if (needResetPayloadTypeInTagsMatcher_) ns_.tagsMatcher_.UpdatePayloadType(ns_.payloadType_); + if (IsDisabled()) { + return; + } + if (oldPayloadType_) { + ns_.payloadType_ = std::move(*oldPayloadType_); + } + if (needDecreaseSparseIndexCount_) { + --ns_.sparseIndexesCount_; + } + if (rollbacker_updateItems_) { + rollbacker_updateItems_->RollBack(); + } + if (rollbacker_insertIndex_) { + rollbacker_insertIndex_->RollBack(); + } + if (needResetPayloadTypeInTagsMatcher_) { + ns_.tagsMatcher_.UpdatePayloadType(ns_.payloadType_); + } Disable(); } void RollBacker_insertIndex(RollBack_insertIndex&& rb) noexcept { rollbacker_insertIndex_.emplace(std::move(rb)); } void RollBacker_updateItems(RollBack_updateItems&& rb) noexcept { rollbacker_updateItems_.emplace(std::move(rb)); } void Disable() noexcept override { - if (rollbacker_insertIndex_) rollbacker_insertIndex_->Disable(); - if (rollbacker_updateItems_) rollbacker_updateItems_->Disable(); + if (rollbacker_insertIndex_) { + rollbacker_insertIndex_->Disable(); + } + if (rollbacker_updateItems_) { + rollbacker_updateItems_->Disable(); + } RollBackBase::Disable(); } void NeedDecreaseSparseIndexCount() noexcept { needDecreaseSparseIndexCount_ = true; } @@ -1196,7 +1239,9 @@ void NamespaceImpl::fillSparseIndex(Index& index, std::string_view jsonPath) { krefs.resize(0); bool needClearCache{false}; index.Upsert(krefs, skrefs, int(rowId), needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } scheduleIndexOptimization(IndexOptimization::Partial); } @@ -1256,7 +1301,9 @@ void NamespaceImpl::addCompositeIndex(const IndexDef& indexDef) { if (!items_[rowId].IsFree()) { bool needClearCache{false}; indexes_[idxPos]->Upsert(Variant(items_[rowId]), rowId, needClearCache); - if (needClearCache && indexes_[idxPos]->IsOrdered()) indexesCacheCleaner.Add(indexes_[idxPos]->SortId()); + if (needClearCache && indexes_[idxPos]->IsOrdered()) { + indexesCacheCleaner.Add(indexes_[idxPos]->SortId()); + } } } @@ -1336,7 +1383,9 @@ int NamespaceImpl::getScalarIndexByName(std::string_view index) const { bool NamespaceImpl::tryGetIndexByName(std::string_view name, int& index) const { auto it = indexesNames_.find(name); - if (it == indexesNames_.end()) return false; + if (it == indexesNames_.end()) { + return false; + } index = it->second; return true; } @@ -1396,9 +1445,15 @@ void NamespaceImpl::doUpdate(const Query& query, QueryResults& result, const NsC bool updateWithJson = false; bool withExpressions = false; for (const UpdateEntry& ue : query.UpdateFields()) { - if (ue.IsExpression()) withExpressions = true; - if (ue.Mode() == FieldModeSetJson) updateWithJson = true; - if (withExpressions && updateWithJson) break; + if (ue.IsExpression()) { + withExpressions = true; + } + if (ue.Mode() == FieldModeSetJson) { + updateWithJson = true; + } + if (withExpressions && updateWithJson) { + break; + } } if (ctx.rdxContext.fromReplication_ && withExpressions) { @@ -1477,14 +1532,19 @@ void NamespaceImpl::replicateItem(IdType itemId, const NsContext& ctx, bool stat auto sendWalUpdate = [this, itemId, &ctx, &pv](ItemModifyMode mode) { lsn_t lsn(wal_.Add(WALRecord(WalItemUpdate, itemId, ctx.inTransaction), lsn_t(pv.GetLSN())), serverId_); - if (!ctx.rdxContext.fromReplication_) repl_.lastSelfLSN = lsn; + if (!ctx.rdxContext.fromReplication_) { + repl_.lastSelfLSN = lsn; + } pv.SetLSN(int64_t(lsn)); ItemImpl item(payloadType_, pv, tagsMatcher_); std::string_view cjson = item.GetCJSON(false); - if (!repl_.temporary) + if (!repl_.temporary) { observers_->OnWALUpdate(LSNPair(lsn, ctx.rdxContext.fromReplication_ ? ctx.rdxContext.LSNs_.originLSN_ : lsn), name_, WALRecord(WalItemModify, cjson, tagsMatcher_.version(), mode, ctx.inTransaction)); - if (!ctx.rdxContext.fromReplication_) setReplLSNs(LSNPair(lsn_t(), lsn)); + } + if (!ctx.rdxContext.fromReplication_) { + setReplLSNs(LSNPair(lsn_t(), lsn)); + } }; if (!statementReplication) { @@ -1564,7 +1624,9 @@ void NamespaceImpl::doDelete(IdType id) { for (field = indexes_.firstCompositePos(); field < indexes_.totalSize(); ++field) { bool needClearCache{false}; indexes_[field]->Delete(Variant(items_[id]), id, *strHolder_, needClearCache); - if (needClearCache && indexes_[field]->IsOrdered()) indexesCacheCleaner.Add(indexes_[field]->SortId()); + if (needClearCache && indexes_[field]->IsOrdered()) { + indexesCacheCleaner.Add(indexes_[field]->SortId()); + } } // Holder for tuple. It is required for sparse indexes will be valid @@ -1594,7 +1656,9 @@ void NamespaceImpl::doDelete(IdType id) { // Delete value from index bool needClearCache{false}; index.Delete(skrefs, id, *strHolder_, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } while (++field != borderIdx); // free PayloadValue @@ -1640,7 +1704,9 @@ void NamespaceImpl::doDelete(const Query& query, QueryResults& result, const NsC for (auto it : result) { cjson.Reset(); const auto err = it.GetCJSON(cjson, false); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } const WALRecord wrec{WalItemModify, cjson.Slice(), tagsMatcher_.version(), ModeDelete, ctx.inTransaction}; processWalRecord(wrec, ctx.rdxContext); } @@ -1673,7 +1739,9 @@ void NamespaceImpl::Truncate(const RdxContext& ctx) { void NamespaceImpl::doTruncate(const NsContext& ctx) { if (storage_.IsValid()) { for (PayloadValue& pv : items_) { - if (pv.IsFree()) continue; + if (pv.IsFree()) { + continue; + } Payload pl(payloadType_, pv); WrSerializer pk; pk << kRxStorageItemPrefix; @@ -1698,11 +1766,16 @@ void NamespaceImpl::doTruncate(const NsContext& ctx) { WALRecord wrec(WalUpdateQuery, (ser << "TRUNCATE " << name_).Slice()); lsn_t lsn(wal_.Add(wrec), serverId_); - if (!ctx.rdxContext.fromReplication_) repl_.lastSelfLSN = lsn; + if (!ctx.rdxContext.fromReplication_) { + repl_.lastSelfLSN = lsn; + } markUpdated(IndexOptimization::Full); - if (!repl_.temporary) + if (!repl_.temporary) { observers_->OnWALUpdate(LSNPair(lsn, ctx.rdxContext.fromReplication_ ? ctx.rdxContext.LSNs_.originLSN_ : lsn), name_, wrec); - if (!ctx.rdxContext.fromReplication_) setReplLSNs(LSNPair(lsn_t(), lsn)); + } + if (!ctx.rdxContext.fromReplication_) { + setReplLSNs(LSNPair(lsn_t(), lsn)); + } } void NamespaceImpl::Refill(std::vector& items, const RdxContext& ctx) { @@ -1849,9 +1922,12 @@ void NamespaceImpl::CommitTransaction(Transaction& tx, QueryResults& result, NsC WALRecord initWrec(WalInitTransaction, 0, true); lsn_t lsn(wal_.Add(initWrec), serverId_); - if (!ctx.rdxContext.fromReplication_) repl_.lastSelfLSN = lsn; - if (!repl_.temporary) + if (!ctx.rdxContext.fromReplication_) { + repl_.lastSelfLSN = lsn; + } + if (!repl_.temporary) { observers_->OnWALUpdate(LSNPair(lsn, ctx.rdxContext.fromReplication_ ? ctx.rdxContext.LSNs_.originLSN_ : lsn), name_, initWrec); + } AsyncStorage::AdviceGuardT storageAdvice; if (tx.GetSteps().size() >= AsyncStorage::kLimitToAdviceBatching) { @@ -1928,7 +2004,9 @@ void NamespaceImpl::doUpsert(ItemImpl* ritem, IdType id, bool doUpdate) { for (size_t field = 0; field < compIndexesCount; ++field) { const auto& fields = indexes_[field + indexes_.firstCompositePos()]->Fields(); for (const auto f : fields) { - if (f == IndexValueType::SetByJsonPath) continue; + if (f == IndexValueType::SetByJsonPath) { + continue; + } pl.Get(f, skrefs); plNew.Get(f, krefs); if (skrefs != krefs) { @@ -1937,7 +2015,9 @@ void NamespaceImpl::doUpsert(ItemImpl* ritem, IdType id, bool doUpdate) { break; } } - if (needUpdateCompIndexes[field]) continue; + if (needUpdateCompIndexes[field]) { + continue; + } for (size_t i = 0, end = fields.getTagsPathsLength(); i < end; ++i) { const auto& tp = fields.getTagsPath(i); pl.GetByJsonPath(tp, skrefs, KeyValueType::Undefined{}); @@ -1983,7 +2063,9 @@ void NamespaceImpl::doUpsert(ItemImpl* ritem, IdType id, bool doUpdate) { } if (index.Opts().GetCollateMode() == CollateUTF8) { - for (auto& key : skrefs) key.EnsureUTF8(); + for (auto& key : skrefs) { + key.EnsureUTF8(); + } } // Check for update @@ -2001,16 +2083,22 @@ void NamespaceImpl::doUpsert(ItemImpl* ritem, IdType id, bool doUpdate) { } else { pl.Get(field, krefs); } - if ((krefs.ArrayType().Is() && skrefs.ArrayType().Is()) || krefs == skrefs) continue; + if ((krefs.ArrayType().Is() && skrefs.ArrayType().Is()) || krefs == skrefs) { + continue; + } bool needClearCache{false}; index.Delete(krefs, id, *strHolder_, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } } // Put value to index krefs.resize(0); bool needClearCache{false}; index.Upsert(krefs, skrefs, id, needClearCache); - if (needClearCache && index.IsOrdered()) indexesCacheCleaner.Add(index.SortId()); + if (needClearCache && index.IsOrdered()) { + indexesCacheCleaner.Add(index.SortId()); + } if (!isIndexSparse) { // Put value to payload @@ -2022,12 +2110,16 @@ void NamespaceImpl::doUpsert(ItemImpl* ritem, IdType id, bool doUpdate) { for (int field2 = indexes_.firstCompositePos(); field2 < indexes_.totalSize(); ++field2) { bool needClearCache{false}; if (doUpdate) { - if (!needUpdateCompIndexes[field2 - indexes_.firstCompositePos()]) continue; + if (!needUpdateCompIndexes[field2 - indexes_.firstCompositePos()]) { + continue; + } // Delete from composite indexes first indexes_[field2]->Delete(oldData, id, *strHolder_, needClearCache); } indexes_[field2]->Upsert(Variant{plData}, id, needClearCache); - if (needClearCache && indexes_[field2]->IsOrdered()) indexesCacheCleaner.Add(indexes_[field2]->SortId()); + if (needClearCache && indexes_[field2]->IsOrdered()) { + indexesCacheCleaner.Add(indexes_[field2]->SortId()); + } } repl_.dataHash ^= pl.GetHash(); itemsDataSize_ += plData.GetCapacity() + sizeof(PayloadValue::dataHeader); @@ -2083,10 +2175,13 @@ void NamespaceImpl::updateTagsMatcherFromItem(ItemImpl* ritem) { *ritem = std::move(tmpItem); auto err = ritem->FromJSON(jsonSliceBuf, nullptr); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } - if (ritem->tagsMatcher().isUpdated() && !tagsMatcher_.try_merge(ritem->tagsMatcher())) + if (ritem->tagsMatcher().isUpdated() && !tagsMatcher_.try_merge(ritem->tagsMatcher())) { throw Error(errLogic, "Could not insert item. TagsMatcher was not merged."); + } ritem->tagsMatcher() = tagsMatcher_; ritem->tagsMatcher().setUpdated(); } else if (ritem->tagsMatcher().isUpdated()) { @@ -2145,7 +2240,9 @@ void NamespaceImpl::doModifyItem(Item& item, ItemModifyMode mode, const NsContex IdType id = exists ? realItem.first : createItem(newPl.RealSize()); lsn_t lsn(wal_.Add(WALRecord(WalItemUpdate, id, ctx.inTransaction), exists ? lsn_t(items_[id].GetLSN()) : lsn_t()), serverId_); - if (!ctx.rdxContext.fromReplication_) repl_.lastSelfLSN = lsn; + if (!ctx.rdxContext.fromReplication_) { + repl_.lastSelfLSN = lsn; + } item.setLSN(int64_t(lsn)); item.setID(id); @@ -2163,11 +2260,14 @@ void NamespaceImpl::doModifyItem(Item& item, ItemModifyMode mode, const NsContex if (!repl_.temporary) { // not send row with fromReplication=true and originLSN_= empty - if (!ctx.rdxContext.fromReplication_ || !ctx.rdxContext.LSNs_.originLSN_.isEmpty()) + if (!ctx.rdxContext.fromReplication_ || !ctx.rdxContext.LSNs_.originLSN_.isEmpty()) { observers_->OnModifyItem(LSNPair(lsn, ctx.rdxContext.fromReplication_ ? ctx.rdxContext.LSNs_.originLSN_ : lsn), name_, item.impl_, mode, ctx.inTransaction); + } + } + if (!ctx.rdxContext.fromReplication_) { + setReplLSNs(LSNPair(lsn_t(), lsn)); } - if (!ctx.rdxContext.fromReplication_) setReplLSNs(LSNPair(lsn_t(), lsn)); markUpdated(exists ? IndexOptimization::Partial : IndexOptimization::Full); } @@ -2180,8 +2280,9 @@ RX_ALWAYS_INLINE VariantArray NamespaceImpl::getPkKeys(const ConstPayload& cpl, keys.emplace_back(*cpl.Value()); } else if (pkIndex->Opts().IsSparse()) { cpl.GetByJsonPath(pkIndex->Fields().getTagsPath(0), keys, pkIndex->KeyType()); - } else + } else { cpl.Get(fieldNum, keys); + } return keys; } @@ -2201,7 +2302,9 @@ RX_ALWAYS_INLINE SelectKeyResult NamespaceImpl::getPkDocs(const ConstPayload& cp // find id by PK. NOT THREAD SAFE! std::pair NamespaceImpl::findByPK(ItemImpl* ritem, bool inTransaction, const RdxContext& ctx) { SelectKeyResult res = getPkDocs(ritem->GetConstPayload(), inTransaction, ctx); - if (res.size() && res[0].ids_.size()) return {res[0].ids_[0], true}; + if (res.size() && res[0].ids_.size()) { + return {res[0].ids_[0], true}; + } return {-1, false}; } @@ -2232,7 +2335,9 @@ void NamespaceImpl::optimizeIndexes(const NsContext& ctx) { // This is read lock only atomics based implementation of rebuild indexes // If optimizationState_ == OptimizationCompleted is true, then indexes are completely built. // In this case reset optimizationState_ and/or any idset's and sort orders builds are allowed only protected by write lock - if (optimizationState_.load(std::memory_order_relaxed) == OptimizationCompleted) return; + if (optimizationState_.load(std::memory_order_relaxed) == OptimizationCompleted) { + return; + } auto lastUpdateTime = lastUpdateTime_.load(std::memory_order_acquire); Locker::RLockT rlck; @@ -2240,7 +2345,8 @@ void NamespaceImpl::optimizeIndexes(const NsContext& ctx) { rlck = rLock(ctx.rdxContext); } - if (isSystem() || repl_.temporary || !indexes_.size() || !lastUpdateTime || !config_.optimizationTimeout) { + if (isSystem() || repl_.temporary || !indexes_.size() || !lastUpdateTime || !config_.optimizationTimeout || + !config_.optimizationSortWorkers) { return; } const auto optState{optimizationState_.load(std::memory_order_acquire)}; @@ -2290,12 +2396,18 @@ void NamespaceImpl::optimizeIndexes(const NsContext& ctx) { } }); } - for (size_t i = 0; i < maxIndexWorkers; i++) thrs[i].join(); + for (size_t i = 0; i < maxIndexWorkers; i++) { + thrs[i].join(); + } + } + if (cancelCommitCnt_.load(std::memory_order_relaxed)) { + break; } - if (cancelCommitCnt_.load(std::memory_order_relaxed)) break; } - if (dbDestroyed_.load(std::memory_order_relaxed)) return; + if (dbDestroyed_.load(std::memory_order_relaxed)) { + return; + } if (maxIndexWorkers && !cancelCommitCnt_.load(std::memory_order_relaxed)) { optimizationState_.store(OptimizationCompleted, std::memory_order_release); @@ -2306,9 +2418,9 @@ void NamespaceImpl::optimizeIndexes(const NsContext& ctx) { } } if (cancelCommitCnt_.load(std::memory_order_relaxed)) { - logPrintf(LogTrace, "Namespace::optimizeIndexes(%s) done", name_); - } else { logPrintf(LogTrace, "Namespace::optimizeIndexes(%s) was cancelled by concurrent update", name_); + } else { + logPrintf(LogTrace, "Namespace::optimizeIndexes(%s) done", name_); } } @@ -2483,7 +2595,9 @@ void NamespaceImpl::ResetPerfStat(const RdxContext& ctx) { auto rlck = rLock(ctx); selectPerfCounter_.Reset(); updatePerfCounter_.Reset(); - for (auto& i : indexes_) i->ResetIndexPerfStat(); + for (auto& i : indexes_) { + i->ResetIndexPerfStat(); + } } Error NamespaceImpl::loadLatestSysRecord(std::string_view baseSysTag, uint64_t& version, std::string& content) { @@ -2664,7 +2778,9 @@ void NamespaceImpl::saveIndexesToStorage() { // clear ItemImpl pool on payload change pool_.clear(); - if (!storage_.IsValid()) return; + if (!storage_.IsValid()) { + return; + } logPrintf(LogTrace, "Namespace::saveIndexesToStorage (%s)", name_); @@ -2689,11 +2805,15 @@ void NamespaceImpl::saveIndexesToStorage() { } void NamespaceImpl::saveSchemaToStorage() { - if (!storage_.IsValid()) return; + if (!storage_.IsValid()) { + return; + } logPrintf(LogTrace, "Namespace::saveSchemaToStorage (%s)", name_); - if (!schema_) return; + if (!schema_) { + return; + } WrSerializer ser; ser.PutUInt64(sysRecordsVersions_.schemaVersion); @@ -2709,7 +2829,9 @@ void NamespaceImpl::saveSchemaToStorage() { } void NamespaceImpl::saveReplStateToStorage(bool direct) { - if (!storage_.IsValid()) return; + if (!storage_.IsValid()) { + return; + } if (direct) { replStateUpdates_.store(0, std::memory_order_release); @@ -2858,7 +2980,9 @@ void NamespaceImpl::removeExpiredItems(RdxActivityContext* ctx) { } lastExpirationCheckTs_ = now; for (const std::unique_ptr& index : indexes_) { - if ((index->Type() != IndexTtl) || (index->Size() == 0)) continue; + if ((index->Type() != IndexTtl) || (index->Size() == 0)) { + continue; + } const int64_t expirationThreshold = std::chrono::duration_cast(system_clock_w::now_coarse().time_since_epoch()).count() - index->GetTTLValue(); @@ -3068,16 +3192,23 @@ void NamespaceImpl::warmupFtIndexes() { } int NamespaceImpl::getSortedIdxCount() const noexcept { - if (!config_.optimizationSortWorkers) return 0; + if (!config_.optimizationSortWorkers) { + return 0; + } int cnt = 0; - for (auto& it : indexes_) - if (it->IsOrdered()) cnt++; + for (auto& it : indexes_) { + if (it->IsOrdered()) { + cnt++; + } + } return cnt; } void NamespaceImpl::updateSortedIdxCount() { int sortedIdxCount = getSortedIdxCount(); - for (auto& idx : indexes_) idx->SetSortedIdxCount(sortedIdxCount); + for (auto& idx : indexes_) { + idx->SetSortedIdxCount(sortedIdxCount); + } scheduleIndexOptimization(IndexOptimization::Full); } @@ -3165,13 +3296,17 @@ void NamespaceImpl::FillResult(QueryResults& result, const IdSet& ids) const { } void NamespaceImpl::getFromJoinCache(const Query& q, const JoinedQuery& jq, JoinCacheRes& out) const { - if (config_.cacheMode == CacheModeOff || optimizationState_ != OptimizationCompleted) return; + if (config_.cacheMode == CacheModeOff || optimizationState_ != OptimizationCompleted) { + return; + } out.key.SetData(jq, q); getFromJoinCacheImpl(out); } void NamespaceImpl::getFromJoinCache(const Query& q, JoinCacheRes& out) const { - if (config_.cacheMode == CacheModeOff || optimizationState_ != OptimizationCompleted) return; + if (config_.cacheMode == CacheModeOff || optimizationState_ != OptimizationCompleted) { + return; + } out.key.SetData(q); getFromJoinCacheImpl(out); } @@ -3191,7 +3326,9 @@ void NamespaceImpl::getFromJoinCacheImpl(JoinCacheRes& ctx) const { } void NamespaceImpl::getInsideFromJoinCache(JoinCacheRes& ctx) const { - if (config_.cacheMode != CacheModeAggressive || optimizationState_ != OptimizationCompleted) return; + if (config_.cacheMode != CacheModeAggressive || optimizationState_ != OptimizationCompleted) { + return; + } getFromJoinCacheImpl(ctx); } @@ -3219,14 +3356,24 @@ const FieldsSet& NamespaceImpl::pkFields() { void NamespaceImpl::processWalRecord(const WALRecord& wrec, const RdxContext& ctx, lsn_t itemLsn, Item* item) { lsn_t lsn(wal_.Add(wrec, itemLsn), serverId_); - if (!ctx.fromReplication_) repl_.lastSelfLSN = lsn; - if (item) item->setLSN(int64_t(lsn)); - if (!repl_.temporary) observers_->OnWALUpdate(LSNPair(lsn, ctx.fromReplication_ ? ctx.LSNs_.originLSN_ : lsn), name_, wrec); - if (!ctx.fromReplication_) setReplLSNs(LSNPair(lsn_t(), lsn)); + if (!ctx.fromReplication_) { + repl_.lastSelfLSN = lsn; + } + if (item) { + item->setLSN(int64_t(lsn)); + } + if (!repl_.temporary) { + observers_->OnWALUpdate(LSNPair(lsn, ctx.fromReplication_ ? ctx.LSNs_.originLSN_ : lsn), name_, wrec); + } + if (!ctx.fromReplication_) { + setReplLSNs(LSNPair(lsn_t(), lsn)); + } } NamespaceImpl::IndexesCacheCleaner::~IndexesCacheCleaner() { - for (auto& idx : ns_.indexes_) idx->ClearCache(sorts_); + for (auto& idx : ns_.indexes_) { + idx->ClearCache(sorts_); + } } int64_t NamespaceImpl::correctMaxIterationsIdSetPreResult(int64_t maxIterationsIdSetPreResult) const { diff --git a/cpp_src/core/namespace/namespaceimpl.h b/cpp_src/core/namespace/namespaceimpl.h index 0a1e41a0a..8e0d22d80 100644 --- a/cpp_src/core/namespace/namespaceimpl.h +++ b/cpp_src/core/namespace/namespaceimpl.h @@ -62,17 +62,17 @@ struct DistanceBetweenJoinedIndexesSameNs; } // namespace SortExprFuncs struct NsContext { - NsContext(const RdxContext &rdxCtx) noexcept : rdxContext{rdxCtx} {} - NsContext &InTransaction() noexcept { + NsContext(const RdxContext& rdxCtx) noexcept : rdxContext{rdxCtx} {} + NsContext& InTransaction() noexcept { inTransaction = true; return *this; } - NsContext &CopiedNsRequest() noexcept { + NsContext& CopiedNsRequest() noexcept { isCopiedNsRequest = true; return *this; } - const RdxContext &rdxContext; + const RdxContext& rdxContext; bool isCopiedNsRequest{false}; bool inTransaction{false}; }; @@ -100,11 +100,11 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor class RollBack_updateItems; class IndexesCacheCleaner { public: - explicit IndexesCacheCleaner(NamespaceImpl &ns) noexcept : ns_{ns} {} - IndexesCacheCleaner(const IndexesCacheCleaner &) = delete; - IndexesCacheCleaner(IndexesCacheCleaner &&) = delete; - IndexesCacheCleaner &operator=(const IndexesCacheCleaner &) = delete; - IndexesCacheCleaner &operator=(IndexesCacheCleaner &&) = delete; + explicit IndexesCacheCleaner(NamespaceImpl& ns) noexcept : ns_{ns} {} + IndexesCacheCleaner(const IndexesCacheCleaner&) = delete; + IndexesCacheCleaner(IndexesCacheCleaner&&) = delete; + IndexesCacheCleaner& operator=(const IndexesCacheCleaner&) = delete; + IndexesCacheCleaner& operator=(IndexesCacheCleaner&&) = delete; void Add(SortType s) { if rx_unlikely (s >= sorts_.size()) { throw Error(errLogic, "Index sort type overflow: %d. Limit is %d", s, sorts_.size() - 1); @@ -116,7 +116,7 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor ~IndexesCacheCleaner(); private: - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; std::bitset sorts_; }; @@ -140,22 +140,23 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor class NSUpdateSortedContext final : public UpdateSortedContext { public: - NSUpdateSortedContext(const NamespaceImpl &ns, SortType curSortId) + NSUpdateSortedContext(const NamespaceImpl& ns, SortType curSortId) : ns_(ns), sorted_indexes_(ns_.getSortedIdxCount()), curSortId_(curSortId) { ids2Sorts_.reserve(ns.items_.size()); ids2SortsMemSize_ = ids2Sorts_.capacity() * sizeof(SortType); ns.nsUpdateSortedContextMemory_.fetch_add(ids2SortsMemSize_); - for (IdType i = 0; i < IdType(ns_.items_.size()); i++) + for (IdType i = 0; i < IdType(ns_.items_.size()); i++) { ids2Sorts_.push_back(ns_.items_[i].IsFree() ? SortIdUnexists : SortIdUnfilled); + } } ~NSUpdateSortedContext() override { ns_.nsUpdateSortedContextMemory_.fetch_sub(ids2SortsMemSize_); } int getSortedIdxCount() const noexcept override { return sorted_indexes_; } SortType getCurSortId() const noexcept override { return curSortId_; } - const std::vector &ids2Sorts() const noexcept override { return ids2Sorts_; } - std::vector &ids2Sorts() noexcept override { return ids2Sorts_; } + const std::vector& ids2Sorts() const noexcept override { return ids2Sorts_; } + std::vector& ids2Sorts() noexcept override { return ids2Sorts_; } private: - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; const int sorted_indexes_{0}; const IdType curSortId_{-1}; std::vector ids2Sorts_; @@ -166,26 +167,26 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor public: using Base = std::vector>; - explicit IndexesStorage(const NamespaceImpl &ns); + explicit IndexesStorage(const NamespaceImpl& ns); - IndexesStorage(const IndexesStorage &src) = delete; - IndexesStorage &operator=(const IndexesStorage &src) = delete; + IndexesStorage(const IndexesStorage& src) = delete; + IndexesStorage& operator=(const IndexesStorage& src) = delete; - IndexesStorage(IndexesStorage &&src) = delete; - IndexesStorage &operator=(IndexesStorage &&src) noexcept = delete; + IndexesStorage(IndexesStorage&& src) = delete; + IndexesStorage& operator=(IndexesStorage&& src) noexcept = delete; int denseIndexesSize() const { return ns_.payloadType_.NumFields(); } int sparseIndexesSize() const { return ns_.sparseIndexesCount_; } int compositeIndexesSize() const { return totalSize() - denseIndexesSize() - sparseIndexesSize(); } - void MoveBase(IndexesStorage &&src); + void MoveBase(IndexesStorage&& src); int firstSparsePos() const { return ns_.payloadType_.NumFields(); } int firstCompositePos() const { return ns_.payloadType_.NumFields() + ns_.sparseIndexesCount_; } - int firstCompositePos(const PayloadType &pt, int sparseIndexes) const { return pt.NumFields() + sparseIndexes; } + int firstCompositePos(const PayloadType& pt, int sparseIndexes) const { return pt.NumFields() + sparseIndexes; } int totalSize() const { return size(); } private: - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; }; class Items final : public std::vector { @@ -199,97 +200,97 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor using Ptr = intrusive_ptr; using Mutex = MarkedMutex; - NamespaceImpl(const std::string &_name, UpdatesObservers &observers); - NamespaceImpl &operator=(const NamespaceImpl &) = delete; + NamespaceImpl(const std::string& _name, UpdatesObservers& observers); + NamespaceImpl& operator=(const NamespaceImpl&) = delete; ~NamespaceImpl() override; - std::string GetName(const RdxContext &ctx) const { + std::string GetName(const RdxContext& ctx) const { auto rlck = rLock(ctx); return name_; } - bool IsSystem(const RdxContext &ctx) const { + bool IsSystem(const RdxContext& ctx) const { auto rlck = rLock(ctx); return isSystem(); } - bool IsTemporary(const RdxContext &ctx) const { return GetReplState(ctx).temporary; } + bool IsTemporary(const RdxContext& ctx) const { return GetReplState(ctx).temporary; } - void EnableStorage(const std::string &path, StorageOpts opts, StorageType storageType, const RdxContext &ctx); - void LoadFromStorage(unsigned threadsCount, const RdxContext &ctx); - void DeleteStorage(const RdxContext &); + void EnableStorage(const std::string& path, StorageOpts opts, StorageType storageType, const RdxContext& ctx); + void LoadFromStorage(unsigned threadsCount, const RdxContext& ctx); + void DeleteStorage(const RdxContext&); uint32_t GetItemsCount() const { return itemsCount_.load(std::memory_order_relaxed); } uint32_t GetItemsCapacity() const { return itemsCapacity_.load(std::memory_order_relaxed); } - void AddIndex(const IndexDef &indexDef, const RdxContext &ctx); - void UpdateIndex(const IndexDef &indexDef, const RdxContext &ctx); - void DropIndex(const IndexDef &indexDef, const RdxContext &ctx); - void SetSchema(std::string_view schema, const RdxContext &ctx); - std::string GetSchema(int format, const RdxContext &ctx); - - void Insert(Item &item, const RdxContext &ctx); - void Update(Item &item, const RdxContext &ctx); - void Upsert(Item &item, const RdxContext &); - void Delete(Item &item, const RdxContext &); - void ModifyItem(Item &item, ItemModifyMode mode, const RdxContext &ctx); - void Truncate(const RdxContext &); - void Refill(std::vector &, const RdxContext &); + void AddIndex(const IndexDef& indexDef, const RdxContext& ctx); + void UpdateIndex(const IndexDef& indexDef, const RdxContext& ctx); + void DropIndex(const IndexDef& indexDef, const RdxContext& ctx); + void SetSchema(std::string_view schema, const RdxContext& ctx); + std::string GetSchema(int format, const RdxContext& ctx); + + void Insert(Item& item, const RdxContext& ctx); + void Update(Item& item, const RdxContext& ctx); + void Upsert(Item& item, const RdxContext&); + void Delete(Item& item, const RdxContext&); + void ModifyItem(Item& item, ItemModifyMode mode, const RdxContext& ctx); + void Truncate(const RdxContext&); + void Refill(std::vector&, const RdxContext&); template - void Select(QueryResults &result, SelectCtxWithJoinPreSelect ¶ms, const RdxContext &); - NamespaceDef GetDefinition(const RdxContext &ctx); - NamespaceMemStat GetMemStat(const RdxContext &); - NamespacePerfStat GetPerfStat(const RdxContext &); - void ResetPerfStat(const RdxContext &); - std::vector EnumMeta(const RdxContext &ctx); - - void BackgroundRoutine(RdxActivityContext *); + void Select(QueryResults& result, SelectCtxWithJoinPreSelect& params, const RdxContext&); + NamespaceDef GetDefinition(const RdxContext& ctx); + NamespaceMemStat GetMemStat(const RdxContext&); + NamespacePerfStat GetPerfStat(const RdxContext&); + void ResetPerfStat(const RdxContext&); + std::vector EnumMeta(const RdxContext& ctx); + + void BackgroundRoutine(RdxActivityContext*); void StorageFlushingRoutine(); - void CloseStorage(const RdxContext &); + void CloseStorage(const RdxContext&); - Transaction NewTransaction(const RdxContext &ctx); - void CommitTransaction(Transaction &tx, QueryResults &result, NsContext ctx, - QueryStatCalculator &queryStatCalculator); + Transaction NewTransaction(const RdxContext& ctx); + void CommitTransaction(Transaction& tx, QueryResults& result, NsContext ctx, + QueryStatCalculator& queryStatCalculator); - Item NewItem(const RdxContext &ctx); - void ToPool(ItemImpl *item); + Item NewItem(const RdxContext& ctx); + void ToPool(ItemImpl* item); // Get metadata from storage by key - std::string GetMeta(const std::string &key, const RdxContext &ctx); + std::string GetMeta(const std::string& key, const RdxContext& ctx); // Put metadata to storage by key - void PutMeta(const std::string &key, std::string_view data, const RdxContext &ctx); + void PutMeta(const std::string& key, std::string_view data, const RdxContext& ctx); // Delete metadata from storage by key - void DeleteMeta(const std::string &key, const RdxContext &ctx); - int64_t GetSerial(const std::string &field); + void DeleteMeta(const std::string& key, const RdxContext& ctx); + int64_t GetSerial(const std::string& field); int getIndexByName(std::string_view index) const; int getIndexByNameOrJsonPath(std::string_view name) const; int getScalarIndexByName(std::string_view name) const; - bool tryGetIndexByName(std::string_view name, int &index) const; - bool getIndexByNameOrJsonPath(std::string_view name, int &index) const; - bool getScalarIndexByName(std::string_view name, int &index) const; - bool getSparseIndexByJsonPath(std::string_view jsonPath, int &index) const; + bool tryGetIndexByName(std::string_view name, int& index) const; + bool getIndexByNameOrJsonPath(std::string_view name, int& index) const; + bool getScalarIndexByName(std::string_view name, int& index) const; + bool getSparseIndexByJsonPath(std::string_view jsonPath, int& index) const; - void FillResult(QueryResults &result, const IdSet &ids) const; + void FillResult(QueryResults& result, const IdSet& ids) const; void EnablePerfCounters(bool enable = true) { enablePerfCounters_ = enable; } // Replication slave mode functions - ReplicationState GetReplState(const RdxContext &) const; - void SetReplLSNs(LSNPair LSNs, const RdxContext &ctx); + ReplicationState GetReplState(const RdxContext&) const; + void SetReplLSNs(LSNPair LSNs, const RdxContext& ctx); - void SetSlaveReplStatus(ReplicationState::Status, const Error &, const RdxContext &); - void SetSlaveReplMasterState(MasterState state, const RdxContext &); + void SetSlaveReplStatus(ReplicationState::Status, const Error&, const RdxContext&); + void SetSlaveReplMasterState(MasterState state, const RdxContext&); - Error ReplaceTagsMatcher(const TagsMatcher &tm, const RdxContext &); + Error ReplaceTagsMatcher(const TagsMatcher& tm, const RdxContext&); - void OnConfigUpdated(DBConfigProvider &configProvider, const RdxContext &ctx); - StorageOpts GetStorageOpts(const RdxContext &); - std::shared_ptr GetSchemaPtr(const RdxContext &ctx) const; + void OnConfigUpdated(DBConfigProvider& configProvider, const RdxContext& ctx); + StorageOpts GetStorageOpts(const RdxContext&); + std::shared_ptr GetSchemaPtr(const RdxContext& ctx) const; int getNsNumber() const noexcept { return schema_ ? schema_->GetProtobufNsNumber() : 0; } IndexesCacheCleaner GetIndexesCacheCleaner() { return IndexesCacheCleaner{*this}; } // Separate method for the v3/v4 replication compatibility. // It should not be used outside of this scenario - void MergeTagsMatcher(const TagsMatcher &tm, const RdxContext &ctx); + void MergeTagsMatcher(const TagsMatcher& tm, const RdxContext& ctx); void SetDestroyFlag() noexcept { dbDestroyed_ = true; } - Error FlushStorage(const RdxContext &ctx) { + Error FlushStorage(const RdxContext& ctx) { const auto flushOpts = StorageFlushOpts().WithImmediateReopen(); auto lck = rLock(ctx); storage_.Flush(flushOpts); @@ -309,8 +310,8 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor typedef contexted_shared_lock RLockT; typedef contexted_unique_lock WLockT; - RLockT RLock(const RdxContext &ctx) const { return RLockT(mtx_, ctx); } - WLockT WLock(const RdxContext &ctx) const { + RLockT RLock(const RdxContext& ctx) const { return RLockT(mtx_, ctx); } + WLockT WLock(const RdxContext& ctx) const { using namespace std::string_view_literals; WLockT lck(mtx_, ctx); if (readonly_.load(std::memory_order_acquire)) { @@ -318,9 +319,9 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor } return lck; } - bool IsNotLocked(const RdxContext &ctx) const { return WLockT(mtx_, std::try_to_lock_t{}, ctx).owns_lock(); } + bool IsNotLocked(const RdxContext& ctx) const { return WLockT(mtx_, std::try_to_lock_t{}, ctx).owns_lock(); } void MarkReadOnly() { readonly_.store(true, std::memory_order_release); } - std::atomic_bool &IsReadOnly() { return readonly_; } + std::atomic_bool& IsReadOnly() { return readonly_; } private: mutable Mutex mtx_; @@ -328,18 +329,18 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor }; struct PKModifyRevertData { - PKModifyRevertData(PayloadValue &p, lsn_t l) : pv(p), lsn(l) {} - PayloadValue &pv; + PKModifyRevertData(PayloadValue& p, lsn_t l) : pv(p), lsn(l) {} + PayloadValue& pv; lsn_t lsn; }; - Error rebuildIndexesTagsPaths(const TagsMatcher &newTm); + Error rebuildIndexesTagsPaths(const TagsMatcher& newTm); ReplicationState getReplState() const; std::string sysRecordName(std::string_view sysTag, uint64_t version); - void writeSysRecToStorage(std::string_view data, std::string_view sysTag, uint64_t &version, bool direct); + void writeSysRecToStorage(std::string_view data, std::string_view sysTag, uint64_t& version, bool direct); void saveIndexesToStorage(); void saveSchemaToStorage(); - Error loadLatestSysRecord(std::string_view baseSysTag, uint64_t &version, std::string &content); + Error loadLatestSysRecord(std::string_view baseSysTag, uint64_t& version, std::string& content); bool loadIndexesFromStorage(); void saveReplStateToStorage(bool direct = true); void saveTagsMatcherToStorage(bool clearUpdate); @@ -350,69 +351,69 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor void markUpdated(IndexOptimization requestedOptimization); void scheduleIndexOptimization(IndexOptimization requestedOptimization); - void doUpdate(const Query &query, QueryResults &result, const NsContext &); - void doDelete(const Query &query, QueryResults &result, const NsContext &); - void doTruncate(const NsContext &ctx); - void doUpsert(ItemImpl *ritem, IdType id, bool doUpdate); - void modifyItem(Item &item, ItemModifyMode mode, const NsContext &); - void doModifyItem(Item &item, ItemModifyMode mode, const NsContext &ctx); - void deleteItem(Item &item, const NsContext &ctx); - void updateTagsMatcherFromItem(ItemImpl *ritem); + void doUpdate(const Query& query, QueryResults& result, const NsContext&); + void doDelete(const Query& query, QueryResults& result, const NsContext&); + void doTruncate(const NsContext& ctx); + void doUpsert(ItemImpl* ritem, IdType id, bool doUpdate); + void modifyItem(Item& item, ItemModifyMode mode, const NsContext&); + void doModifyItem(Item& item, ItemModifyMode mode, const NsContext& ctx); + void deleteItem(Item& item, const NsContext& ctx); + void updateTagsMatcherFromItem(ItemImpl* ritem); template - [[nodiscard]] RollBack_updateItems updateItems(const PayloadType &oldPlType, int changedField); - void fillSparseIndex(Index &, std::string_view jsonPath); + [[nodiscard]] RollBack_updateItems updateItems(const PayloadType& oldPlType, int changedField); + void fillSparseIndex(Index&, std::string_view jsonPath); void doDelete(IdType id); - void optimizeIndexes(const NsContext &); - [[nodiscard]] RollBack_insertIndex insertIndex(std::unique_ptr newIndex, int idxNo, const std::string &realName); - bool addIndex(const IndexDef &indexDef); - void addCompositeIndex(const IndexDef &indexDef); + void optimizeIndexes(const NsContext&); + [[nodiscard]] RollBack_insertIndex insertIndex(std::unique_ptr newIndex, int idxNo, const std::string& realName); + bool addIndex(const IndexDef& indexDef); + void addCompositeIndex(const IndexDef& indexDef); template - void createCompositeFieldsSet(const std::string &idxName, const PathsT &paths, FieldsSet &fields); - void verifyCompositeIndex(const IndexDef &indexDef) const; + void createCompositeFieldsSet(const std::string& idxName, const PathsT& paths, FieldsSet& fields); + void verifyCompositeIndex(const IndexDef& indexDef) const; template - void verifyAddIndex(const IndexDef &indexDef, GetNameF &&) const; - void verifyUpdateIndex(const IndexDef &indexDef) const; - void verifyUpdateCompositeIndex(const IndexDef &indexDef) const; - bool updateIndex(const IndexDef &indexDef); - void dropIndex(const IndexDef &index); - void addToWAL(const IndexDef &indexDef, WALRecType type, const RdxContext &ctx); - void addToWAL(std::string_view json, WALRecType type, const RdxContext &ctx); - void replicateItem(IdType itemId, const NsContext &ctx, bool statementReplication, uint64_t oldPlHash, size_t oldItemCapacity, - std::optional &&modifyData); - void removeExpiredItems(RdxActivityContext *); - void removeExpiredStrings(RdxActivityContext *); - void mergeTagsMatcher(const TagsMatcher &tm, const NsContext &ctx); + void verifyAddIndex(const IndexDef& indexDef, GetNameF&&) const; + void verifyUpdateIndex(const IndexDef& indexDef) const; + void verifyUpdateCompositeIndex(const IndexDef& indexDef) const; + bool updateIndex(const IndexDef& indexDef); + void dropIndex(const IndexDef& index); + void addToWAL(const IndexDef& indexDef, WALRecType type, const RdxContext& ctx); + void addToWAL(std::string_view json, WALRecType type, const RdxContext& ctx); + void replicateItem(IdType itemId, const NsContext& ctx, bool statementReplication, uint64_t oldPlHash, size_t oldItemCapacity, + std::optional&& modifyData); + void removeExpiredItems(RdxActivityContext*); + void removeExpiredStrings(RdxActivityContext*); + void mergeTagsMatcher(const TagsMatcher& tm, const NsContext& ctx); Item newItem(); template [[nodiscard]] RollBack_recreateCompositeIndexes recreateCompositeIndexes(size_t startIdx, size_t endIdx); NamespaceDef getDefinition() const; - IndexDef getIndexDefinition(const std::string &indexName) const; + IndexDef getIndexDefinition(const std::string& indexName) const; IndexDef getIndexDefinition(size_t) const; - std::string getMeta(const std::string &key) const; - void putMeta(const std::string &key, std::string_view data, const RdxContext &ctx); - void deleteMeta(const std::string &key, const RdxContext &ctx); + std::string getMeta(const std::string& key) const; + void putMeta(const std::string& key, std::string_view data, const RdxContext& ctx); + void deleteMeta(const std::string& key, const RdxContext& ctx); - std::pair findByPK(ItemImpl *ritem, bool inTransaction, const RdxContext &); + std::pair findByPK(ItemImpl* ritem, bool inTransaction, const RdxContext&); - RX_ALWAYS_INLINE SelectKeyResult getPkDocs(const ConstPayload &cpl, bool inTransaction, const RdxContext &ctx); - RX_ALWAYS_INLINE VariantArray getPkKeys(const ConstPayload &cpl, Index *pkIndex, int fieldNum); - void checkUniquePK(const ConstPayload &cpl, bool inTransaction, const RdxContext &ctx); + RX_ALWAYS_INLINE SelectKeyResult getPkDocs(const ConstPayload& cpl, bool inTransaction, const RdxContext& ctx); + RX_ALWAYS_INLINE VariantArray getPkKeys(const ConstPayload& cpl, Index* pkIndex, int fieldNum); + void checkUniquePK(const ConstPayload& cpl, bool inTransaction, const RdxContext& ctx); int getSortedIdxCount() const noexcept; void updateSortedIdxCount(); - void setFieldsBasedOnPrecepts(ItemImpl *ritem); - - void putToJoinCache(JoinCacheRes &res, std::shared_ptr preResult) const; - void putToJoinCache(JoinCacheRes &res, JoinCacheVal &&val) const; - void getFromJoinCache(const Query &, const JoinedQuery &, JoinCacheRes &out) const; - void getFromJoinCache(const Query &, JoinCacheRes &out) const; - void getFromJoinCacheImpl(JoinCacheRes &out) const; - void getInsideFromJoinCache(JoinCacheRes &ctx) const; + void setFieldsBasedOnPrecepts(ItemImpl* ritem); + + void putToJoinCache(JoinCacheRes& res, std::shared_ptr preResult) const; + void putToJoinCache(JoinCacheRes& res, JoinCacheVal&& val) const; + void getFromJoinCache(const Query&, const JoinedQuery&, JoinCacheRes& out) const; + void getFromJoinCache(const Query&, JoinCacheRes& out) const; + void getFromJoinCacheImpl(JoinCacheRes& out) const; + void getInsideFromJoinCache(JoinCacheRes& ctx) const; int64_t lastUpdateTimeNano() const noexcept { return repl_.updatedUnixNano; } - const FieldsSet &pkFields(); + const FieldsSet& pkFields(); std::vector enumMeta() const; @@ -423,9 +424,9 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor } bool hadSelects() const noexcept { return lastSelectTime_.load(std::memory_order_relaxed) != 0; } void markReadOnly() { locker_.MarkReadOnly(); } - Locker::WLockT wLock(const RdxContext &ctx) const { return locker_.WLock(ctx); } - bool isNotLocked(const RdxContext &ctx) const { return locker_.IsNotLocked(ctx); } - Locker::RLockT rLock(const RdxContext &ctx) const { return locker_.RLock(ctx); } + Locker::WLockT wLock(const RdxContext& ctx) const { return locker_.WLock(ctx); } + bool isNotLocked(const RdxContext& ctx) const { return locker_.IsNotLocked(ctx); } + Locker::RLockT rLock(const RdxContext& ctx) const { return locker_.RLock(ctx); } bool SortOrdersBuilt() const noexcept { return optimizationState_.load(std::memory_order_acquire) == OptimizationCompleted; } @@ -460,33 +461,33 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor StringsHolderPtr strHolder() const noexcept { return strHolder_; } size_t itemsCount() const noexcept { return items_.size() - free_.size(); } - const NamespaceConfigData &config() const noexcept { return config_; } + const NamespaceConfigData& config() const noexcept { return config_; } - void DumpIndex(std::ostream &os, std::string_view index, const RdxContext &ctx) const; + void DumpIndex(std::ostream& os, std::string_view index, const RdxContext& ctx) const; - NamespaceImpl(const NamespaceImpl &src, AsyncStorage::FullLockT &storageLock); + NamespaceImpl(const NamespaceImpl& src, AsyncStorage::FullLockT& storageLock); bool isSystem() const { return isSystemNamespaceNameFast(name_); } IdType createItem(size_t realSize); void checkApplySlaveUpdate(bool v); - void processWalRecord(const WALRecord &wrec, const RdxContext &ctx, lsn_t itemLsn = lsn_t(), Item *item = nullptr); + void processWalRecord(const WALRecord& wrec, const RdxContext& ctx, lsn_t itemLsn = lsn_t(), Item* item = nullptr); void setReplLSNs(LSNPair LSNs); void setTemporary() { repl_.temporary = true; } - void setSlaveMode(const RdxContext &ctx); + void setSlaveMode(const RdxContext& ctx); - void removeIndex(std::unique_ptr &); - void dumpIndex(std::ostream &os, std::string_view index) const; - void tryForceFlush(Locker::WLockT &&wlck) { + void removeIndex(std::unique_ptr&); + void dumpIndex(std::ostream& os, std::string_view index) const; + void tryForceFlush(Locker::WLockT&& wlck) { if (wlck.owns_lock()) { wlck.unlock(); storage_.TryForceFlush(); } } - size_t getWalSize(const NamespaceConfigData &cfg) const noexcept { return isSystem() ? int64_t(1) : std::max(cfg.walSize, int64_t(1)); } + size_t getWalSize(const NamespaceConfigData& cfg) const noexcept { return isSystem() ? int64_t(1) : std::max(cfg.walSize, int64_t(1)); } void clearNamespaceCaches(); - std::vector pickJsonPath(const PayloadFieldType &fld); + std::vector pickJsonPath(const PayloadFieldType& fld); PerfStatCounterMT updatePerfCounter_, selectPerfCounter_; std::atomic_bool enablePerfCounters_{false}; @@ -497,7 +498,7 @@ class NamespaceImpl final : public intrusive_atomic_rc_base { // NOLINT(*perfor // Replication variables WALTracker wal_; ReplicationState repl_; - UpdatesObservers *observers_; + UpdatesObservers* observers_; StorageOpts storageOpts_; std::atomic_int64_t lastSelectTime_{0}; diff --git a/cpp_src/core/namespace/namespacestat.cc b/cpp_src/core/namespace/namespacestat.cc index 2b90620c1..de8a1d2a1 100644 --- a/cpp_src/core/namespace/namespacestat.cc +++ b/cpp_src/core/namespace/namespacestat.cc @@ -9,13 +9,15 @@ namespace reindexer { using namespace std::string_view_literals; -void NamespaceMemStat::GetJSON(WrSerializer &ser) { +void NamespaceMemStat::GetJSON(WrSerializer& ser) { JsonBuilder builder(ser); builder.Put("name", name); builder.Put("items_count", itemsCount); - if (emptyItemsCount) builder.Put("empty_items_count", emptyItemsCount); + if (emptyItemsCount) { + builder.Put("empty_items_count", emptyItemsCount); + } builder.Put("strings_waiting_to_be_deleted_size", stringsWaitingToBeDeletedSize); builder.Put("storage_ok", storageOK); @@ -47,31 +49,53 @@ void NamespaceMemStat::GetJSON(WrSerializer &ser) { } auto arr = builder.Array("indexes"); - for (auto &index : indexes) { + for (auto& index : indexes) { auto obj = arr.Object(); index.GetJSON(obj); } } -void LRUCacheMemStat::GetJSON(JsonBuilder &builder) { +void LRUCacheMemStat::GetJSON(JsonBuilder& builder) { builder.Put("total_size", totalSize); builder.Put("items_count", itemsCount); builder.Put("empty_count", emptyCount); builder.Put("hit_count_limit", hitCountLimit); } -void IndexMemStat::GetJSON(JsonBuilder &builder) { - if (uniqKeysCount) builder.Put("uniq_keys_count", uniqKeysCount); - if (trackedUpdatesCount) builder.Put("tracked_updates_count", trackedUpdatesCount); - if (trackedUpdatesBuckets) builder.Put("tracked_updates_buckets", trackedUpdatesBuckets); - if (trackedUpdatesSize) builder.Put("tracked_updates_size", trackedUpdatesSize); - if (trackedUpdatesOveflow) builder.Put("tracked_updates_overflow", trackedUpdatesOveflow); - if (dataSize) builder.Put("data_size", dataSize); - if (idsetBTreeSize) builder.Put("idset_btree_size", idsetBTreeSize); - if (idsetPlainSize) builder.Put("idset_plain_size", idsetPlainSize); - if (sortOrdersSize) builder.Put("sort_orders_size", sortOrdersSize); - if (fulltextSize) builder.Put("fulltext_size", fulltextSize); - if (columnSize) builder.Put("column_size", columnSize); +void IndexMemStat::GetJSON(JsonBuilder& builder) { + if (uniqKeysCount) { + builder.Put("uniq_keys_count", uniqKeysCount); + } + if (trackedUpdatesCount) { + builder.Put("tracked_updates_count", trackedUpdatesCount); + } + if (trackedUpdatesBuckets) { + builder.Put("tracked_updates_buckets", trackedUpdatesBuckets); + } + if (trackedUpdatesSize) { + builder.Put("tracked_updates_size", trackedUpdatesSize); + } + if (trackedUpdatesOveflow) { + builder.Put("tracked_updates_overflow", trackedUpdatesOveflow); + } + if (dataSize) { + builder.Put("data_size", dataSize); + } + if (idsetBTreeSize) { + builder.Put("idset_btree_size", idsetBTreeSize); + } + if (idsetPlainSize) { + builder.Put("idset_plain_size", idsetPlainSize); + } + if (sortOrdersSize) { + builder.Put("sort_orders_size", sortOrdersSize); + } + if (fulltextSize) { + builder.Put("fulltext_size", fulltextSize); + } + if (columnSize) { + builder.Put("column_size", columnSize); + } if (idsetCache.totalSize || idsetCache.itemsCount || idsetCache.emptyCount || idsetCache.hitCountLimit) { auto obj = builder.Object("idset_cache"); @@ -81,7 +105,7 @@ void IndexMemStat::GetJSON(JsonBuilder &builder) { builder.Put("name", name); } -void PerfStat::GetJSON(JsonBuilder &builder) { +void PerfStat::GetJSON(JsonBuilder& builder) { builder.Put("total_queries_count", totalHitCount); builder.Put("total_avg_latency_us", totalTimeUs); builder.Put("total_avg_lock_time_us", totalLockTimeUs); @@ -93,7 +117,7 @@ void PerfStat::GetJSON(JsonBuilder &builder) { builder.Put("max_latency_us", maxTimeUs); } -void NamespacePerfStat::GetJSON(WrSerializer &ser) { +void NamespacePerfStat::GetJSON(WrSerializer& ser) { JsonBuilder builder(ser); builder.Put("name", name); @@ -118,7 +142,7 @@ void NamespacePerfStat::GetJSON(WrSerializer &ser) { } } -void IndexPerfStat::GetJSON(JsonBuilder &builder) { +void IndexPerfStat::GetJSON(JsonBuilder& builder) { builder.Put("name", name); { auto obj = builder.Object("selects"); @@ -130,7 +154,7 @@ void IndexPerfStat::GetJSON(JsonBuilder &builder) { } } -void MasterState::GetJSON(JsonBuilder &builder) { +void MasterState::GetJSON(JsonBuilder& builder) { { auto lastUpstreamLSNmObj = builder.Object("last_upstream_lsn"); lastUpstreamLSNm.GetJSON(lastUpstreamLSNmObj); @@ -145,27 +169,28 @@ void MasterState::FromJSON(span json) { gason::JsonParser parser; auto root = parser.Parse(json); FromJSON(root); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { throw Error(errParseJson, "MasterState: %s", ex.what()); } } -void LoadLsn(lsn_t &to, const gason::JsonNode &node) { +void LoadLsn(lsn_t& to, const gason::JsonNode& node) { if (!node.empty()) { - if (node.value.getTag() == gason::JSON_OBJECT) + if (node.value.getTag() == gason::JSON_OBJECT) { to.FromJSON(node); - else + } else { to = lsn_t(node.As()); + } } } -void MasterState::FromJSON(const gason::JsonNode &root) { +void MasterState::FromJSON(const gason::JsonNode& root) { try { LoadLsn(lastUpstreamLSNm, root["last_upstream_lsn"]); dataHash = root["data_hash"].As(); dataCount = root["data_count"].As(); updatedUnixNano = root["updated_unix_nano"].As(); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { throw Error(errParseJson, "MasterState: %s", ex.what()); } } @@ -199,7 +224,7 @@ static ReplicationState::Status strToReplicationStatus(std::string_view status) return ReplicationState::Status::None; } -void ReplicationState::GetJSON(JsonBuilder &builder) { +void ReplicationState::GetJSON(JsonBuilder& builder) { builder.Put("last_lsn", int64_t(lastLsn)); { auto lastLsnObj = builder.Object("last_lsn_v2"); @@ -257,18 +282,18 @@ void ReplicationState::FromJSON(span json) { replError = Error(static_cast(errCode), root["error_message"].As()); try { masterState.FromJSON(root["master_state"]); - } catch (const Error &e) { + } catch (const Error& e) { logPrintf(LogError, "[repl] Can't load master state error %s", e.what()); - } catch (const gason::Exception &e) { + } catch (const gason::Exception& e) { logPrintf(LogError, "[repl] Can't load master state gasson error %s", e.what()); } } - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { throw Error(errParseJson, "ReplicationState: %s", ex.what()); } } -void ReplicationStat::GetJSON(JsonBuilder &builder) { +void ReplicationStat::GetJSON(JsonBuilder& builder) { ReplicationState::GetJSON(builder); if (!slaveMode) { builder.Put("wal_count", walCount); @@ -276,7 +301,7 @@ void ReplicationStat::GetJSON(JsonBuilder &builder) { } } -void TxPerfStat::GetJSON(JsonBuilder &builder) { +void TxPerfStat::GetJSON(JsonBuilder& builder) { builder.Put("total_count", totalCount); builder.Put("total_copy_count", totalCopyCount); builder.Put("avg_steps_count", avgStepsCount); diff --git a/cpp_src/core/namespace/namespacestat.h b/cpp_src/core/namespace/namespacestat.h index 9fe6ca7bb..2f3e861e8 100644 --- a/cpp_src/core/namespace/namespacestat.h +++ b/cpp_src/core/namespace/namespacestat.h @@ -16,7 +16,7 @@ class WrSerializer; class JsonBuilder; struct LRUCacheMemStat { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); size_t totalSize = 0; size_t itemsCount = 0; @@ -25,7 +25,7 @@ struct LRUCacheMemStat { }; struct IndexMemStat { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); std::string name; size_t uniqKeysCount = 0; size_t dataSize = 0; @@ -45,9 +45,9 @@ struct IndexMemStat { }; struct MasterState { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); void FromJSON(span); - void FromJSON(const gason::JsonNode &root); + void FromJSON(const gason::JsonNode& root); // LSN of last change lsn_t lastUpstreamLSNm; @@ -62,7 +62,7 @@ struct MasterState { struct ReplicationState { enum class Status { None, Idle, Error, Fatal, Syncing }; - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); void FromJSON(span); // LSN of last change @@ -95,13 +95,13 @@ struct ReplicationState { }; struct ReplicationStat : public ReplicationState { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); size_t walCount = 0; size_t walSize = 0; }; struct NamespaceMemStat { - void GetJSON(WrSerializer &ser); + void GetJSON(WrSerializer& ser); std::string name; std::string storagePath; @@ -126,7 +126,7 @@ struct NamespaceMemStat { }; struct PerfStat { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); size_t totalHitCount; size_t totalTimeUs; @@ -140,7 +140,7 @@ struct PerfStat { }; struct TxPerfStat { - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); size_t totalCount; size_t totalCopyCount; @@ -160,9 +160,9 @@ struct TxPerfStat { struct IndexPerfStat { IndexPerfStat() = default; - IndexPerfStat(const std::string &n, const PerfStat &s, const PerfStat &c) : name(n), selects(s), commits(c) {} + IndexPerfStat(const std::string& n, const PerfStat& s, const PerfStat& c) : name(n), selects(s), commits(c) {} - void GetJSON(JsonBuilder &builder); + void GetJSON(JsonBuilder& builder); std::string name; PerfStat selects; @@ -170,7 +170,7 @@ struct IndexPerfStat { }; struct NamespacePerfStat { - void GetJSON(WrSerializer &ser); + void GetJSON(WrSerializer& ser); std::string name; PerfStat updates; diff --git a/cpp_src/core/namespacedef.cc b/cpp_src/core/namespacedef.cc index 0ccd79ea0..e06939579 100644 --- a/cpp_src/core/namespacedef.cc +++ b/cpp_src/core/namespacedef.cc @@ -9,21 +9,21 @@ namespace reindexer { Error NamespaceDef::FromJSON(span json) { try { FromJSON(gason::JsonParser().Parse(json)); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "NamespaceDef: %s", ex.what()); - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; } -void NamespaceDef::FromJSON(const gason::JsonNode &root) { +void NamespaceDef::FromJSON(const gason::JsonNode& root) { name = root["name"].As(); storage.Enabled(root["storage"]["enabled"].As(true)); storage.DropOnFileFormatError(root["storage"]["drop_on_file_format_error"].As()); storage.CreateIfMissing(root["storage"]["create_if_missing"].As(true)); - for (auto &arrelem : root["indexes"]) { + for (auto& arrelem : root["indexes"]) { IndexDef idx; idx.FromJSON(arrelem); indexes.push_back(idx); @@ -32,13 +32,13 @@ void NamespaceDef::FromJSON(const gason::JsonNode &root) { schemaJson = root["schema"].As(schemaJson); } -void NamespaceDef::GetJSON(WrSerializer &ser, int formatFlags) const { +void NamespaceDef::GetJSON(WrSerializer& ser, int formatFlags) const { JsonBuilder json(ser); json.Put("name", name); json.Object("storage").Put("enabled", storage.IsEnabled()); { auto arr = json.Array("indexes"); - for (auto &idx : indexes) { + for (auto& idx : indexes) { arr.Raw(nullptr, ""); idx.GetJSON(ser, formatFlags); } diff --git a/cpp_src/core/namespacedef.h b/cpp_src/core/namespacedef.h index db65c1549..05f12ecd5 100644 --- a/cpp_src/core/namespacedef.h +++ b/cpp_src/core/namespacedef.h @@ -14,29 +14,29 @@ class WrSerializer; struct NamespaceDef { NamespaceDef() = default; - NamespaceDef(const std::string &iname, StorageOpts istorage = StorageOpts().Enabled().CreateIfMissing()) + NamespaceDef(const std::string& iname, StorageOpts istorage = StorageOpts().Enabled().CreateIfMissing()) : name(iname), storage(istorage) {} - NamespaceDef &AddIndex(const std::string &iname, const std::string &indexType, const std::string &fieldType, + NamespaceDef& AddIndex(const std::string& iname, const std::string& indexType, const std::string& fieldType, IndexOpts opts = IndexOpts()) { indexes.emplace_back(iname, JsonPaths{iname}, indexType, fieldType, std::move(opts)); return *this; } - NamespaceDef &AddIndex(const std::string &iname, const JsonPaths &jsonPaths, const std::string &indexType, const std::string &fieldType, + NamespaceDef& AddIndex(const std::string& iname, const JsonPaths& jsonPaths, const std::string& indexType, const std::string& fieldType, IndexOpts opts = IndexOpts()) { indexes.emplace_back(iname, jsonPaths, indexType, fieldType, std::move(opts)); return *this; } - NamespaceDef &AddIndex(const IndexDef &idxDef) { + NamespaceDef& AddIndex(const IndexDef& idxDef) { indexes.emplace_back(idxDef); return *this; } Error FromJSON(span json); - void FromJSON(const gason::JsonNode &root); - void GetJSON(WrSerializer &, int formatFlags = 0) const; + void FromJSON(const gason::JsonNode& root); + void GetJSON(WrSerializer&, int formatFlags = 0) const; public: std::string name; @@ -63,24 +63,24 @@ struct EnumNamespacesOpts { } // Add not openened namespaces to enumeration - EnumNamespacesOpts &WithClosed(bool value = true) { + EnumNamespacesOpts& WithClosed(bool value = true) { options_ = value ? options_ | kEnumNamespacesWithClosed : options_ & ~(kEnumNamespacesWithClosed); return *this; } // Return only namespaces names (faster, and do not try rlock nses) - EnumNamespacesOpts &OnlyNames(bool value = true) { + EnumNamespacesOpts& OnlyNames(bool value = true) { options_ = value ? options_ | kEnumNamespacesOnlyNames : options_ & ~(kEnumNamespacesOnlyNames); return *this; } // Hide system namespaces from enumeration - EnumNamespacesOpts &HideSystem(bool value = true) { + EnumNamespacesOpts& HideSystem(bool value = true) { options_ = value ? options_ | kEnumNamespacesHideSystem : options_ & ~(kEnumNamespacesHideSystem); return *this; } // Add name filter - EnumNamespacesOpts &WithFilter(std::string_view flt) { + EnumNamespacesOpts& WithFilter(std::string_view flt) { filter_ = flt; return *this; } diff --git a/cpp_src/core/nsselecter/aggregator.cc b/cpp_src/core/nsselecter/aggregator.cc index a336862b9..3a02a6d4c 100644 --- a/cpp_src/core/nsselecter/aggregator.cc +++ b/cpp_src/core/nsselecter/aggregator.cc @@ -19,7 +19,7 @@ namespace { namespace reindexer { template -static void moveFrames(It &begin, It &end, size_t size, size_t offset, size_t limit) { +static void moveFrames(It& begin, It& end, size_t size, size_t offset, size_t limit) { if (offset > QueryEntry::kDefaultOffset) { std::advance(begin, offset); } @@ -30,7 +30,7 @@ static void moveFrames(It &begin, It &end, size_t size, size_t offset, size_t li } template -static void copy(It begin, It end, std::vector &facets, const FieldsSet &fields, const PayloadType &payloadType) { +static void copy(It begin, It end, std::vector& facets, const FieldsSet& fields, const PayloadType& payloadType) { for (; begin != end; ++begin) { facets.push_back({{}, begin->second}); int tagPathIdx = 0; @@ -39,10 +39,10 @@ static void copy(It begin, It end, std::vector &facets, const Field VariantArray va; if (fields[i] == IndexValueType::SetByJsonPath) { if (fields.isTagsPathIndexed(tagPathIdx)) { - const IndexedTagsPath &tagsPath = fields.getIndexedTagsPath(tagPathIdx++); + const IndexedTagsPath& tagsPath = fields.getIndexedTagsPath(tagPathIdx++); pl.GetByJsonPath(tagsPath, va, KeyValueType::Undefined{}); } else { - const TagsPath &tagsPath = fields.getTagsPath(tagPathIdx++); + const TagsPath& tagsPath = fields.getTagsPath(tagPathIdx++); pl.GetByJsonPath(tagsPath, va, KeyValueType::Undefined{}); } if (va.IsObjectValue()) { @@ -57,7 +57,7 @@ static void copy(It begin, It end, std::vector &facets, const Field } template -static void copy(It begin, It end, std::vector &facets) { +static void copy(It begin, It end, std::vector& facets) { for (; begin != end; ++begin) { facets.push_back({{begin->first.template As()}, begin->second}); } @@ -65,15 +65,15 @@ static void copy(It begin, It end, std::vector &facets) { class Aggregator::MultifieldComparator { public: - MultifieldComparator(const h_vector &, const FieldsSet &, const PayloadType &); + MultifieldComparator(const h_vector&, const FieldsSet&, const PayloadType&); bool HaveCompareByCount() const { return haveCompareByCount; } - bool operator()(const PayloadValue &lhs, const PayloadValue &rhs) const; - bool operator()(const std::pair &lhs, const std::pair &rhs) const; + bool operator()(const PayloadValue& lhs, const PayloadValue& rhs) const; + bool operator()(const std::pair& lhs, const std::pair& rhs) const; private: struct CompOpts { CompOpts() : direction{Asc} {} - CompOpts(const FieldsSet &fs, Direction d) : fields{fs}, direction{d} {} + CompOpts(const FieldsSet& fs, Direction d) : fields{fs}, direction{d} {} FieldsSet fields; // if empty - compare by count Direction direction = Asc; }; @@ -81,19 +81,19 @@ class Aggregator::MultifieldComparator { PayloadType type_; bool haveCompareByCount = false; - void insertField(size_t toIdx, const FieldsSet &from, size_t fromIdx, int &tagsPathIdx); + void insertField(size_t toIdx, const FieldsSet& from, size_t fromIdx, int& tagsPathIdx); }; class Aggregator::SinglefieldComparator { enum CompareBy { ByValue, ByCount }; public: - SinglefieldComparator(const h_vector &); + SinglefieldComparator(const h_vector&); bool HaveCompareByCount() const { return haveCompareByCount; } - bool operator()(const Variant &lhs, const Variant &rhs) const { + bool operator()(const Variant& lhs, const Variant& rhs) const { return toSigned(lhs.Compare(rhs)) * valueCompareDirection_ < 0; } - bool operator()(const std::pair &lhs, const std::pair &rhs) const; + bool operator()(const std::pair& lhs, const std::pair& rhs) const; private: struct CompOpts { @@ -107,8 +107,8 @@ class Aggregator::SinglefieldComparator { bool haveCompareByCount = false; }; -Aggregator::MultifieldComparator::MultifieldComparator(const h_vector &sortingEntries, const FieldsSet &fields, - const PayloadType &type) +Aggregator::MultifieldComparator::MultifieldComparator(const h_vector& sortingEntries, const FieldsSet& fields, + const PayloadType& type) : compOpts_{}, type_{type}, haveCompareByCount{false} { assertrx_throw(type_); if (sortingEntries.empty()) { @@ -135,7 +135,7 @@ Aggregator::MultifieldComparator::MultifieldComparator(const h_vector(rhs, opt.fields); - if (less == ComparationResult::Eq) continue; + if (less == ComparationResult::Eq) { + continue; + } return toSigned(less) * opt.direction < 0; } return false; } -bool Aggregator::MultifieldComparator::operator()(const std::pair &lhs, const std::pair &rhs) const { +bool Aggregator::MultifieldComparator::operator()(const std::pair& lhs, const std::pair& rhs) const { assertrx_throw(!lhs.first.IsFree()); assertrx_throw(!rhs.first.IsFree()); - for (const auto &opt : compOpts_) { + for (const auto& opt : compOpts_) { if (opt.fields.empty()) { - if (lhs.second == rhs.second) continue; + if (lhs.second == rhs.second) { + continue; + } return opt.direction * (lhs.second - rhs.second) < 0; } const auto less = ConstPayload(type_, lhs.first).Compare(rhs.first, opt.fields); - if (less == ComparationResult::Eq) continue; + if (less == ComparationResult::Eq) { + continue; + } return toSigned(less) * opt.direction < 0; } return false; } -void Aggregator::MultifieldComparator::insertField(size_t toIdx, const FieldsSet &from, size_t fromIdx, int &tagsPathIdx) { +void Aggregator::MultifieldComparator::insertField(size_t toIdx, const FieldsSet& from, size_t fromIdx, int& tagsPathIdx) { compOpts_[toIdx].fields.push_back(from[fromIdx]); if (from[fromIdx] == IndexValueType::SetByJsonPath) { compOpts_[toIdx].fields.push_back(from.getTagsPath(tagsPathIdx++)); @@ -183,10 +191,10 @@ struct Aggregator::MultifieldOrderedMap : public btree::btree_map &sortingEntries) +Aggregator::SinglefieldComparator::SinglefieldComparator(const h_vector& sortingEntries) : valueCompareDirection_(Asc), haveCompareByCount(false) { bool haveCompareByValue = false; - for (const SortingEntry &sortEntry : sortingEntries) { + for (const SortingEntry& sortEntry : sortingEntries) { CompareBy compareBy = ByValue; Direction direc = sortEntry.desc ? Desc : Asc; if (sortEntry.field == SortingEntry::Count) { @@ -203,24 +211,26 @@ Aggregator::SinglefieldComparator::SinglefieldComparator(const h_vector &lhs, const std::pair &rhs) const { - for (const CompOpts &opt : compOpts_) { +bool Aggregator::SinglefieldComparator::operator()(const std::pair& lhs, const std::pair& rhs) const { + for (const CompOpts& opt : compOpts_) { int less; if (opt.compareBy == ByValue) { less = toSigned(lhs.first.Compare(rhs.first)); } else { less = lhs.second - rhs.second; } - if (less != 0) return less * opt.direction < 0; + if (less != 0) { + return less * opt.direction < 0; + } } return false; } -Aggregator::Aggregator(Aggregator &&) noexcept = default; +Aggregator::Aggregator(Aggregator&&) noexcept = default; Aggregator::~Aggregator() = default; -Aggregator::Aggregator(const PayloadType &payloadType, const FieldsSet &fields, AggType aggType, const h_vector &names, - const h_vector &sort, size_t limit, size_t offset, bool compositeIndexFields) +Aggregator::Aggregator(const PayloadType& payloadType, const FieldsSet& fields, AggType aggType, const h_vector& names, + const h_vector& sort, size_t limit, size_t offset, bool compositeIndexFields) : payloadType_(payloadType), fields_(fields), aggType_(aggType), @@ -261,11 +271,13 @@ Aggregator::Aggregator(const PayloadType &payloadType, const FieldsSet &fields, } template -static void fillOrderedFacetResult(std::vector &result, const FacetMap &facets, size_t offset, size_t limit, - const Args &...args) { - if (offset >= static_cast(facets.size())) return; +static void fillOrderedFacetResult(std::vector& result, const FacetMap& facets, size_t offset, size_t limit, + const Args&... args) { + if (offset >= static_cast(facets.size())) { + return; + } result.reserve(std::min(limit, facets.size() - offset)); - const auto &comparator = facets.key_comp(); + const auto& comparator = facets.key_comp(); if (comparator.HaveCompareByCount()) { std::vector> tmpFacets(facets.begin(), facets.end()); auto begin = tmpFacets.begin(); @@ -283,9 +295,11 @@ static void fillOrderedFacetResult(std::vector &result, const Facet } template -static void fillUnorderedFacetResult(std::vector &result, const FacetMap &facets, size_t offset, size_t limit, - const Args &...args) { - if (offset >= static_cast(facets.size())) return; +static void fillUnorderedFacetResult(std::vector& result, const FacetMap& facets, size_t offset, size_t limit, + const Args&... args) { + if (offset >= static_cast(facets.size())) { + return; + } result.reserve(std::min(limit, facets.size() - offset)); auto begin = facets.begin(); auto end = facets.end(); @@ -300,20 +314,24 @@ AggregationResult Aggregator::GetResult() const { switch (aggType_) { case AggAvg: - if (result_) ret.SetValue(double(hitCount_ == 0 ? 0 : (*result_ / hitCount_))); + if (result_) { + ret.SetValue(double(hitCount_ == 0 ? 0 : (*result_ / hitCount_))); + } break; case AggSum: case AggMin: case AggMax: - if (result_) ret.SetValue(*result_); + if (result_) { + ret.SetValue(*result_); + } break; case AggFacet: - std::visit(overloaded{[&](const SinglefieldOrderedMap &fm) { fillOrderedFacetResult(ret.facets, fm, offset_, limit_); }, - [&](const SinglefieldUnorderedMap &fm) { fillUnorderedFacetResult(ret.facets, fm, offset_, limit_); }, - [&](const MultifieldOrderedMap &fm) { + std::visit(overloaded{[&](const SinglefieldOrderedMap& fm) { fillOrderedFacetResult(ret.facets, fm, offset_, limit_); }, + [&](const SinglefieldUnorderedMap& fm) { fillUnorderedFacetResult(ret.facets, fm, offset_, limit_); }, + [&](const MultifieldOrderedMap& fm) { fillOrderedFacetResult(ret.facets, fm, offset_, limit_, fields_, payloadType_); }, - [&](const MultifieldUnorderedMap &fm) { + [&](const MultifieldUnorderedMap& fm) { fillUnorderedFacetResult(ret.facets, fm, offset_, limit_, fields_, payloadType_); }}, *facets_); @@ -323,7 +341,7 @@ AggregationResult Aggregator::GetResult() const { ret.payloadType = payloadType_; ret.distinctsFields = fields_; ret.distincts.reserve(distincts_->size()); - for (const Variant &value : *distincts_) { + for (const Variant& value : *distincts_) { ret.distincts.push_back(value); } break; @@ -335,20 +353,22 @@ AggregationResult Aggregator::GetResult() const { return ret; } -void Aggregator::Aggregate(const PayloadValue &data) { +void Aggregator::Aggregate(const PayloadValue& data) { if (aggType_ == AggFacet) { const bool done = - std::visit(overloaded{[&data](MultifieldUnorderedMap &fm) { + std::visit(overloaded{[&data](MultifieldUnorderedMap& fm) { ++fm[data]; return true; }, - [&data](MultifieldOrderedMap &fm) { + [&data](MultifieldOrderedMap& fm) { ++fm[data]; return true; }, - [](SinglefieldOrderedMap &) { return false; }, [](SinglefieldUnorderedMap &) { return false; }}, + [](SinglefieldOrderedMap&) { return false; }, [](SinglefieldUnorderedMap&) { return false; }}, *facets_); - if (done) return; + if (done) { + return; + } } if (aggType_ == AggDistinct && compositeIndexFields_) { aggregate(Variant(data)); @@ -359,28 +379,30 @@ void Aggregator::Aggregate(const PayloadValue &data) { if (fields_[0] == IndexValueType::SetByJsonPath) { ConstPayload pl(payloadType_, data); VariantArray va; - const TagsPath &tagsPath = fields_.getTagsPath(0); + const TagsPath& tagsPath = fields_.getTagsPath(0); pl.GetByJsonPath(tagsPath, va, KeyValueType::Undefined{}); if (va.IsObjectValue()) { throw Error(errQueryExec, "Cannot aggregate object field"); } - for (const Variant &v : va) aggregate(v); + for (const Variant& v : va) { + aggregate(v); + } return; } - const auto &fieldType = payloadType_.Field(fields_[0]); + const auto& fieldType = payloadType_.Field(fields_[0]); if (!fieldType.IsArray()) { aggregate(PayloadFieldValue(fieldType, data.Ptr() + fieldType.Offset()).Get()); } else { - PayloadFieldValue::Array *arr = reinterpret_cast(data.Ptr() + fieldType.Offset()); - uint8_t *ptr = data.Ptr() + arr->offset; + PayloadFieldValue::Array* arr = reinterpret_cast(data.Ptr() + fieldType.Offset()); + uint8_t* ptr = data.Ptr() + arr->offset; for (int i = 0; i < arr->len; i++, ptr += fieldType.ElemSizeof()) { aggregate(PayloadFieldValue(fieldType, ptr).Get()); } } } -void Aggregator::aggregate(const Variant &v) { +void Aggregator::aggregate(const Variant& v) { switch (aggType_) { case AggSum: case AggAvg: @@ -394,8 +416,8 @@ void Aggregator::aggregate(const Variant &v) { result_ = result_ ? std::max(v.As(), *result_) : v.As(); break; case AggFacet: - std::visit(overloaded{[&v](SinglefieldUnorderedMap &fm) { ++fm[v]; }, [&v](SinglefieldOrderedMap &fm) { ++fm[v]; }, - [](MultifieldUnorderedMap &) { throw_as_assert; }, [](MultifieldOrderedMap &) { throw_as_assert; }}, + std::visit(overloaded{[&v](SinglefieldUnorderedMap& fm) { ++fm[v]; }, [&v](SinglefieldOrderedMap& fm) { ++fm[v]; }, + [](MultifieldUnorderedMap&) { throw_as_assert; }, [](MultifieldOrderedMap&) { throw_as_assert; }}, *facets_); break; case AggDistinct: diff --git a/cpp_src/core/nsselecter/aggregator.h b/cpp_src/core/nsselecter/aggregator.h index 24e1d6ce3..f4df61b4a 100644 --- a/cpp_src/core/nsselecter/aggregator.h +++ b/cpp_src/core/nsselecter/aggregator.h @@ -19,21 +19,21 @@ class Aggregator { enum { Count = -1 }; }; - Aggregator(const PayloadType &, const FieldsSet &, AggType aggType, const h_vector &names, - const h_vector &sort = {}, size_t limit = QueryEntry::kDefaultLimit, + Aggregator(const PayloadType&, const FieldsSet&, AggType aggType, const h_vector& names, + const h_vector& sort = {}, size_t limit = QueryEntry::kDefaultLimit, size_t offset = QueryEntry::kDefaultOffset, bool compositeIndexFields = false); - Aggregator(Aggregator &&) noexcept; + Aggregator(Aggregator&&) noexcept; ~Aggregator(); - void Aggregate(const PayloadValue &lhs); + void Aggregate(const PayloadValue& lhs); AggregationResult GetResult() const; - Aggregator(const Aggregator &) = delete; - Aggregator &operator=(const Aggregator &) = delete; - Aggregator &operator=(Aggregator &&) = delete; + Aggregator(const Aggregator&) = delete; + Aggregator& operator=(const Aggregator&) = delete; + Aggregator& operator=(Aggregator&&) = delete; AggType Type() const noexcept { return aggType_; } - const h_vector &Names() const noexcept { return names_; } + const h_vector& Names() const noexcept { return names_; } bool DistinctChanged() noexcept { return distinctChecker_(); } @@ -47,7 +47,7 @@ class Aggregator { using SinglefieldUnorderedMap = fast_hash_map; using Facets = std::variant; - void aggregate(const Variant &variant); + void aggregate(const Variant& variant); PayloadType payloadType_; FieldsSet fields_; @@ -62,14 +62,16 @@ class Aggregator { class RelaxVariantCompare { public: - RelaxVariantCompare(const PayloadType &type, const FieldsSet &fields) : type_(type), fields_(fields) {} - bool operator()(const Variant &v1, const Variant &v2) const { - if (!v1.Type().IsSame(v2.Type())) return false; + RelaxVariantCompare(const PayloadType& type, const FieldsSet& fields) : type_(type), fields_(fields) {} + bool operator()(const Variant& v1, const Variant& v2) const { + if (!v1.Type().IsSame(v2.Type())) { + return false; + } return v1.Type().EvaluateOneOf( [&](OneOf) { return v1.Compare(v2) == ComparationResult::Eq; }, [&](KeyValueType::Composite) { - return ConstPayload(type_, static_cast(v1)).IsEQ(static_cast(v2), fields_); + return ConstPayload(type_, static_cast(v1)).IsEQ(static_cast(v2), fields_); }, [](OneOf) -> bool { throw_as_assert; }); } @@ -79,12 +81,12 @@ class Aggregator { FieldsSet fields_; }; struct DistinctHasher { - DistinctHasher(const PayloadType &type, const FieldsSet &fields) : type_(type), fields_(fields) {} - size_t operator()(const Variant &v) const { + DistinctHasher(const PayloadType& type, const FieldsSet& fields) : type_(type), fields_(fields) {} + size_t operator()(const Variant& v) const { return v.Type().EvaluateOneOf( [&](OneOf) noexcept { return v.Hash(); }, - [&](KeyValueType::Composite) { return ConstPayload(type_, static_cast(v)).GetHash(fields_); }, + [&](KeyValueType::Composite) { return ConstPayload(type_, static_cast(v)).GetHash(fields_); }, [](OneOf) -> size_t { throw_as_assert; }); } @@ -95,7 +97,7 @@ class Aggregator { class DistinctChangeChecker { public: - DistinctChangeChecker(const Aggregator &aggregator) noexcept : aggregator_(aggregator) {} + DistinctChangeChecker(const Aggregator& aggregator) noexcept : aggregator_(aggregator) {} [[nodiscard]] bool operator()() noexcept { assertrx_dbg(aggregator_.Type() == AggType::AggDistinct); assertrx_dbg(aggregator_.distincts_); @@ -105,7 +107,7 @@ class Aggregator { } private: - const Aggregator &aggregator_; + const Aggregator& aggregator_; size_t lastCheckSize_ = 0; } distinctChecker_; diff --git a/cpp_src/core/nsselecter/btreeindexiterator.h b/cpp_src/core/nsselecter/btreeindexiterator.h index c31574eb7..6365f922a 100644 --- a/cpp_src/core/nsselecter/btreeindexiterator.h +++ b/cpp_src/core/nsselecter/btreeindexiterator.h @@ -21,7 +21,9 @@ class BtreeIndexIterator final : public IndexIterator { } else { impl_ = std::make_shared>(idxMap_, first_, last_); } - if (impl_->getSize() == 0) return; + if (impl_->getSize() == 0) { + return; + } impl_->shiftToBegin(); impl_->shiftIdsetToBegin(); } @@ -51,7 +53,9 @@ class BtreeIndexIterator final : public IndexIterator { return impl_->getValue(); } size_t GetMaxIterations(size_t limitIters) noexcept final { - if (cachedIters_ != std::numeric_limits::max()) return cachedIters_; + if (cachedIters_ != std::numeric_limits::max()) { + return cachedIters_; + } return BtreeIndexForwardIteratorImpl(idxMap_, first_, last_).getMaxIterations(limitIters); } void SetMaxIterations(size_t iters) noexcept final { cachedIters_ = iters; } diff --git a/cpp_src/core/nsselecter/btreeindexiteratorimpl.h b/cpp_src/core/nsselecter/btreeindexiteratorimpl.h index 26c2696c1..c1e340911 100644 --- a/cpp_src/core/nsselecter/btreeindexiteratorimpl.h +++ b/cpp_src/core/nsselecter/btreeindexiteratorimpl.h @@ -20,11 +20,15 @@ class BtreeIndexIteratorImpl { virtual void next() noexcept = 0; bool shiftToNextIdset() noexcept { - if (isOver()) return false; + if (isOver()) { + return false; + } for (next(); !isOver() && getCurrentIdsetSize() == 0;) { next(); } - if (isOver()) return false; + if (isOver()) { + return false; + } shiftIdsetToBegin(); updateCurrentValue(); return true; diff --git a/cpp_src/core/nsselecter/comparator/comparator_indexed.cc b/cpp_src/core/nsselecter/comparator/comparator_indexed.cc index 6a7c87f0a..d6b6ace4d 100644 --- a/cpp_src/core/nsselecter/comparator/comparator_indexed.cc +++ b/cpp_src/core/nsselecter/comparator/comparator_indexed.cc @@ -1,5 +1,7 @@ #include "comparator_indexed.h" #include +#include "core/formatters/key_string_fmt.h" +#include "core/formatters/uuid_fmt.h" #include "core/nsselecter/comparator/helpers.h" namespace { diff --git a/cpp_src/core/nsselecter/comparator/comparator_indexed.h b/cpp_src/core/nsselecter/comparator/comparator_indexed.h index 86979e73c..6f3e4e5b4 100644 --- a/cpp_src/core/nsselecter/comparator/comparator_indexed.h +++ b/cpp_src/core/nsselecter/comparator/comparator_indexed.h @@ -485,33 +485,49 @@ class ComparatorIndexedOffsetArray : private DataHolder { for (const auto* const end = ptr + arr.len; ptr != end; ++ptr) { switch (this->cond_) { case CondEq: - if (*ptr == this->value_) return true; + if (*ptr == this->value_) { + return true; + } continue; case CondLt: - if (*ptr < this->value_) return true; + if (*ptr < this->value_) { + return true; + } continue; case CondLe: - if (*ptr <= this->value_) return true; + if (*ptr <= this->value_) { + return true; + } continue; case CondGt: - if (*ptr > this->value_) return true; + if (*ptr > this->value_) { + return true; + } continue; case CondGe: - if (*ptr >= this->value_) return true; + if (*ptr >= this->value_) { + return true; + } continue; case CondRange: - if (this->range_.first <= *ptr && *ptr <= this->range_.second) return true; + if (this->range_.first <= *ptr && *ptr <= this->range_.second) { + return true; + } continue; case CondSet: assertrx_dbg(this->setPtr_); - if (this->setPtr_->find(*ptr) != this->setPtr_->cend()) return true; + if (this->setPtr_->find(*ptr) != this->setPtr_->cend()) { + return true; + } continue; case CondAllSet: { assertrx_dbg(this->allSetPtr_); const auto it = this->allSetPtr_->values_.find(*ptr); if (it != this->allSetPtr_->values_.cend()) { this->allSetPtr_->allSetValues_.insert(it->second); - if (this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) return true; + if (this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) { + return true; + } } } continue; @@ -548,26 +564,40 @@ class ComparatorIndexedOffsetArrayDistinct : private DataHolder { for (const auto* const end = ptr + arr.len; ptr != end; ++ptr) { switch (this->cond_) { case CondEq: - if (*ptr == this->value_ && distinct_.Compare(*ptr)) return true; + if (*ptr == this->value_ && distinct_.Compare(*ptr)) { + return true; + } continue; case CondLt: - if (*ptr < this->value_ && distinct_.Compare(*ptr)) return true; + if (*ptr < this->value_ && distinct_.Compare(*ptr)) { + return true; + } continue; case CondLe: - if (*ptr <= this->value_ && distinct_.Compare(*ptr)) return true; + if (*ptr <= this->value_ && distinct_.Compare(*ptr)) { + return true; + } continue; case CondGt: - if (*ptr > this->value_ && distinct_.Compare(*ptr)) return true; + if (*ptr > this->value_ && distinct_.Compare(*ptr)) { + return true; + } continue; case CondGe: - if (*ptr >= this->value_ && distinct_.Compare(*ptr)) return true; + if (*ptr >= this->value_ && distinct_.Compare(*ptr)) { + return true; + } continue; case CondRange: - if (this->range_.first <= *ptr && *ptr <= this->range_.second && distinct_.Compare(*ptr)) return true; + if (this->range_.first <= *ptr && *ptr <= this->range_.second && distinct_.Compare(*ptr)) { + return true; + } continue; case CondSet: assertrx_dbg(this->setPtr_); - if (this->setPtr_->find(*ptr) != this->setPtr_->cend() && distinct_.Compare(*ptr)) return true; + if (this->setPtr_->find(*ptr) != this->setPtr_->cend() && distinct_.Compare(*ptr)) { + return true; + } continue; case CondAllSet: { assertrx_dbg(this->allSetPtr_); @@ -576,7 +606,9 @@ class ComparatorIndexedOffsetArrayDistinct : private DataHolder { if (it != this->allSetPtr_->values_.cend()) { haveDistinct |= distinct_.Compare(*ptr); this->allSetPtr_->allSetValues_.insert(it->second); - if (haveDistinct && this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) return true; + if (haveDistinct && this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) { + return true; + } } } continue; @@ -621,38 +653,56 @@ class ComparatorIndexedJsonPath : private DataHolder { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::From()); for (Variant& value : buffer_) { - if rx_unlikely (value.IsNullValue()) continue; + if rx_unlikely (value.IsNullValue()) { + continue; + } switch (this->cond_) { case CondEq: - if (value.As() == this->value_) return true; + if (value.As() == this->value_) { + return true; + } continue; case CondLt: - if (value.As() < this->value_) return true; + if (value.As() < this->value_) { + return true; + } continue; case CondLe: - if (value.As() <= this->value_) return true; + if (value.As() <= this->value_) { + return true; + } continue; case CondGt: - if (value.As() > this->value_) return true; + if (value.As() > this->value_) { + return true; + } continue; case CondGe: - if (value.As() >= this->value_) return true; + if (value.As() >= this->value_) { + return true; + } continue; case CondRange: { const auto v = value.As(); - if (this->range_.first <= v && v <= this->range_.second) return true; + if (this->range_.first <= v && v <= this->range_.second) { + return true; + } } continue; case CondSet: assertrx_dbg(this->setPtr_); - if (this->setPtr_->find(value.As()) != this->setPtr_->cend()) return true; + if (this->setPtr_->find(value.As()) != this->setPtr_->cend()) { + return true; + } continue; case CondAllSet: { assertrx_dbg(this->allSetPtr_); const auto it = this->allSetPtr_->values_.find(value.As()); if (it != this->allSetPtr_->values_.cend()) { this->allSetPtr_->allSetValues_.insert(it->second); - if (this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) return true; + if (this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) { + return true; + } } } continue; @@ -692,32 +742,48 @@ class ComparatorIndexedJsonPathDistinct : private DataHolder { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::From()); for (Variant& v : buffer_) { - if rx_unlikely (v.IsNullValue()) continue; + if rx_unlikely (v.IsNullValue()) { + continue; + } const auto value = v.As(); switch (this->cond_) { case CondEq: - if (value == this->value_ && distinct_.Compare(value)) return true; + if (value == this->value_ && distinct_.Compare(value)) { + return true; + } continue; case CondLt: - if (value < this->value_ && distinct_.Compare(value)) return true; + if (value < this->value_ && distinct_.Compare(value)) { + return true; + } continue; case CondLe: - if (value <= this->value_ && distinct_.Compare(value)) return true; + if (value <= this->value_ && distinct_.Compare(value)) { + return true; + } continue; case CondGt: - if (value > this->value_ && distinct_.Compare(value)) return true; + if (value > this->value_ && distinct_.Compare(value)) { + return true; + } continue; case CondGe: - if (value >= this->value_ && distinct_.Compare(value)) return true; + if (value >= this->value_ && distinct_.Compare(value)) { + return true; + } continue; case CondRange: { const auto v = value; - if (this->range_.first <= v && v <= this->range_.second && distinct_.Compare(value)) return true; + if (this->range_.first <= v && v <= this->range_.second && distinct_.Compare(value)) { + return true; + } } continue; case CondSet: assertrx_dbg(this->setPtr_); - if (this->setPtr_->find(value) != this->setPtr_->cend() && distinct_.Compare(value)) return true; + if (this->setPtr_->find(value) != this->setPtr_->cend() && distinct_.Compare(value)) { + return true; + } continue; case CondAllSet: { assertrx_dbg(this->allSetPtr_); @@ -726,7 +792,9 @@ class ComparatorIndexedJsonPathDistinct : private DataHolder { if (it != this->allSetPtr_->values_.cend()) { haveDistinct |= distinct_.Compare(value); this->allSetPtr_->allSetValues_.insert(it->second); - if (haveDistinct && this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) return true; + if (haveDistinct && this->allSetPtr_->allSetValues_.size() == this->allSetPtr_->values_.size()) { + return true; + } } } continue; @@ -746,7 +814,9 @@ class ComparatorIndexedJsonPathDistinct : private DataHolder { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::From()); for (Variant& v : buffer_) { - if rx_unlikely (v.IsNullValue()) continue; + if rx_unlikely (v.IsNullValue()) { + continue; + } distinct_.ExcludeValues(v.As()); } } @@ -958,7 +1028,9 @@ class ComparatorIndexedOffsetArrayString : private DataHolder { const std::string_view value = *ptr; switch (cond_) { case CondSet: - if (setPtr_->find(value) != setPtr_->cend()) return true; + if (setPtr_->find(value) != setPtr_->cend()) { + return true; + } continue; case CondRange: if ((collateCompare(value, range_.value1_.valueView_, *collateOpts_) & ComparationResult::Ge) && @@ -971,27 +1043,41 @@ class ComparatorIndexedOffsetArrayString : private DataHolder { const auto it = allSetPtr_->values_.find(value); if (it != allSetPtr_->values_.cend()) { allSetPtr_->allSetValues_.insert(it->second); - if (allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) return true; + if (allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) { + return true; + } } } continue; case CondLike: - if (matchLikePattern(value, value_.valueView_)) return true; + if (matchLikePattern(value, value_.valueView_)) { + return true; + } continue; case CondEq: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq) { + return true; + } continue; case CondLt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt) { + return true; + } continue; case CondLe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le) { + return true; + } continue; case CondGt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt) { + return true; + } continue; case CondGe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge) { + return true; + } continue; case CondAny: case CondEmpty: @@ -1027,7 +1113,9 @@ class ComparatorIndexedOffsetArrayStringDistinct : private DataHoldersetPtr_); - if (setPtr_->find(value) != setPtr_->cend() && distinct_.Compare(value)) return true; + if (setPtr_->find(value) != setPtr_->cend() && distinct_.Compare(value)) { + return true; + } continue; case CondRange: if ((collateCompare(value, range_.value1_.valueView_, *collateOpts_) & ComparationResult::Ge) && @@ -1043,32 +1131,41 @@ class ComparatorIndexedOffsetArrayStringDistinct : private DataHoldervalues_.cend()) { haveDistinct |= distinct_.Compare(value); allSetPtr_->allSetValues_.insert(it->second); - if (haveDistinct && allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) return true; + if (haveDistinct && allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) { + return true; + } } } continue; case CondLike: - if (matchLikePattern(value, value_.valueView_) && distinct_.Compare(value)) return true; + if (matchLikePattern(value, value_.valueView_) && distinct_.Compare(value)) { + return true; + } continue; case CondEq: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq && distinct_.Compare(value)) { return true; + } continue; case CondLt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt && distinct_.Compare(value)) { return true; + } continue; case CondLe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le && distinct_.Compare(value)) { return true; + } continue; case CondGt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt && distinct_.Compare(value)) { return true; + } continue; case CondGe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge && distinct_.Compare(value)) { return true; + } continue; case CondAny: case CondEmpty: @@ -1113,7 +1210,9 @@ class ComparatorIndexedJsonPathString : private DataHolder { switch (cond_) { case CondSet: assertrx_dbg(this->setPtr_); - if (setPtr_->find(value) != setPtr_->cend()) return true; + if (setPtr_->find(value) != setPtr_->cend()) { + return true; + } break; case CondRange: if ((collateCompare(value, range_.value1_.valueView_, *collateOpts_) & ComparationResult::Ge) && @@ -1126,26 +1225,40 @@ class ComparatorIndexedJsonPathString : private DataHolder { const auto it = allSetPtr_->values_.find(value); if (it != allSetPtr_->values_.cend()) { allSetPtr_->allSetValues_.insert(it->second); - if (allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) return true; + if (allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) { + return true; + } } } break; case CondLike: - if (matchLikePattern(value, value_.valueView_)) return true; + if (matchLikePattern(value, value_.valueView_)) { + return true; + } break; case CondEq: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq) { + return true; + } break; case CondLt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt) { + return true; + } break; case CondLe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le) { + return true; + } break; case CondGt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt) { + return true; + } break; case CondGe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge) return true; + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge) { + return true; + } break; case CondEmpty: case CondAny: @@ -1185,7 +1298,9 @@ class ComparatorIndexedJsonPathStringDistinct : private DataHolder { switch (cond_) { case CondSet: assertrx_dbg(this->setPtr_); - if (setPtr_->find(value) != setPtr_->cend() && distinct_.Compare(value)) return true; + if (setPtr_->find(value) != setPtr_->cend() && distinct_.Compare(value)) { + return true; + } break; case CondRange: if ((collateCompare(value, range_.value1_.valueView_, *collateOpts_) & ComparationResult::Ge) && @@ -1201,31 +1316,40 @@ class ComparatorIndexedJsonPathStringDistinct : private DataHolder { if (it != allSetPtr_->values_.cend()) { haveDistinct |= distinct_.Compare(value); allSetPtr_->allSetValues_.insert(it->second); - if (haveDistinct && allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) return true; + if (haveDistinct && allSetPtr_->allSetValues_.size() == allSetPtr_->values_.size()) { + return true; + } } } break; case CondLike: - if (matchLikePattern(value, value_.valueView_) && distinct_.Compare(value)) return true; + if (matchLikePattern(value, value_.valueView_) && distinct_.Compare(value)) { + return true; + } break; case CondEq: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Eq && distinct_.Compare(value)) { return true; + } break; case CondLt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Lt && distinct_.Compare(value)) { return true; + } break; case CondLe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Le && distinct_.Compare(value)) { return true; + } break; case CondGt: - if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) == ComparationResult::Gt && distinct_.Compare(value)) { return true; + } break; case CondGe: - if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge && distinct_.Compare(value)) + if (collateCompare(value, value_.valueView_, *collateOpts_) & ComparationResult::Ge && distinct_.Compare(value)) { return true; + } break; case CondEmpty: case CondAny: @@ -1496,7 +1620,9 @@ class ComparatorIndexedOffsetArrayAnyDistinct { const PayloadFieldValue::Array& arr = *reinterpret_cast(item.Ptr() + offset_); const auto* ptr = reinterpret_cast(item.Ptr() + arr.offset); for (const auto* const end = ptr + arr.len; ptr != end; ++ptr) { - if (distinct_.Compare(*ptr)) return true; + if (distinct_.Compare(*ptr)) { + return true; + } } return false; } @@ -1524,7 +1650,9 @@ class ComparatorIndexedOffsetArrayAnyStringDistinct { const PayloadFieldValue::Array& arr = *reinterpret_cast(item.Ptr() + offset_); const p_string* ptr = reinterpret_cast(item.Ptr() + arr.offset); for (const auto* const end = ptr + arr.len; ptr != end; ++ptr) { - if (distinct_.Compare(*ptr)) return true; + if (distinct_.Compare(*ptr)) { + return true; + } } return false; } @@ -1552,7 +1680,9 @@ class ComparatorIndexedJsonPathAny { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::Undefined{}); for (Variant& value : buffer_) { - if (!value.IsNullValue()) return true; + if (!value.IsNullValue()) { + return true; + } } return false; } @@ -1576,7 +1706,9 @@ class ComparatorIndexedJsonPathAnyDistinct { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::From()); for (Variant& value : buffer_) { - if (!value.IsNullValue() && distinct_.Compare(value.As())) return true; + if (!value.IsNullValue() && distinct_.Compare(value.As())) { + return true; + } } return false; } @@ -1608,7 +1740,9 @@ class ComparatorIndexedJsonPathAnyStringDistinct { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::String{}); for (Variant& value : buffer_) { - if (!value.IsNullValue() && distinct_.Compare(std::string_view{value})) return true; + if (!value.IsNullValue() && distinct_.Compare(std::string_view{value})) { + return true; + } } return false; } @@ -1656,7 +1790,9 @@ class ComparatorIndexedJsonPathEmpty { buffer_.clear(); ConstPayload(payloadType_, item).GetByJsonPath(tagsPath_, buffer_, KeyValueType::Undefined{}); for (Variant& value : buffer_) { - if (!value.IsNullValue()) return false; + if (!value.IsNullValue()) { + return false; + } } return true; } diff --git a/cpp_src/core/nsselecter/comparator/comparator_not_indexed.h b/cpp_src/core/nsselecter/comparator/comparator_not_indexed.h index 4d5d45711..149fc9e1d 100644 --- a/cpp_src/core/nsselecter/comparator/comparator_not_indexed.h +++ b/cpp_src/core/nsselecter/comparator/comparator_not_indexed.h @@ -77,7 +77,9 @@ class ComparatorNotIndexedImplBase { ComparatorNotIndexedImplBase(const VariantArray&); [[nodiscard]] std::string ConditionStr() const; [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const Variant& v) const { - if (!v.Type().Is()) return false; + if (!v.Type().Is()) { + return false; + } return matchLikePattern(static_cast(v), valueView_); } @@ -99,7 +101,9 @@ class ComparatorNotIndexedImpl : private ComparatorNotIndexedImplBa [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); for (const Variant& v : buffer_) { - if (Base::Compare(v)) return true; + if (Base::Compare(v)) { + return true; + } } return false; } @@ -124,7 +128,9 @@ class ComparatorNotIndexedImpl : private ComparatorNotIndexedImplBas [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); for (const Variant& v : buffer_) { - if (Base::Compare(v) == 0 && distinct_.Compare(v)) return true; + if (Base::Compare(v) == 0 && distinct_.Compare(v)) { + return true; + } } return false; } @@ -154,7 +160,9 @@ class ComparatorNotIndexedImpl { [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); for (const Variant& v : buffer_) { - if (!v.IsNullValue()) return true; + if (!v.IsNullValue()) { + return true; + } } return false; } @@ -177,7 +185,9 @@ class ComparatorNotIndexedImpl { [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); for (const Variant& v : buffer_) { - if (!v.IsNullValue() && distinct_.Compare(v)) return true; + if (!v.IsNullValue() && distinct_.Compare(v)) { + return true; + } } return false; } @@ -206,7 +216,9 @@ class ComparatorNotIndexedImpl { [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); for (const Variant& v : buffer_) { - if rx_unlikely (!v.IsNullValue()) return false; + if rx_unlikely (!v.IsNullValue()) { + return false; + } } return true; } @@ -266,8 +278,9 @@ class ComparatorNotIndexedImpl : private ComparatorNotIndexed : Base{values, payloadType, fieldPath} {} [[nodiscard]] RX_ALWAYS_INLINE bool Compare(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); - if (buffer_.size() != 2 || !buffer_[0].Type().Is() || !buffer_[0].Type().Is()) + if (buffer_.size() != 2 || !buffer_[0].Type().Is() || !buffer_[0].Type().Is()) { return false; + } const Point p{buffer_[0].As(), buffer_[1].As()}; return DWithin(p, point_, distance_) && distinct_.Compare(Variant{p}); } @@ -275,7 +288,9 @@ class ComparatorNotIndexedImpl : private ComparatorNotIndexed void ClearDistinctValues() noexcept { distinct_.ClearValues(); } void ExcludeDistinctValues(const PayloadValue& item, IdType /*rowId*/) { ConstPayload{payloadType_, item}.GetByJsonPath(fieldPath_, buffer_, KeyValueType::Undefined{}); - if (buffer_.size() != 2 || !buffer_[0].Type().Is() || !buffer_[0].Type().Is()) return; + if (buffer_.size() != 2 || !buffer_[0].Type().Is() || !buffer_[0].Type().Is()) { + return; + } const Point p{buffer_[0].As(), buffer_[1].As()}; distinct_.ExcludeValues(Variant{p}); } @@ -304,7 +319,9 @@ class ComparatorNotIndexedImpl { const auto it = values_.find(v); if (it != values_.cend()) { allSetValues_.emplace(it->second); - if (allSetValues_.size() == values_.size()) return true; + if (allSetValues_.size() == values_.size()) { + return true; + } } } return false; @@ -341,7 +358,9 @@ class ComparatorNotIndexedImpl : private ComparatorNotIndexedI if (distinct_.Compare(it->first)) { haveNotDistinct = true; } - if (haveNotDistinct && allSetValues_.size() == values_.size()) return true; + if (haveNotDistinct && allSetValues_.size() == values_.size()) { + return true; + } } } return false; diff --git a/cpp_src/core/nsselecter/comparator/equalposition_comparator.cc b/cpp_src/core/nsselecter/comparator/equalposition_comparator.cc index c28eb467a..e280835c2 100644 --- a/cpp_src/core/nsselecter/comparator/equalposition_comparator.cc +++ b/cpp_src/core/nsselecter/comparator/equalposition_comparator.cc @@ -6,20 +6,20 @@ namespace reindexer { -void EqualPositionComparator::BindField(const std::string &name, int field, const VariantArray &values, CondType cond, - const CollateOpts &collate) { +void EqualPositionComparator::BindField(const std::string& name, int field, const VariantArray& values, CondType cond, + const CollateOpts& collate) { bindField(name, field, values, cond, collate); } -void EqualPositionComparator::BindField(const std::string &name, const FieldsPath &fieldPath, const VariantArray &values, CondType cond) { +void EqualPositionComparator::BindField(const std::string& name, const FieldsPath& fieldPath, const VariantArray& values, CondType cond) { bindField(name, fieldPath, values, cond, CollateOpts{}); } template -void EqualPositionComparator::bindField(const std::string &name, F field, const VariantArray &values, CondType cond, - const CollateOpts &collate) { +void EqualPositionComparator::bindField(const std::string& name, F field, const VariantArray& values, CondType cond, + const CollateOpts& collate) { fields_.push_back(field); - Context &ctx = ctx_.emplace_back(collate); + Context& ctx = ctx_.emplace_back(collate); ctx.cond = cond; ctx.cmpBool.SetValues(cond, values); @@ -33,7 +33,7 @@ void EqualPositionComparator::bindField(const std::string &name, F field, const name_ += ' ' + name; } -bool EqualPositionComparator::Compare(const PayloadValue &pv, IdType /*rowId*/) { +bool EqualPositionComparator::Compare(const PayloadValue& pv, IdType /*rowId*/) { ConstPayload pl(payloadType_, pv); size_t len = INT_MAX; @@ -41,7 +41,7 @@ bool EqualPositionComparator::Compare(const PayloadValue &pv, IdType /*rowId*/) size_t tagsPathIdx = 0; vals.reserve(fields_.size()); for (size_t j = 0; j < fields_.size(); ++j) { - auto &v = vals.emplace_back(); + auto& v = vals.emplace_back(); bool isRegularIndex = fields_[j] != IndexValueType::SetByJsonPath && fields_[j] < payloadType_.NumFields(); if (isRegularIndex) { pl.Get(fields_[j], v); @@ -49,7 +49,9 @@ bool EqualPositionComparator::Compare(const PayloadValue &pv, IdType /*rowId*/) assertrx_throw(tagsPathIdx < fields_.getTagsPathsLength()); pl.GetByJsonPath(fields_.getTagsPath(tagsPathIdx++), v, KeyValueType::Undefined{}); } - if (v.size() < len) len = vals.back().size(); + if (v.size() < len) { + len = vals.back().size(); + } } for (size_t i = 0; i < len; ++i) { @@ -57,7 +59,9 @@ bool EqualPositionComparator::Compare(const PayloadValue &pv, IdType /*rowId*/) for (size_t j = 0; j < fields_.size(); ++j) { assertrx_throw(i < vals[j].size()); cmpRes &= !vals[j][i].Type().Is() && compareField(j, vals[j][i]); - if (!cmpRes) break; + if (!cmpRes) { + break; + } } if (cmpRes) { @@ -68,7 +72,7 @@ bool EqualPositionComparator::Compare(const PayloadValue &pv, IdType /*rowId*/) return false; } -bool EqualPositionComparator::compareField(size_t field, const Variant &v) { +bool EqualPositionComparator::compareField(size_t field, const Variant& v) { return v.Type().EvaluateOneOf( [&](KeyValueType::Bool) { return ctx_[field].cmpBool.Compare(ctx_[field].cond, static_cast(v)); }, [&](KeyValueType::Int) { return ctx_[field].cmpInt.Compare(ctx_[field].cond, static_cast(v)); }, diff --git a/cpp_src/core/nsselecter/comparator/equalposition_comparator_impl.h b/cpp_src/core/nsselecter/comparator/equalposition_comparator_impl.h index 52566b39b..ea5818181 100644 --- a/cpp_src/core/nsselecter/comparator/equalposition_comparator_impl.h +++ b/cpp_src/core/nsselecter/comparator/equalposition_comparator_impl.h @@ -15,12 +15,12 @@ namespace reindexer { template class EqualPositionComparatorImpl { using ValuesSet = intrusive_atomic_rc_wrapper>; - using AllSetValuesSet = intrusive_atomic_rc_wrapper>; + using AllSetValuesSet = intrusive_atomic_rc_wrapper>; public: EqualPositionComparatorImpl() noexcept = default; - void SetValues(CondType cond, const VariantArray &values) { + void SetValues(CondType cond, const VariantArray& values) { if (cond == CondSet) { valuesS_.reset(new ValuesSet{}); } else if (cond == CondAllSet) { @@ -62,7 +62,9 @@ class EqualPositionComparatorImpl { return valuesS_->find(lhs) != valuesS_->end(); case CondAllSet: { const auto it = valuesS_->find(lhs); - if (it == valuesS_->end()) return false; + if (it == valuesS_->end()) { + return false; + } allSetValuesS_->insert(&*it); return allSetValuesS_->size() == valuesS_->size(); } @@ -88,17 +90,17 @@ class EqualPositionComparatorImpl { private: KeyValueType type() { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) { return KeyValueType::Int{}; - else if constexpr (std::is_same_v) + } else if constexpr (std::is_same_v) { return KeyValueType::Bool{}; - else if constexpr (std::is_same_v) + } else if constexpr (std::is_same_v) { return KeyValueType::Int64{}; - else if constexpr (std::is_same_v) + } else if constexpr (std::is_same_v) { return KeyValueType::Double{}; - else if constexpr (std::is_same_v) + } else if constexpr (std::is_same_v) { return KeyValueType::Uuid{}; - else { + } else { static_assert(std::is_same_v, "Unknown KeyValueType"); } } @@ -115,12 +117,12 @@ class EqualPositionComparatorImpl { template <> class EqualPositionComparatorImpl { using ValuesSet = intrusive_atomic_rc_wrapper>; - using AllSetValuesSet = intrusive_atomic_rc_wrapper>; + using AllSetValuesSet = intrusive_atomic_rc_wrapper>; public: EqualPositionComparatorImpl() noexcept = default; - void SetValues(CondType cond, const VariantArray &values) { + void SetValues(CondType cond, const VariantArray& values) { if (cond == CondSet) { valuesS_.reset(new ValuesSet{}); } else if (cond == CondAllSet) { @@ -128,7 +130,7 @@ class EqualPositionComparatorImpl { allSetValuesS_.reset(new AllSetValuesSet{}); } - for (const Variant &key : values) { + for (const Variant& key : values) { key.Type().EvaluateOneOf( overloaded{[&](KeyValueType::Uuid) { addValue(cond, key.As()); }, [&](KeyValueType::String) { @@ -166,7 +168,9 @@ class EqualPositionComparatorImpl { return valuesS_->find(lhs) != valuesS_->end(); case CondAllSet: { const auto it = valuesS_->find(lhs); - if (it == valuesS_->end()) return false; + if (it == valuesS_->end()) { + return false; + } allSetValuesS_->insert(&*it); return allSetValuesS_->size() == valuesS_->size(); } @@ -202,14 +206,14 @@ class EqualPositionComparatorImpl { template <> class EqualPositionComparatorImpl { public: - EqualPositionComparatorImpl(const CollateOpts &collate) : collate_{collate} {} + EqualPositionComparatorImpl(const CollateOpts& collate) : collate_{collate} {} - void SetValues(CondType cond, const VariantArray &values) { + void SetValues(CondType cond, const VariantArray& values) { if (cond == CondSet) { valuesS_ = make_intrusive>(collate_); } else if (cond == CondAllSet) { valuesS_ = make_intrusive>(collate_); - allSetValuesS_ = make_intrusive>>(); + allSetValuesS_ = make_intrusive>>(); } for (Variant key : values) { @@ -241,7 +245,9 @@ class EqualPositionComparatorImpl { assertrx_dbg(valuesS_); assertrx_dbg(allSetValuesS_); auto it = valuesS_->find(lhs); - if (it == valuesS_->end()) return false; + if (it == valuesS_->end()) { + return false; + } allSetValuesS_->insert(&*it); return allSetValuesS_->size() == valuesS_->size(); } @@ -267,17 +273,17 @@ class EqualPositionComparatorImpl { class key_string_set : public tsl::hopscotch_sc_set { public: - key_string_set(const CollateOpts &opts) + key_string_set(const CollateOpts& opts) : tsl::hopscotch_sc_set( 1000, hash_key_string(CollateMode(opts.mode)), equal_key_string(opts), std::allocator(), less_key_string(opts)) {} }; intrusive_ptr> valuesS_; - intrusive_ptr>> allSetValuesS_; + intrusive_ptr>> allSetValuesS_; private: - void addValue(CondType cond, const key_string &value) { + void addValue(CondType cond, const key_string& value) { if (cond == CondSet || cond == CondAllSet) { valuesS_->emplace(value); } else { @@ -301,8 +307,10 @@ class EqualPositionComparatorImpl { public: EqualPositionComparatorImpl() noexcept = default; - void SetValues(const VariantArray &values) { - if (values.size() != 2) throw Error(errQueryExec, "CondDWithin expects two arguments"); + void SetValues(const VariantArray& values) { + if (values.size() != 2) { + throw Error(errQueryExec, "CondDWithin expects two arguments"); + } if (values[0].Type().Is()) { rhs_ = values[0].As(); distance_ = values[1].As(); diff --git a/cpp_src/core/nsselecter/comparator/fieldscomparator.cc b/cpp_src/core/nsselecter/comparator/fieldscomparator.cc index e0f191aef..6b84de8c0 100644 --- a/cpp_src/core/nsselecter/comparator/fieldscomparator.cc +++ b/cpp_src/core/nsselecter/comparator/fieldscomparator.cc @@ -12,42 +12,42 @@ namespace { class ArrayAdapter { class ConstIterator { public: - ConstIterator(const ArrayAdapter &aa, size_t i) noexcept : aa_{aa}, index_{i} {} - ConstIterator &operator++() noexcept { + ConstIterator(const ArrayAdapter& aa, size_t i) noexcept : aa_{aa}, index_{i} {} + ConstIterator& operator++() noexcept { ++index_; return *this; } - bool operator!=(const ConstIterator &other) const noexcept { + bool operator!=(const ConstIterator& other) const noexcept { assertrx_dbg(&aa_ == &other.aa_); return index_ != other.index_; } reindexer::Variant operator*() const { return aa_[index_]; } private: - const ArrayAdapter &aa_; + const ArrayAdapter& aa_; size_t index_; }; public: - ArrayAdapter(const uint8_t *ptr, size_t l, unsigned size_of, reindexer::KeyValueType t) noexcept + ArrayAdapter(const uint8_t* ptr, size_t l, unsigned size_of, reindexer::KeyValueType t) noexcept : ptr_{ptr}, len_{l}, sizeof_{size_of}, type_{t} {} size_t size() const noexcept { return len_; } reindexer::Variant operator[](size_t i) const { assertrx_dbg(i < len_); return type_.EvaluateOneOf( [&](reindexer::KeyValueType::Int64) noexcept { - return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; + return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, [&](reindexer::KeyValueType::Double) noexcept { - return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; + return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, [&](reindexer::KeyValueType::String) noexcept { - return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; + return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, - [&](reindexer::KeyValueType::Bool) noexcept { return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, - [&](reindexer::KeyValueType::Int) noexcept { return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, + [&](reindexer::KeyValueType::Bool) noexcept { return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, + [&](reindexer::KeyValueType::Int) noexcept { return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, [&](reindexer::KeyValueType::Uuid) noexcept { - return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; + return reindexer::Variant{*reinterpret_cast(ptr_ + sizeof_ * i)}; }, [&](reindexer::OneOf) -> reindexer::Variant { @@ -58,7 +58,7 @@ class ArrayAdapter { ConstIterator end() const noexcept { return {*this, len_}; } private: - const uint8_t *ptr_; + const uint8_t* ptr_; size_t len_; unsigned sizeof_; reindexer::KeyValueType type_; @@ -92,16 +92,18 @@ FieldsComparator::FieldsComparator(std::string_view lField, CondType cond, std:: } template -bool FieldsComparator::compare(const LArr &lhs, const RArr &rhs) { +bool FieldsComparator::compare(const LArr& lhs, const RArr& rhs) { static constexpr bool needCompareTypes{std::is_same_v || std::is_same_v}; switch (condition_) { case CondRange: if (rhs.size() < 2 || rhs[0].Type().template Is() || rhs[1].Type().template Is()) { throw Error{errQueryExec, "For condition range second field should be an array of 2 values"}; } - for (const Variant &v : lhs) { + for (const Variant& v : lhs) { if constexpr (needCompareTypes) { - if (!compareTypes(v.Type(), rhs[0].Type()) || !compareTypes(v.Type(), rhs[1].Type())) continue; + if (!compareTypes(v.Type(), rhs[0].Type()) || !compareTypes(v.Type(), rhs[1].Type())) { + continue; + } } if ((v.RelaxCompare(rhs[0], collateOpts_) & ComparationResult::Ge) && (v.RelaxCompare(rhs[1], collateOpts_) & ComparationResult::Le)) { @@ -110,30 +112,40 @@ bool FieldsComparator::compare(const LArr &lhs, const RArr &rhs) { } return false; case CondLike: - for (const Variant &lv : lhs) { - for (const Variant &rv : rhs) { + for (const Variant& lv : lhs) { + for (const Variant& rv : rhs) { if (!lv.Type().Is() || !rv.Type().Is()) { throw Error{errQueryExec, "For condition LIKE fields should be of string type"}; } - if (matchLikePattern(std::string_view(lv), std::string_view(rv))) return true; + if (matchLikePattern(std::string_view(lv), std::string_view(rv))) { + return true; + } } } return false; case CondAllSet: - for (const Variant &rv : rhs) { - if (rv.Type().Is()) continue; + for (const Variant& rv : rhs) { + if (rv.Type().Is()) { + continue; + } bool found = false; - for (const Variant &lv : lhs) { - if (lv.Type().Is()) continue; + for (const Variant& lv : lhs) { + if (lv.Type().Is()) { + continue; + } if constexpr (needCompareTypes) { - if (!compareTypes(lv.Type(), rv.Type())) continue; + if (!compareTypes(lv.Type(), rv.Type())) { + continue; + } } if (lv.RelaxCompare(rv, collateOpts_) == ComparationResult::Eq) { found = true; break; } } - if (!found) return false; + if (!found) { + return false; + } } return true; case CondAny: @@ -146,30 +158,46 @@ bool FieldsComparator::compare(const LArr &lhs, const RArr &rhs) { case CondEmpty: case CondDWithin: default: - for (const Variant &lv : lhs) { - if (lv.Type().Is()) continue; - for (const Variant &rv : rhs) { - if (rv.Type().Is()) continue; + for (const Variant& lv : lhs) { + if (lv.Type().Is()) { + continue; + } + for (const Variant& rv : rhs) { + if (rv.Type().Is()) { + continue; + } if constexpr (needCompareTypes) { - if (!compareTypes(lv.Type(), rv.Type())) continue; + if (!compareTypes(lv.Type(), rv.Type())) { + continue; + } } const auto compRes = lv.RelaxCompare(rv, collateOpts_); switch (condition_) { case CondEq: case CondSet: - if (compRes == ComparationResult::Eq) return true; + if (compRes == ComparationResult::Eq) { + return true; + } break; case CondLt: - if (compRes == ComparationResult::Lt) return true; + if (compRes == ComparationResult::Lt) { + return true; + } break; case CondLe: - if (compRes & ComparationResult::Le) return true; + if (compRes & ComparationResult::Le) { + return true; + } break; case CondGt: - if (compRes == ComparationResult::Gt) return true; + if (compRes == ComparationResult::Gt) { + return true; + } break; case CondGe: - if (compRes & ComparationResult::Ge) return true; + if (compRes & ComparationResult::Ge) { + return true; + } break; case CondAny: case CondEmpty: @@ -186,7 +214,7 @@ bool FieldsComparator::compare(const LArr &lhs, const RArr &rhs) { } } -bool FieldsComparator::compare(const PayloadValue &item, const Context &ctx) { +bool FieldsComparator::compare(const PayloadValue& item, const Context& ctx) { bool result; if (ctx.lCtx_.fields_.getTagsPathsLength() > 0) { VariantArray lhs; @@ -196,7 +224,7 @@ bool FieldsComparator::compare(const PayloadValue &item, const Context &ctx) { ConstPayload(payloadType_, item).GetByJsonPath(ctx.rCtx_.fields_.getTagsPath(0), rhs, ctx.rCtx_.type_); result = compare(lhs, rhs); } else if (ctx.rCtx_.isArray_) { - const PayloadFieldValue::Array *rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); + const PayloadFieldValue::Array* rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); result = compare(lhs, ArrayAdapter(item.Ptr() + rArr->offset, rArr->len, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); } else { result = compare(lhs, ArrayAdapter(item.Ptr() + ctx.rCtx_.offset_, 1, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); @@ -205,15 +233,15 @@ bool FieldsComparator::compare(const PayloadValue &item, const Context &ctx) { VariantArray rhs; ConstPayload(payloadType_, item).GetByJsonPath(ctx.rCtx_.fields_.getTagsPath(0), rhs, ctx.rCtx_.type_); if (ctx.lCtx_.isArray_) { - const PayloadFieldValue::Array *lArr = reinterpret_cast(item.Ptr() + ctx.lCtx_.offset_); + const PayloadFieldValue::Array* lArr = reinterpret_cast(item.Ptr() + ctx.lCtx_.offset_); result = compare(ArrayAdapter(item.Ptr() + lArr->offset, lArr->len, ctx.lCtx_.sizeof_, ctx.lCtx_.type_), rhs); } else { result = compare(ArrayAdapter(item.Ptr() + ctx.lCtx_.offset_, 1, ctx.lCtx_.sizeof_, ctx.lCtx_.type_), rhs); } } else if (ctx.lCtx_.isArray_) { - const PayloadFieldValue::Array *lArr = reinterpret_cast(item.Ptr() + ctx.lCtx_.offset_); + const PayloadFieldValue::Array* lArr = reinterpret_cast(item.Ptr() + ctx.lCtx_.offset_); if (ctx.rCtx_.isArray_) { - const PayloadFieldValue::Array *rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); + const PayloadFieldValue::Array* rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); result = compare(ArrayAdapter(item.Ptr() + lArr->offset, lArr->len, ctx.lCtx_.sizeof_, ctx.lCtx_.type_), ArrayAdapter(item.Ptr() + rArr->offset, rArr->len, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); } else { @@ -221,31 +249,31 @@ bool FieldsComparator::compare(const PayloadValue &item, const Context &ctx) { ArrayAdapter(item.Ptr() + ctx.rCtx_.offset_, 1, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); } } else if (ctx.rCtx_.isArray_) { - const PayloadFieldValue::Array *rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); + const PayloadFieldValue::Array* rArr = reinterpret_cast(item.Ptr() + ctx.rCtx_.offset_); result = compare(ArrayAdapter(item.Ptr() + ctx.lCtx_.offset_, 1, ctx.lCtx_.sizeof_, ctx.lCtx_.type_), ArrayAdapter(item.Ptr() + rArr->offset, rArr->len, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); } else { result = compare(ArrayAdapter(item.Ptr() + ctx.lCtx_.offset_, 1, ctx.lCtx_.sizeof_, ctx.lCtx_.type_), ArrayAdapter(item.Ptr() + ctx.rCtx_.offset_, 1, ctx.rCtx_.sizeof_, ctx.rCtx_.type_)); } - if (result) ++matchedCount_; + if (result) { + ++matchedCount_; + } return result; } void FieldsComparator::validateTypes(KeyValueType lType, KeyValueType rType) const { - if (lType.IsSame(rType) || lType.Is() || rType.Is()) return; + if (lType.IsSame(rType) || lType.Is() || rType.Is()) { + return; + } lType.EvaluateOneOf( - [&](KeyValueType::String) { - throw Error{errQueryExec, "Cannot compare a string field with a non-string one: %s", name_}; - }, + [&](KeyValueType::String) { throw Error{errQueryExec, "Cannot compare a string field with a non-string one: %s", name_}; }, [&](OneOf) { if (!rType.Is() && !rType.Is() && !rType.Is()) { throw Error{errQueryExec, "Cannot compare a numeric field with a non-numeric one: %s", name_}; } }, - [&](KeyValueType::Bool) { - throw Error{errQueryExec, "Cannot compare a boolean field with a non-boolean one: %s", name_}; - }, + [&](KeyValueType::Bool) { throw Error{errQueryExec, "Cannot compare a boolean field with a non-boolean one: %s", name_}; }, [&](OneOf) { throw Error{errQueryExec, "Field of type %s cannot be compared with another field: %s", lType.Name(), name_}; }); diff --git a/cpp_src/core/nsselecter/comparator/fieldscomparator.h b/cpp_src/core/nsselecter/comparator/fieldscomparator.h index e8f90730d..41a6fbd8f 100644 --- a/cpp_src/core/nsselecter/comparator/fieldscomparator.h +++ b/cpp_src/core/nsselecter/comparator/fieldscomparator.h @@ -16,7 +16,9 @@ class FieldsComparator { bool Compare(const PayloadValue& item, IdType /*rowId*/) { if (ctx_.size() > 1) { for (const auto& c : ctx_) { - if (!compare(item, c)) return false; + if (!compare(item, c)) { + return false; + } } return true; } @@ -130,7 +132,9 @@ class FieldsComparator { bool compare(const PayloadValue& item, const Context&); void validateTypes(KeyValueType lType, KeyValueType rType) const; inline static bool compareTypes(KeyValueType lType, KeyValueType rType) noexcept { - if (lType.IsSame(rType)) return true; + if (lType.IsSame(rType)) { + return true; + } return lType.EvaluateOneOf( [&](OneOf) noexcept { return rType.EvaluateOneOf( diff --git a/cpp_src/core/nsselecter/explaincalc.cc b/cpp_src/core/nsselecter/explaincalc.cc index 9cd5544f0..cba66acf2 100644 --- a/cpp_src/core/nsselecter/explaincalc.cc +++ b/cpp_src/core/nsselecter/explaincalc.cc @@ -23,23 +23,23 @@ void ExplainCalc::LogDump(int logLevel) { if (selectors_) { selectors_->VisitForEach( Skip{}, - [this](const SelectIterator &s) { + [this](const SelectIterator& s) { logPrintf(LogInfo, "%s: %d idsets, cost %g, matched %d, %s", s.name, s.size(), s.Cost(iters_), s.GetMatchedCount(), s.Dump()); }, - [this](const FieldsComparator &c) { + [this](const FieldsComparator& c) { logPrintf(LogInfo, "%s: cost %g, matched %d, %s", c.Name(), c.Cost(iters_), c.GetMatchedCount(), c.Dump()); }, Restricted>{}( - [this](const auto &c) { + [this](const auto& c) { logPrintf(LogInfo, "%s: cost %g, matched %d, %s", c.Name(), c.Cost(iters_), c.GetMatchedCount(), c.Dump()); }), - [](const AlwaysTrue &) { logPrintf(LogInfo, "AlwaysTrue"); }); + [](const AlwaysTrue&) { logPrintf(LogInfo, "AlwaysTrue"); }); } if (jselectors_) { - for (auto &js : *jselectors_) { + for (auto& js : *jselectors_) { if (js.Type() == JoinType::LeftJoin || js.Type() == JoinType::Merge) { logPrintf(LogInfo, "%s %s: called %d", JoinTypeName(js.Type()), js.RightNsName(), js.Called()); } else { @@ -51,7 +51,7 @@ void ExplainCalc::LogDump(int logLevel) { } } -constexpr static inline const char *joinTypeName(JoinType type) noexcept { +constexpr static inline const char* joinTypeName(JoinType type) noexcept { switch (type) { case JoinType::InnerJoin: return "inner_join "; @@ -66,7 +66,7 @@ constexpr static inline const char *joinTypeName(JoinType type) noexcept { } } -constexpr static inline const char *opName(OpType op, bool first = true) { +constexpr static inline const char* opName(OpType op, bool first = true) { switch (op) { case OpAnd: return first ? "" : "and "; @@ -93,12 +93,12 @@ constexpr std::string_view fieldKind(IteratorFieldKind fk) { } } -RX_NO_INLINE static std::string buildPreselectDescription(const JoinPreResult &result) { +RX_NO_INLINE static std::string buildPreselectDescription(const JoinPreResult& result) { assertrx_throw(result.properties); return std::visit( overloaded{ - [&](const IdSet &) -> std::string { - const PreselectProperties &props = *result.properties; + [&](const IdSet&) -> std::string { + const PreselectProperties& props = *result.properties; switch (result.storedValuesOptStatus) { case StoredValuesOptimizationStatus::DisabledByCompositeIndex: return fmt::sprintf( @@ -125,8 +125,8 @@ RX_NO_INLINE static std::string buildPreselectDescription(const JoinPreResult &r throw_as_assert; } }, - [&](const SelectIteratorContainer &) -> std::string { - const PreselectProperties &props = *result.properties; + [&](const SelectIteratorContainer&) -> std::string { + const PreselectProperties& props = *result.properties; if (props.isLimitExceeded) { return fmt::sprintf( "using no_preselect, because joined query's expected max iterations count of %d is larger than " @@ -138,14 +138,14 @@ RX_NO_INLINE static std::string buildPreselectDescription(const JoinPreResult &r return "using no_preselect, because joined query expects a sort a btree index that is not yet committed " "(optimization of indexes for the target namespace is not complete)"; }, - [&](const JoinPreResult::Values &) { + [&](const JoinPreResult::Values&) { return fmt::sprintf("using preselected_values, because the namespace's max iterations count is very small of %d", result.properties->qresMaxIteratios); }}, result.payload); } -static std::string addToJSON(JsonBuilder &builder, const JoinedSelector &js, OpType op = OpAnd) { +static std::string addToJSON(JsonBuilder& builder, const JoinedSelector& js, OpType op = OpAnd) { using namespace std::string_view_literals; auto jsonSel = builder.Object(); std::string name{joinTypeName(js.Type()) + js.RightNsName()}; @@ -157,15 +157,15 @@ static std::string addToJSON(JsonBuilder &builder, const JoinedSelector &js, OpT case JoinType::InnerJoin: case JoinType::OrInnerJoin: case JoinType::LeftJoin: - std::visit(overloaded{[&](const JoinPreResult::Values &values) { + std::visit(overloaded{[&](const JoinPreResult::Values& values) { jsonSel.Put("method"sv, "preselected_values"sv); jsonSel.Put("keys"sv, values.size()); }, - [&](const IdSet &ids) { + [&](const IdSet& ids) { jsonSel.Put("method"sv, "preselected_rows"sv); jsonSel.Put("keys"sv, ids.size()); }, - [&](const SelectIteratorContainer &iterators) { + [&](const SelectIteratorContainer& iterators) { jsonSel.Put("method"sv, "no_preselect"sv); jsonSel.Put("keys"sv, iterators.Size()); }}, @@ -186,7 +186,7 @@ static std::string addToJSON(JsonBuilder &builder, const JoinedSelector &js, OpT return name; } -static void addToJSON(JsonBuilder &builder, const ConditionInjection &injCond) { +static void addToJSON(JsonBuilder& builder, const ConditionInjection& injCond) { auto jsonSel = builder.Object(); using namespace std::string_view_literals; using namespace std::string_literals; @@ -220,7 +220,7 @@ static void addToJSON(JsonBuilder &builder, const ConditionInjection &injCond) { jsonSel.Put("new_condition"sv, injCond.newCond); } -static std::string addToJSON(JsonBuilder &builder, const JoinOnInjection &injCond) { +static std::string addToJSON(JsonBuilder& builder, const JoinOnInjection& injCond) { auto jsonSel = builder.Object(); std::string name{injCond.rightNsName}; using namespace std::string_view_literals; @@ -236,7 +236,7 @@ static std::string addToJSON(JsonBuilder &builder, const JoinOnInjection &injCon jsonSel.Put("injected_condition"sv, injCond.injectedCond.Slice()); if (!injCond.conditions.empty()) { auto jsonCondInjections = jsonSel.Array("conditions"sv); - for (const auto &cond : injCond.conditions) { + for (const auto& cond : injCond.conditions) { addToJSON(jsonCondInjections, cond); } } @@ -260,11 +260,11 @@ std::string ExplainCalc::GetJSON() { json.Put("general_sort_us"sv, To_us(sort_)); if (!subqueries_.empty()) { auto subQueries = json.Array("subqueries"); - for (const auto &sq : subqueries_) { + for (const auto& sq : subqueries_) { auto s = subQueries.Object(); s.Put("namespace", sq.NsName()); s.Raw("explain", sq.Explain()); - std::visit(overloaded{[&](size_t k) { s.Put("keys", k); }, [&](const std::string &f) { s.Put("field", f); }}, + std::visit(overloaded{[&](size_t k) { s.Put("keys", k); }, [&](const std::string& f) { s.Put("field", f); }}, sq.FieldOrKeys()); } } @@ -281,8 +281,10 @@ std::string ExplainCalc::GetJSON() { if (jselectors_) { // adding explain for LeftJoin-s and Merge subqueries - for (const JoinedSelector &js : *jselectors_) { - if (js.Type() == JoinType::InnerJoin || js.Type() == JoinType::OrInnerJoin) continue; + for (const JoinedSelector& js : *jselectors_) { + if (js.Type() == JoinType::InnerJoin || js.Type() == JoinType::OrInnerJoin) { + continue; + } addToJSON(jsonSelArr, js); } } @@ -290,7 +292,7 @@ std::string ExplainCalc::GetJSON() { if (onInjections_ && !onInjections_->empty()) { auto jsonOnInjections = json.Array("on_conditions_injections"sv); - for (const JoinOnInjection &injCond : *onInjections_) { + for (const JoinOnInjection& injCond : *onInjections_) { addToJSON(jsonOnInjections, injCond); } } @@ -299,17 +301,19 @@ std::string ExplainCalc::GetJSON() { return std::string(ser.Slice()); } -std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_iterator end, int iters, JsonBuilder &builder, - const JoinedSelectors *jselectors) { +std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_iterator end, int iters, JsonBuilder& builder, + const JoinedSelectors* jselectors) { using namespace std::string_literals; using namespace std::string_view_literals; std::stringstream name; name << '('; for (const_iterator it = begin; it != end; ++it) { - if (it != begin) name << ' '; + if (it != begin) { + name << ' '; + } it->Visit( - [&](const SelectIteratorsBracket &) { + [&](const SelectIteratorsBracket&) { auto jsonSel = builder.Object(); auto jsonSelArr = jsonSel.Array("selectors"sv); const std::string brName{explainJSON(it.cbegin(), it.cend(), iters, jsonSelArr, jselectors)}; @@ -317,7 +321,7 @@ std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_ite jsonSel.Put("field"sv, opName(it->operation) + brName); name << opName(it->operation, it == begin) << brName; }, - [&](const SelectIterator &siter) { + [&](const SelectIterator& siter) { auto jsonSel = builder.Object(); const bool isScanIterator{std::string_view(siter.name) == "-scan"sv}; if (!isScanIterator) { @@ -335,12 +339,12 @@ std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_ite jsonSel.Put("type"sv, siter.TypeName()); name << opName(it->operation, it == begin) << siter.name; }, - [&](const JoinSelectIterator &jiter) { + [&](const JoinSelectIterator& jiter) { assertrx_throw(jiter.joinIndex < jselectors->size()); const std::string jName{addToJSON(builder, (*jselectors)[jiter.joinIndex], it->operation)}; name << opName(it->operation, it == begin) << jName; }, - Restricted{}([&](const auto &c) { + Restricted{}([&](const auto& c) { auto jsonSel = builder.Object(); if constexpr (std::is_same_v) { jsonSel.Put("comparators"sv, c.FieldsCount()); @@ -356,7 +360,7 @@ std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_ite }), Restricted>{}( - [&](const auto &c) { + [&](const auto& c) { auto jsonSel = builder.Object(); jsonSel.Put("comparators"sv, 1); jsonSel.Put("field"sv, opName(it->operation) + std::string{c.Name()}); @@ -370,7 +374,7 @@ std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_ite : IteratorFieldKind::Indexed)); name << opName(it->operation, it == begin) << c.Name(); }), - [&](const AlwaysTrue &) { + [&](const AlwaysTrue&) { auto jsonSkipped = builder.Object(); jsonSkipped.Put("type"sv, "Skipped"sv); jsonSkipped.Put("description"sv, "always "s + (it->operation == OpNot ? "false" : "true")); @@ -382,6 +386,6 @@ std::string SelectIteratorContainer::explainJSON(const_iterator begin, const_ite return name.str(); } -int ExplainCalc::To_us(const ExplainCalc::Duration &d) noexcept { return duration_cast(d).count(); } +int ExplainCalc::To_us(const ExplainCalc::Duration& d) noexcept { return duration_cast(d).count(); } } // namespace reindexer diff --git a/cpp_src/core/nsselecter/explaincalc.h b/cpp_src/core/nsselecter/explaincalc.h index 02cce38d1..bc53f7177 100644 --- a/cpp_src/core/nsselecter/explaincalc.h +++ b/cpp_src/core/nsselecter/explaincalc.h @@ -49,39 +49,55 @@ class ExplainCalc { explicit ExplainCalc(bool enable) noexcept : enabled_(enable) {} void StartTiming() noexcept { - if (enabled_) lap(); + if (enabled_) { + lap(); + } } void StopTiming() noexcept { - if (enabled_) total_ = preselect_ + prepare_ + select_ + postprocess_ + loop_; + if (enabled_) { + total_ = preselect_ + prepare_ + select_ + postprocess_ + loop_; + } } void AddPrepareTime() noexcept { - if (enabled_) prepare_ += lap(); + if (enabled_) { + prepare_ += lap(); + } } void AddSelectTime() noexcept { - if (enabled_) select_ += lap(); + if (enabled_) { + select_ += lap(); + } } void AddPostprocessTime() noexcept { - if (enabled_) postprocess_ += lap(); + if (enabled_) { + postprocess_ += lap(); + } } void AddLoopTime() noexcept { - if (enabled_) loop_ += lap(); + if (enabled_) { + loop_ += lap(); + } } void AddIterations(int iters) noexcept { iters_ += iters; } void StartSort() noexcept { - if (enabled_) sort_start_point_ = Clock::now(); + if (enabled_) { + sort_start_point_ = Clock::now(); + } } void StopSort() noexcept { - if (enabled_) sort_ = Clock::now() - sort_start_point_; + if (enabled_) { + sort_ = Clock::now() - sort_start_point_; + } } void PutCount(int cnt) noexcept { count_ = cnt; } void PutSortIndex(std::string_view index) noexcept { sortIndex_ = index; } - void PutSelectors(const SelectIteratorContainer *qres) noexcept { selectors_ = qres; } - void PutJoinedSelectors(const JoinedSelectors *jselectors) noexcept { jselectors_ = jselectors; } + void PutSelectors(const SelectIteratorContainer* qres) noexcept { selectors_ = qres; } + void PutJoinedSelectors(const JoinedSelectors* jselectors) noexcept { jselectors_ = jselectors; } void SetPreselectTime(Duration preselectTime) noexcept { preselect_ = preselectTime; } - void PutOnConditionInjections(const OnConditionInjections *onCondInjections) noexcept { onInjections_ = onCondInjections; } + void PutOnConditionInjections(const OnConditionInjections* onCondInjections) noexcept { onInjections_ = onCondInjections; } void SetSortOptimization(bool enable) noexcept { sortOptimization_ = enable; } - void SetSubQueriesExplains(std::vector &&subQueriesExpl) noexcept { subqueries_ = std::move(subQueriesExpl); } + void SetSubQueriesExplains(std::vector&& subQueriesExpl) noexcept { subqueries_ = std::move(subQueriesExpl); } void LogDump(int logLevel); std::string GetJSON(); diff --git a/cpp_src/core/nsselecter/itemcomparator.cc b/cpp_src/core/nsselecter/itemcomparator.cc index e92896048..baedc2b59 100644 --- a/cpp_src/core/nsselecter/itemcomparator.cc +++ b/cpp_src/core/nsselecter/itemcomparator.cc @@ -24,15 +24,15 @@ struct FieldsCompRes { namespace reindexer { -bool ItemComparator::operator()(const ItemRef &lhs, const ItemRef &rhs) const { +bool ItemComparator::operator()(const ItemRef& lhs, const ItemRef& rhs) const { size_t expressionIndex{0}; FieldsCompRes mainNsRes; FieldsCompRes joinedNsRes; - for (const auto &comp : comparators_) { + for (const auto& comp : comparators_) { const ComparationResult res = std::visit( overloaded{[&](CompareByExpression c) noexcept { assertrx_throw(expressionIndex < ctx_.sortingContext.exprResults.size()); - const auto &eR{ctx_.sortingContext.exprResults[expressionIndex++]}; + const auto& eR{ctx_.sortingContext.exprResults[expressionIndex++]}; const auto lR{eR[lhs.SortExprResultsIdx()]}; const auto rR{eR[rhs.SortExprResultsIdx()]}; if (lR == rR) { @@ -45,8 +45,8 @@ bool ItemComparator::operator()(const ItemRef &lhs, const ItemRef &rhs) const { }, [&](CompareByJoinedField c) { if (joinedNsRes.firstDifferentFieldIdx == kNotComputed) { - const auto &jNs = joined_; - const auto &joinedSelector = *jNs.joinedSelector; + const auto& jNs = joined_; + const auto& joinedSelector = *jNs.joinedSelector; const joins::ItemIterator ljIt{joinResults_, lhs.Id()}; const joins::ItemIterator rjIt{joinResults_, rhs.Id()}; const auto ljfIt = ljIt.at(c.joinedNs); @@ -71,45 +71,47 @@ bool ItemComparator::operator()(const ItemRef &lhs, const ItemRef &rhs) const { return mainNsRes.GetResult(c.desc); }}, comp); - if (res != ComparationResult::Eq) return res == ComparationResult::Lt; + if (res != ComparationResult::Eq) { + return res == ComparationResult::Lt; + } } // If values are equal, then sort by row ID, to give consistent results - return std::visit([&](const auto &e) noexcept { return e.data.desc ? lhs.Id() > rhs.Id() : lhs.Id() < rhs.Id(); }, + return std::visit([&](const auto& e) noexcept { return e.data.desc ? lhs.Id() > rhs.Id() : lhs.Id() < rhs.Id(); }, ctx_.sortingContext.entries[0]); } class ItemComparator::BackInserter { public: - explicit BackInserter(ItemComparator &comparator) noexcept : comparator_(comparator) {} + explicit BackInserter(ItemComparator& comparator) noexcept : comparator_(comparator) {} void expr(bool desc) { comparator_.comparators_.emplace_back(CompareByExpression{desc}); } - void fields(TagsPath &&tp) { comparator_.fields_.push_back(std::move(tp)); } - void fields(Joined &joined, TagsPath &&tp) { joined.fields.push_back(std::move(tp)); } + void fields(TagsPath&& tp) { comparator_.fields_.push_back(std::move(tp)); } + void fields(Joined& joined, TagsPath&& tp) { joined.fields.push_back(std::move(tp)); } void fields(int fieldIdx) { if (fieldIdx != SetByJsonPath && !comparator_.fields_.contains(fieldIdx)) { comparator_.fields_.push_back(fieldIdx); - auto &rawDataRef = comparator_.rawData_.emplace_back(); + auto& rawDataRef = comparator_.rawData_.emplace_back(); if (auto rawData = comparator_.ns_.indexes_[fieldIdx]->ColumnData(); rawData) { rawDataRef.ptr = rawData; rawDataRef.type = comparator_.ns_.payloadType_.Field(fieldIdx).Type(); } } } - void fields(Joined &joined, int fieldIdx) { joined.fields.push_back(fieldIdx); } + void fields(Joined& joined, int fieldIdx) { joined.fields.push_back(fieldIdx); } void index(bool desc) { comparator_.comparators_.emplace_back(CompareByField{desc}); } void joined(size_t nsIdx, bool desc) { comparator_.comparators_.emplace_back(CompareByJoinedField{nsIdx, desc}); } - void collateOpts(const CollateOpts *opts) { comparator_.collateOpts_.emplace_back(opts); } - void collateOpts(Joined &joined, const CollateOpts *opts) { joined.collateOpts.emplace_back(opts); } + void collateOpts(const CollateOpts* opts) { comparator_.collateOpts_.emplace_back(opts); } + void collateOpts(Joined& joined, const CollateOpts* opts) { joined.collateOpts.emplace_back(opts); } private: - ItemComparator &comparator_; + ItemComparator& comparator_; }; class ItemComparator::FrontInserter { public: - FrontInserter(ItemComparator &comparator) noexcept : comparator_(comparator) {} + FrontInserter(ItemComparator& comparator) noexcept : comparator_(comparator) {} void expr(bool desc) { comparator_.comparators_.emplace(comparator_.comparators_.begin(), CompareByExpression{desc}); } - void fields(TagsPath &&tp) { comparator_.fields_.push_front(std::move(tp)); } - void fields(Joined &joined, TagsPath &&tp) { joined.fields.push_front(std::move(tp)); } + void fields(TagsPath&& tp) { comparator_.fields_.push_front(std::move(tp)); } + void fields(Joined& joined, TagsPath&& tp) { joined.fields.push_front(std::move(tp)); } void fields(int fieldIdx) { if (fieldIdx != SetByJsonPath && !comparator_.fields_.contains(fieldIdx)) { comparator_.fields_.push_front(fieldIdx); @@ -120,23 +122,23 @@ class ItemComparator::FrontInserter { } } } - void fields(Joined &joined, int fieldIdx) { joined.fields.push_front(fieldIdx); } + void fields(Joined& joined, int fieldIdx) { joined.fields.push_front(fieldIdx); } void index(bool desc) { comparator_.comparators_.emplace(comparator_.comparators_.begin(), CompareByField{desc}); } void joined(size_t nsIdx, bool desc) { comparator_.comparators_.emplace(comparator_.comparators_.begin(), CompareByJoinedField{nsIdx, desc}); } - void collateOpts(const CollateOpts *opts) { comparator_.collateOpts_.emplace(comparator_.collateOpts_.begin(), opts); } - void collateOpts(Joined &joined, const CollateOpts *opts) { joined.collateOpts.emplace(joined.collateOpts.begin(), opts); } + void collateOpts(const CollateOpts* opts) { comparator_.collateOpts_.emplace(comparator_.collateOpts_.begin(), opts); } + void collateOpts(Joined& joined, const CollateOpts* opts) { joined.collateOpts.emplace(joined.collateOpts.begin(), opts); } private: - ItemComparator &comparator_; + ItemComparator& comparator_; }; template -void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter insert, bool multiSort) { - std::visit(overloaded{[&](const SortingContext::ExpressionEntry &e) { insert.expr(e.data.desc); }, - [&](const SortingContext::JoinedFieldEntry &e) { - auto &jns = joined_; +void ItemComparator::bindOne(const SortingContext::Entry& sortingEntry, Inserter insert, bool multiSort) { + std::visit(overloaded{[&](const SortingContext::ExpressionEntry& e) { insert.expr(e.data.desc); }, + [&](const SortingContext::JoinedFieldEntry& e) { + auto& jns = joined_; if (jns.joinedSelector == nullptr) { assertrx_throw(ctx_.joinedSelectors); assertrx_throw(ctx_.joinedSelectors->size() > e.nsIdx); @@ -145,12 +147,12 @@ void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter assertrx_dbg(&(*ctx_.joinedSelectors)[e.nsIdx] == jns.joinedSelector); } assertrx_dbg(!std::holds_alternative(jns.joinedSelector->PreResult().payload)); - const auto &ns = *jns.joinedSelector->RightNs(); + const auto& ns = *jns.joinedSelector->RightNs(); const int fieldIdx = e.index; if (fieldIdx == IndexValueType::SetByJsonPath || ns.indexes_[fieldIdx]->Opts().IsSparse()) { TagsPath tagsPath; if (fieldIdx != IndexValueType::SetByJsonPath) { - const FieldsSet &fs = ns.indexes_[fieldIdx]->Fields(); + const FieldsSet& fs = ns.indexes_[fieldIdx]->Fields(); assertrx_throw(fs.getTagsPathsLength() > 0); tagsPath = fs.getTagsPath(0); } else { @@ -167,7 +169,7 @@ void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter insert.collateOpts(jns, nullptr); } } else { - const auto &idx = *ns.indexes_[fieldIdx]; + const auto& idx = *ns.indexes_[fieldIdx]; if (idx.Opts().IsArray()) { throw Error(errQueryExec, "Sorting cannot be applied to array field."); } @@ -192,12 +194,12 @@ void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter insert.collateOpts(jns, &idx.Opts().collateOpts_); } }, - [&](const SortingContext::FieldEntry &e) { + [&](const SortingContext::FieldEntry& e) { const int fieldIdx = e.data.index; if (fieldIdx == IndexValueType::SetByJsonPath || ns_.indexes_[fieldIdx]->Opts().IsSparse()) { TagsPath tagsPath; if (fieldIdx != IndexValueType::SetByJsonPath) { - const FieldsSet &fs = ns_.indexes_[fieldIdx]->Fields(); + const FieldsSet& fs = ns_.indexes_[fieldIdx]->Fields(); assertrx_throw(fs.getTagsPathsLength() > 0); tagsPath = fs.getTagsPath(0); } else { @@ -224,7 +226,7 @@ void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter const auto field(fields_[i]); assertrx_dbg(field != SetByJsonPath); comparators_.emplace_back(CompareByField{e.data.desc}); - auto &rawDataRef = rawData_.emplace_back(); + auto& rawDataRef = rawData_.emplace_back(); if (auto rawData = ns_.indexes_[field]->ColumnData(); rawData) { rawDataRef.ptr = rawData; rawDataRef.type = ns_.payloadType_.Field(field).Type(); @@ -244,8 +246,8 @@ void ItemComparator::bindOne(const SortingContext::Entry &sortingEntry, Inserter } void ItemComparator::BindForForcedSort() { - const auto &entries = ctx_.sortingContext.entries; - [[maybe_unused]] const auto &exprResults = ctx_.sortingContext.exprResults; + const auto& entries = ctx_.sortingContext.entries; + [[maybe_unused]] const auto& exprResults = ctx_.sortingContext.exprResults; assertrx_throw(entries.size() >= exprResults.size()); comparators_.reserve(entries.size()); const bool multiSort = entries.size() > 1; @@ -255,13 +257,13 @@ void ItemComparator::BindForForcedSort() { } void ItemComparator::BindForGeneralSort() { - const auto &entries = ctx_.sortingContext.entries; - [[maybe_unused]] const auto &exprResults = ctx_.sortingContext.exprResults; + const auto& entries = ctx_.sortingContext.entries; + [[maybe_unused]] const auto& exprResults = ctx_.sortingContext.exprResults; assertrx_throw(entries.size() >= exprResults.size()); const bool multiSort = entries.size() > 1; if (comparators_.empty()) { comparators_.reserve(entries.size()); - for (const auto &e : entries) { + for (const auto& e : entries) { bindOne(e, BackInserter{*this}, multiSort); } } else if (!entries.empty()) { @@ -269,42 +271,42 @@ void ItemComparator::BindForGeneralSort() { } } -ComparationResult ItemComparator::compareFields(IdType lId, IdType rId, size_t &firstDifferentFieldIdx) const { +ComparationResult ItemComparator::compareFields(IdType lId, IdType rId, size_t& firstDifferentFieldIdx) const { const bool commonOpts = (collateOpts_.size() == 1); size_t tagPathIdx = 0; size_t rawDataIdx = 0; for (size_t i = 0, sz = fields_.size(); i < sz; ++i) { - const CollateOpts *opts(commonOpts ? collateOpts_[0] : collateOpts_[i]); + const CollateOpts* opts(commonOpts ? collateOpts_[0] : collateOpts_[i]); ComparationResult cmpRes; const auto field(fields_[i]); if (field != SetByJsonPath && rawData_[rawDataIdx].ptr) { - const auto &rd = rawData_[rawDataIdx]; + const auto& rd = rawData_[rawDataIdx]; ++rawDataIdx; const auto rawData = rd.ptr; auto values = rd.type.EvaluateOneOf( [rawData, lId, rId](KeyValueType::Bool) noexcept { - return std::make_pair(Variant(*(static_cast(rawData) + lId)), - Variant(*(static_cast(rawData) + rId))); + return std::make_pair(Variant(*(static_cast(rawData) + lId)), + Variant(*(static_cast(rawData) + rId))); }, [rawData, lId, rId](KeyValueType::Int) noexcept { - return std::make_pair(Variant(*(static_cast(rawData) + lId)), - Variant(*(static_cast(rawData) + rId))); + return std::make_pair(Variant(*(static_cast(rawData) + lId)), + Variant(*(static_cast(rawData) + rId))); }, [rawData, lId, rId](KeyValueType::Int64) noexcept { - return std::make_pair(Variant(*(static_cast(rawData) + lId)), - Variant(*(static_cast(rawData) + rId))); + return std::make_pair(Variant(*(static_cast(rawData) + lId)), + Variant(*(static_cast(rawData) + rId))); }, [rawData, lId, rId](KeyValueType::Double) noexcept { - return std::make_pair(Variant(*(static_cast(rawData) + lId)), - Variant(*(static_cast(rawData) + rId))); + return std::make_pair(Variant(*(static_cast(rawData) + lId)), + Variant(*(static_cast(rawData) + rId))); }, [rawData, lId, rId](KeyValueType::String) noexcept { - return std::make_pair(Variant(p_string(static_cast(rawData) + lId), Variant::no_hold_t{}), - Variant(p_string(static_cast(rawData) + rId), Variant::no_hold_t{})); + return std::make_pair(Variant(p_string(static_cast(rawData) + lId), Variant::no_hold_t{}), + Variant(p_string(static_cast(rawData) + rId), Variant::no_hold_t{})); }, [rawData, lId, rId](KeyValueType::Uuid) noexcept { - return std::make_pair(Variant(*(static_cast(rawData) + lId)), - Variant(*(static_cast(rawData) + rId))); + return std::make_pair(Variant(*(static_cast(rawData) + lId)), + Variant(*(static_cast(rawData) + rId))); }, [](OneOf) -> std::pair { throw_as_assert; }); diff --git a/cpp_src/core/nsselecter/itemcomparator.h b/cpp_src/core/nsselecter/itemcomparator.h index 0489e097e..b51a22447 100644 --- a/cpp_src/core/nsselecter/itemcomparator.h +++ b/cpp_src/core/nsselecter/itemcomparator.h @@ -11,22 +11,22 @@ class ItemRef; class ItemComparator { public: - ItemComparator(const NamespaceImpl &ns, const SelectCtx &ctx, const joins::NamespaceResults *jr) noexcept + ItemComparator(const NamespaceImpl& ns, const SelectCtx& ctx, const joins::NamespaceResults* jr) noexcept : ns_(ns), ctx_(ctx), joinResults_(jr) {} - ItemComparator(const ItemComparator &) = delete; - ItemComparator(ItemComparator &&) = delete; - ItemComparator &operator=(const ItemComparator &) = delete; - ItemComparator &operator=(ItemComparator &&) = delete; + ItemComparator(const ItemComparator&) = delete; + ItemComparator(ItemComparator&&) = delete; + ItemComparator& operator=(const ItemComparator&) = delete; + ItemComparator& operator=(ItemComparator&&) = delete; - [[nodiscard]] bool operator()(const ItemRef &lhs, const ItemRef &rhs) const; + [[nodiscard]] bool operator()(const ItemRef& lhs, const ItemRef& rhs) const; void BindForForcedSort(); void BindForGeneralSort(); private: template - void bindOne(const SortingContext::Entry &sortingCtx, Inserter insert, bool multiSort); - ComparationResult compareFields(IdType lId, IdType rId, size_t &firstDifferentFieldIdx) const; + void bindOne(const SortingContext::Entry& sortingCtx, Inserter insert, bool multiSort); + ComparationResult compareFields(IdType lId, IdType rId, size_t& firstDifferentFieldIdx) const; class BackInserter; class FrontInserter; @@ -41,18 +41,18 @@ class ItemComparator { bool desc; }; struct Joined { - const JoinedSelector *joinedSelector{nullptr}; + const JoinedSelector* joinedSelector{nullptr}; FieldsSet fields; - h_vector collateOpts; + h_vector collateOpts; }; - const NamespaceImpl &ns_; - const SelectCtx &ctx_; - const joins::NamespaceResults *joinResults_; + const NamespaceImpl& ns_; + const SelectCtx& ctx_; + const joins::NamespaceResults* joinResults_; FieldsSet fields_; h_vector rawData_; Joined joined_; - h_vector collateOpts_; + h_vector collateOpts_; h_vector, 4> comparators_; }; diff --git a/cpp_src/core/nsselecter/joinedselector.cc b/cpp_src/core/nsselecter/joinedselector.cc index 9f0d433b4..8ff29e42e 100644 --- a/cpp_src/core/nsselecter/joinedselector.cc +++ b/cpp_src/core/nsselecter/joinedselector.cc @@ -10,7 +10,7 @@ constexpr size_t kMaxIterationsScaleForInnerJoinOptimization = 100; namespace reindexer { -void JoinedSelector::selectFromRightNs(QueryResults &joinItemR, const Query &query, bool &found, bool &matchedAtLeastOnce) { +void JoinedSelector::selectFromRightNs(QueryResults& joinItemR, const Query& query, bool& found, bool& matchedAtLeastOnce) { assertrx_dbg(rightNs_); JoinCacheRes joinResLong; @@ -43,23 +43,25 @@ void JoinedSelector::selectFromRightNs(QueryResults &joinItemR, const Query &que JoinCacheVal val; val.ids_ = make_intrusive>(); val.matchedAtLeastOnce = matchedAtLeastOnce; - for (auto &r : joinItemR.Items()) { + for (auto& r : joinItemR.Items()) { val.ids_->Add(r.Id(), IdSet::Unordered, 0); } rightNs_->putToJoinCache(joinResLong, std::move(val)); } } -void JoinedSelector::selectFromPreResultValues(QueryResults &joinItemR, const Query &query, bool &found, bool &matchedAtLeastOnce) const { +void JoinedSelector::selectFromPreResultValues(QueryResults& joinItemR, const Query& query, bool& found, bool& matchedAtLeastOnce) const { size_t matched = 0; - const auto &entries = query.Entries(); - const JoinPreResult::Values &values = std::get(PreResult().payload); - const auto &pt = values.payloadType; - for (const ItemRef &item : values) { - auto &v = item.Value(); + const auto& entries = query.Entries(); + const JoinPreResult::Values& values = std::get(PreResult().payload); + const auto& pt = values.payloadType; + for (const ItemRef& item : values) { + auto& v = item.Value(); assertrx_throw(!v.IsFree()); if (entries.CheckIfSatisfyConditions({pt, v})) { - if (++matched > query.Limit()) break; + if (++matched > query.Limit()) { + break; + } found = true; joinItemR.Add(item); } @@ -77,11 +79,13 @@ bool JoinedSelector::Process(IdType rowId, int nsId, ConstPayload payload, bool const auto startTime = ExplainCalc::Clock::now(); // Put values to join conditions size_t i = 0; - if (itemQuery_.NeedExplain() && !explainOneSelect_.empty()) itemQuery_.Explain(false); + if (itemQuery_.NeedExplain() && !explainOneSelect_.empty()) { + itemQuery_.Explain(false); + } std::unique_ptr itemQueryCopy; - Query *itemQueryPtr = &itemQuery_; - for (auto &je : joinQuery_.joinEntries_) { - QueryEntry &qentry = itemQueryPtr->GetUpdatableEntry(i); + Query* itemQueryPtr = &itemQuery_; + for (auto& je : joinQuery_.joinEntries_) { + QueryEntry& qentry = itemQueryPtr->GetUpdatableEntry(i); { auto keyValues = qentry.UpdatableValues(QueryEntry::IgnoreEmptyValues{}); payload.GetByFieldsSet(je.LeftFields(), keyValues, je.LeftFieldType(), je.LeftCompositeFieldsTypes()); @@ -101,112 +105,136 @@ bool JoinedSelector::Process(IdType rowId, int nsId, ConstPayload payload, bool bool matchedAtLeastOnce = false; QueryResults joinItemR; std::visit( - overloaded{[&](const JoinPreResult::Values &) { selectFromPreResultValues(joinItemR, *itemQueryPtr, found, matchedAtLeastOnce); }, + overloaded{[&](const JoinPreResult::Values&) { selectFromPreResultValues(joinItemR, *itemQueryPtr, found, matchedAtLeastOnce); }, Restricted{}( - [&](const auto &) { selectFromRightNs(joinItemR, *itemQueryPtr, found, matchedAtLeastOnce); })}, + [&](const auto&) { selectFromRightNs(joinItemR, *itemQueryPtr, found, matchedAtLeastOnce); })}, PreResult().payload); if (match && found) { assertrx_throw(nsId < static_cast(result_.joined_.size())); - joins::NamespaceResults &nsJoinRes = result_.joined_[nsId]; + joins::NamespaceResults& nsJoinRes = result_.joined_[nsId]; assertrx_dbg(nsJoinRes.GetJoinedSelectorsCount()); nsJoinRes.Insert(rowId, joinedFieldIdx_, std::move(joinItemR)); } - if (matchedAtLeastOnce) ++matched_; + if (matchedAtLeastOnce) { + ++matched_; + } selectTime_ += (ExplainCalc::Clock::now() - startTime); return matchedAtLeastOnce; } template -VariantArray JoinedSelector::readValuesOfRightNsFrom(const Cont &data, const Fn &createPayload, const QueryJoinEntry &entry, - const PayloadType &pt) const { +VariantArray JoinedSelector::readValuesOfRightNsFrom(const Cont& data, const Fn& createPayload, const QueryJoinEntry& entry, + const PayloadType& pt) const { const auto rightFieldType = entry.RightFieldType(); const auto leftFieldType = entry.LeftFieldType(); VariantArray res; if (rightFieldType.Is()) { unordered_payload_ref_set set(data.size(), hash_composite_ref(pt, entry.RightFields()), equal_composite_ref(pt, entry.RightFields())); - for (const auto &v : data) { + for (const auto& v : data) { const auto pl = createPayload(v); if (!pl.Value()->IsFree()) { set.insert(*pl.Value()); } } res.reserve(set.size()); - for (auto &s : set) { + for (auto& s : set) { res.emplace_back(std::move(s)); } } else { tsl::sparse_set set(data.size()); - for (const auto &val : data) { + for (const auto& val : data) { const auto pl = createPayload(val); if (pl.Value()->IsFree()) { continue; } pl.GetByFieldsSet(entry.RightFields(), res, entry.RightFieldType(), entry.RightCompositeFieldsTypes()); if (!leftFieldType.Is() && !leftFieldType.Is()) { - for (Variant &v : res) set.insert(std::move(v.convert(leftFieldType))); + for (Variant& v : res) { + set.insert(std::move(v.convert(leftFieldType))); + } } else { - for (Variant &v : res) set.insert(std::move(v)); + for (Variant& v : res) { + set.insert(std::move(v)); + } } } res.clear(); - for (auto &s : set) { + for (auto& s : set) { res.emplace_back(std::move(s)); } } return res; } -VariantArray JoinedSelector::readValuesFromPreResult(const QueryJoinEntry &entry) const { - const JoinPreResult::Values &values = std::get(PreResult().payload); +VariantArray JoinedSelector::readValuesFromPreResult(const QueryJoinEntry& entry) const { + const JoinPreResult::Values& values = std::get(PreResult().payload); return readValuesOfRightNsFrom( - values, - [&values](const ItemRef &item) noexcept { - return ConstPayload{values.payloadType, item.Value()}; - }, - entry, values.payloadType); + values, [&values](const ItemRef& item) noexcept { return ConstPayload{values.payloadType, item.Value()}; }, entry, + values.payloadType); } -void JoinedSelector::AppendSelectIteratorOfJoinIndexData(SelectIteratorContainer &iterators, int *maxIterations, unsigned sortId, - const SelectFunction::Ptr &selectFnc, const RdxContext &rdxCtx) { +void JoinedSelector::AppendSelectIteratorOfJoinIndexData(SelectIteratorContainer& iterators, int* maxIterations, unsigned sortId, + const SelectFunction::Ptr& selectFnc, const RdxContext& rdxCtx) { + const auto& preresult = PreResult(); if (joinType_ != JoinType::InnerJoin || preSelectCtx_.Mode() != JoinPreSelectMode::Execute || - std::visit(overloaded{[](const SelectIteratorContainer &) noexcept { return true; }, - Restricted{}([maxIterations](const auto &v) noexcept { + std::visit(overloaded{[](const SelectIteratorContainer&) noexcept { return true; }, + Restricted{}([maxIterations](const auto& v) noexcept { return v.size() > *maxIterations * kMaxIterationsScaleForInnerJoinOptimization; })}, - PreResult().payload)) { + preresult.payload)) { return; } unsigned optimized = 0; - assertrx_throw(!std::holds_alternative(PreResult().payload) || + assertrx_throw(!std::holds_alternative(preresult.payload) || itemQuery_.Entries().Size() == joinQuery_.joinEntries_.size()); for (size_t i = 0; i < joinQuery_.joinEntries_.size(); ++i) { - const QueryJoinEntry &joinEntry = joinQuery_.joinEntries_[i]; + const QueryJoinEntry& joinEntry = joinQuery_.joinEntries_[i]; if (!joinEntry.IsLeftFieldIndexed() || joinEntry.Operation() != OpAnd || (joinEntry.Condition() != CondEq && joinEntry.Condition() != CondSet) || (i + 1 < joinQuery_.joinEntries_.size() && joinQuery_.joinEntries_[i + 1].Operation() == OpOr)) { continue; } - const auto &leftIndex = leftNs_->indexes_[joinEntry.LeftIdxNo()]; + const auto& leftIndex = leftNs_->indexes_[joinEntry.LeftIdxNo()]; assertrx_throw(!IsFullText(leftIndex->Type())); - if (leftIndex->Opts().IsSparse()) continue; - - const VariantArray values = std::visit(overloaded{[&](const IdSet &preselected) { - return readValuesOfRightNsFrom( - preselected, - [this](IdType rowId) noexcept { - return ConstPayload{rightNs_->payloadType_, rightNs_->items_[rowId]}; - }, - joinEntry, rightNs_->payloadType_); - }, - [&](const JoinPreResult::Values &) { return readValuesFromPreResult(joinEntry); }, - [](const SelectIteratorContainer &) -> VariantArray { throw_as_assert; }}, - PreResult().payload); + + // Avoiding to use 'GetByJsonPath' during values extraction + // TODO: Sometimes this substituition may be effective even with 'GetByJsonPath', so we should allow user to hint this optimization. + bool hasSparse = false; + for (int field : joinEntry.RightFields()) { + if (field == SetByJsonPath) { + hasSparse = true; + break; + } + } + if (hasSparse) { + continue; + } + + const VariantArray values = + std::visit(overloaded{[&](const IdSet& preselected) { + const std::vector* sortOrderes = nullptr; + if (preresult.sortOrder.index) { + sortOrderes = &(preresult.sortOrder.index->SortOrders()); + } + return readValuesOfRightNsFrom( + preselected, + [this, sortOrderes](IdType rowId) noexcept { + const auto properRowId = sortOrderes ? (*sortOrderes)[rowId] : rowId; + return ConstPayload{rightNs_->payloadType_, rightNs_->items_[properRowId]}; + }, + joinEntry, rightNs_->payloadType_); + }, + [&](const JoinPreResult::Values&) { return readValuesFromPreResult(joinEntry); }, + [](const SelectIteratorContainer&) -> VariantArray { throw_as_assert; }}, + preresult.payload); auto ctx = selectFnc ? selectFnc->CreateCtx(joinEntry.LeftIdxNo()) : BaseFunctionCtx::Ptr{}; assertrx_throw(!ctx || ctx->type != BaseFunctionCtx::kFtCtx); if (leftIndex->Opts().GetCollateMode() == CollateUTF8) { - for (auto &key : values) key.EnsureUTF8(); + for (auto& key : values) { + key.EnsureUTF8(); + } } Index::SelectOpts opts; opts.maxIterations = iterators.GetMaxIterations(); @@ -214,17 +242,21 @@ void JoinedSelector::AppendSelectIteratorOfJoinIndexData(SelectIteratorContainer opts.inTransaction = inTransaction_; auto selectResults = leftIndex->SelectKey(values, CondSet, sortId, opts, ctx, rdxCtx); - if (auto *selRes = std::get_if(&selectResults)) { + if (auto* selRes = std::get_if(&selectResults)) { bool wasAppended = false; - for (SelectKeyResult &res : *selRes) { + for (SelectKeyResult& res : *selRes) { SelectIterator selIter{std::move(res), false, std::string(joinEntry.LeftFieldName()), (joinEntry.LeftIdxNo() < 0 ? IteratorFieldKind::NonIndexed : IteratorFieldKind::Indexed), false}; const int curIterations = selIter.GetMaxIterations(); - if (curIterations && curIterations < *maxIterations) *maxIterations = curIterations; + if (curIterations && curIterations < *maxIterations) { + *maxIterations = curIterations; + } iterators.Append(OpAnd, std::move(selIter)); wasAppended = true; } - if (wasAppended) ++optimized; + if (wasAppended) { + ++optimized; + } } } optimized_ = optimized == joinQuery_.joinEntries_.size(); diff --git a/cpp_src/core/nsselecter/joinedselector.h b/cpp_src/core/nsselecter/joinedselector.h index e3047e4a0..c4136a6dd 100644 --- a/cpp_src/core/nsselecter/joinedselector.h +++ b/cpp_src/core/nsselecter/joinedselector.h @@ -21,8 +21,8 @@ struct PreselectProperties { struct JoinPreResult { class Values : public std::vector { public: - Values(const PayloadType &pt, const TagsMatcher &tm) noexcept : payloadType{pt}, tagsMatcher{tm} {} - Values(Values &&other) noexcept + Values(const PayloadType& pt, const TagsMatcher& tm) noexcept : payloadType{pt}, tagsMatcher{tm} {} + Values(Values&& other) noexcept : std::vector(std::move(other)), payloadType(std::move(other.payloadType)), tagsMatcher(std::move(other.tagsMatcher)), @@ -30,18 +30,22 @@ struct JoinPreResult { other.locked_ = false; } Values() noexcept : locked_(false) {} - Values(const Values &) = delete; - Values &operator=(const Values &) = delete; - Values &operator=(Values &&) = delete; + Values(const Values&) = delete; + Values& operator=(const Values&) = delete; + Values& operator=(Values&&) = delete; ~Values() { if (locked_) { - for (size_t i = 0; i < size(); ++i) Payload{payloadType, (*this)[i].Value()}.ReleaseStrings(); + for (size_t i = 0; i < size(); ++i) { + Payload{payloadType, (*this)[i].Value()}.ReleaseStrings(); + } } } bool Locked() const { return locked_; } void Lock() { assertrx_throw(!locked_); - for (size_t i = 0; i < size(); ++i) Payload{payloadType, (*this)[i].Value()}.AddRefStrings(); + for (size_t i = 0; i < size(); ++i) { + Payload{payloadType, (*this)[i].Value()}.AddRefStrings(); + } locked_ = true; } bool IsPreselectAllowed() const noexcept { return preselectAllowed_; } @@ -55,12 +59,18 @@ struct JoinPreResult { bool preselectAllowed_ = true; }; + struct SortOrderContext { + const Index* index = nullptr; // main ordered index with built sort order mapping + SortingEntry sortingEntry; // main sorting entry for the ordered index + }; + using PreselectT = std::variant; typedef std::shared_ptr Ptr; typedef std::shared_ptr CPtr; PreselectT payload; bool enableSortOrders = false; bool btreeIndexOptimizationEnabled = true; + SortOrderContext sortOrder; StoredValuesOptimizationStatus storedValuesOptStatus = StoredValuesOptimizationStatus::Enabled; std::optional properties; std::string explainPreSelect; @@ -71,10 +81,10 @@ enum class JoinPreSelectMode { Empty, Build, Execute, ForInjection, InjectionRej class JoinPreResultBuildCtx { public: explicit JoinPreResultBuildCtx(JoinPreResult::Ptr r) noexcept : result_{std::move(r)} {} - JoinPreResult &Result() & noexcept { return *result_; } + JoinPreResult& Result() & noexcept { return *result_; } JoinPreSelectMode Mode() const noexcept { return JoinPreSelectMode::Build; } - const JoinPreResult::Ptr &ResultPtr() const & noexcept { return result_; } - auto ResultPtr() const && = delete; + const JoinPreResult::Ptr& ResultPtr() const& noexcept { return result_; } + auto ResultPtr() const&& = delete; private: JoinPreResult::Ptr result_; @@ -85,20 +95,20 @@ class JoinPreResultExecuteCtx { explicit JoinPreResultExecuteCtx(JoinPreResult::CPtr r) noexcept : result_{std::move(r)}, mode_{JoinPreSelectMode::Execute} {} explicit JoinPreResultExecuteCtx(JoinPreResult::CPtr r, int maxIters) noexcept : result_{std::move(r)}, mode_{JoinPreSelectMode::ForInjection}, mainQueryMaxIterations_{maxIters} {} - const JoinPreResult &Result() const & noexcept { return *result_; } + const JoinPreResult& Result() const& noexcept { return *result_; } JoinPreSelectMode Mode() const noexcept { return mode_; } int MainQueryMaxIterations() const { assertrx_dbg(mode_ == JoinPreSelectMode::ForInjection); return mainQueryMaxIterations_; } - const JoinPreResult::CPtr &ResultPtr() const & noexcept { return result_; } + const JoinPreResult::CPtr& ResultPtr() const& noexcept { return result_; } void Reject() { assertrx_dbg(mode_ == JoinPreSelectMode::ForInjection); mode_ = JoinPreSelectMode::InjectionRejected; } - auto Result() const && = delete; - auto ResultPtr() const && = delete; + auto Result() const&& = delete; + auto ResultPtr() const&& = delete; private: JoinPreResult::CPtr result_; @@ -120,9 +130,9 @@ class JoinedSelector { friend QueryPreprocessor; public: - JoinedSelector(JoinType joinType, NamespaceImpl::Ptr leftNs, NamespaceImpl::Ptr rightNs, JoinCacheRes &&joinRes, Query &&itemQuery, - QueryResults &result, const JoinedQuery &joinQuery, JoinPreResultExecuteCtx &&preSelCtx, uint32_t joinedFieldIdx, - SelectFunctionsHolder &selectFunctions, bool inTransaction, int64_t lastUpdateTime, const RdxContext &rdxCtx) + JoinedSelector(JoinType joinType, NamespaceImpl::Ptr leftNs, NamespaceImpl::Ptr rightNs, JoinCacheRes&& joinRes, Query&& itemQuery, + QueryResults& result, const JoinedQuery& joinQuery, JoinPreResultExecuteCtx&& preSelCtx, uint32_t joinedFieldIdx, + SelectFunctionsHolder& selectFunctions, bool inTransaction, int64_t lastUpdateTime, const RdxContext& rdxCtx) : joinType_(joinType), called_(0), matched_(0), @@ -140,46 +150,46 @@ class JoinedSelector { inTransaction_{inTransaction}, lastUpdateTime_{lastUpdateTime} { #ifndef NDEBUG - for (const auto &jqe : joinQuery_.joinEntries_) { + for (const auto& jqe : joinQuery_.joinEntries_) { assertrx_throw(jqe.FieldsHaveBeenSet()); } #endif } - JoinedSelector(JoinedSelector &&) = default; - JoinedSelector &operator=(JoinedSelector &&) = delete; - JoinedSelector(const JoinedSelector &) = delete; - JoinedSelector &operator=(const JoinedSelector &) = delete; + JoinedSelector(JoinedSelector&&) = default; + JoinedSelector& operator=(JoinedSelector&&) = delete; + JoinedSelector(const JoinedSelector&) = delete; + JoinedSelector& operator=(const JoinedSelector&) = delete; bool Process(IdType, int nsId, ConstPayload, bool match); JoinType Type() const noexcept { return joinType_; } void SetType(JoinType type) noexcept { joinType_ = type; } - const std::string &RightNsName() const noexcept { return itemQuery_.NsName(); } + const std::string& RightNsName() const noexcept { return itemQuery_.NsName(); } int64_t LastUpdateTime() const noexcept { return lastUpdateTime_; } - const JoinedQuery &JoinQuery() const noexcept { return joinQuery_; } + const JoinedQuery& JoinQuery() const noexcept { return joinQuery_; } int Called() const noexcept { return called_; } int Matched() const noexcept { return matched_; } - void AppendSelectIteratorOfJoinIndexData(SelectIteratorContainer &, int *maxIterations, unsigned sortId, const SelectFunction::Ptr &, - const RdxContext &); + void AppendSelectIteratorOfJoinIndexData(SelectIteratorContainer&, int* maxIterations, unsigned sortId, const SelectFunction::Ptr&, + const RdxContext&); static constexpr int MaxIterationsForPreResultStoreValuesOptimization() noexcept { return 200; } - const JoinPreResult &PreResult() const & noexcept { return preSelectCtx_.Result(); } - const JoinPreResult::CPtr &PreResultPtr() const & noexcept { return preSelectCtx_.ResultPtr(); } + const JoinPreResult& PreResult() const& noexcept { return preSelectCtx_.Result(); } + const JoinPreResult::CPtr& PreResultPtr() const& noexcept { return preSelectCtx_.ResultPtr(); } JoinPreSelectMode PreSelectMode() const noexcept { return preSelectCtx_.Mode(); } - const NamespaceImpl::Ptr &RightNs() const noexcept { return rightNs_; } + const NamespaceImpl::Ptr& RightNs() const noexcept { return rightNs_; } ExplainCalc::Duration SelectTime() const noexcept { return selectTime_; } - const std::string &ExplainOneSelect() const & noexcept { return explainOneSelect_; } + const std::string& ExplainOneSelect() const& noexcept { return explainOneSelect_; } - auto ExplainOneSelect() const && = delete; - auto PreResult() const && = delete; - auto PreResultPtr() const && = delete; + auto ExplainOneSelect() const&& = delete; + auto PreResult() const&& = delete; + auto PreResultPtr() const&& = delete; private: - [[nodiscard]] VariantArray readValuesFromPreResult(const QueryJoinEntry &) const; + [[nodiscard]] VariantArray readValuesFromPreResult(const QueryJoinEntry&) const; template - [[nodiscard]] VariantArray readValuesOfRightNsFrom(const Cont &from, const Fn &createPayload, const QueryJoinEntry &, - const PayloadType &) const; - void selectFromRightNs(QueryResults &joinItemR, const Query &, bool &found, bool &matchedAtLeastOnce); - void selectFromPreResultValues(QueryResults &joinItemR, const Query &, bool &found, bool &matchedAtLeastOnce) const; + [[nodiscard]] VariantArray readValuesOfRightNsFrom(const Cont& from, const Fn& createPayload, const QueryJoinEntry&, + const PayloadType&) const; + void selectFromRightNs(QueryResults& joinItemR, const Query&, bool& found, bool& matchedAtLeastOnce); + void selectFromPreResultValues(QueryResults& joinItemR, const Query&, bool& found, bool& matchedAtLeastOnce) const; JoinType joinType_; int called_, matched_; @@ -187,13 +197,13 @@ class JoinedSelector { NamespaceImpl::Ptr rightNs_; JoinCacheRes joinRes_; Query itemQuery_; - QueryResults &result_; - const JoinedQuery &joinQuery_; + QueryResults& result_; + const JoinedQuery& joinQuery_; JoinPreResultExecuteCtx preSelectCtx_; std::string explainOneSelect_; uint32_t joinedFieldIdx_; - SelectFunctionsHolder &selectFunctions_; - const RdxContext &rdxCtx_; + SelectFunctionsHolder& selectFunctions_; + const RdxContext& rdxCtx_; bool optimized_ = false; bool inTransaction_ = false; int64_t lastUpdateTime_ = 0; diff --git a/cpp_src/core/nsselecter/nsselecter.cc b/cpp_src/core/nsselecter/nsselecter.cc index 7eeb3f40b..984c4a78a 100644 --- a/cpp_src/core/nsselecter/nsselecter.cc +++ b/cpp_src/core/nsselecter/nsselecter.cc @@ -20,14 +20,14 @@ constexpr int kCancelCheckFrequency = 1024; namespace reindexer { template -void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect &ctx, const RdxContext &rdxCtx) { +void NsSelecter::operator()(QueryResults& result, SelectCtxWithJoinPreSelect& ctx, const RdxContext& rdxCtx) { // const std::string sql = ctx.query.GetSQL(); // std::cout << sql << std::endl; const size_t resultInitSize = result.Count(); ctx.sortingContext.enableSortOrders = ns_->SortOrdersBuilt(); const LogLevel logLevel = std::max(ns_->config_.logLevel, LogLevel(ctx.query.GetDebugLevel())); - auto &explain = ctx.explain; + auto& explain = ctx.explain; explain = ExplainCalc(ctx.query.NeedExplain() || logLevel >= LogInfo); explain.SetSubQueriesExplains(std::move(ctx.subQueriesExplains)); ActiveQueryScope queryScope(ctx, ns_->optimizationState_, explain, ns_->locker_.IsReadOnly(), ns_->strHolder_.get()); @@ -35,11 +35,11 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect) { assertrx_throw(ctx.preSelect.Mode() == JoinPreSelectMode::Execute || ctx.preSelect.Mode() == JoinPreSelectMode::ForInjection); - std::visit(overloaded{[&](const IdSet &ids) { + std::visit(overloaded{[&](const IdSet& ids) { SelectKeyResult res; res.emplace_back(ids); // Iterator Field Kind: Preselect IdSet -> None qres.Append(OpAnd, SelectIterator(std::move(res), false, "-preresult", IteratorFieldKind::None)); }, - [&](const SelectIteratorContainer &iterators) { + [&](const SelectIteratorContainer& iterators) { if (ctx.preSelect.Mode() == JoinPreSelectMode::Execute) { qres.Append(iterators.begin(), iterators.end()); } }, - [](const JoinPreResult::Values &) { throw_as_assert; }}, + [](const JoinPreResult::Values&) { throw_as_assert; }}, ctx.preSelect.Result().payload); } @@ -198,9 +198,12 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect) { // Building pre-result for next joins - auto &preResult = ctx.preSelect.Result(); + auto& preResult = ctx.preSelect.Result(); + if (auto sortFieldEntry = ctx.sortingContext.sortFieldEntryIfOrdered(); sortFieldEntry) { + preResult.sortOrder = JoinPreResult::SortOrderContext{.index = sortFieldEntry->index, .sortingEntry = sortFieldEntry->data}; + } preResult.properties.emplace(qres.GetMaxIterations(true), ns_->config().maxIterationsIdSetPreResult); - auto &preselectProps = preResult.properties.value(); + auto& preselectProps = preResult.properties.value(); assertrx_throw(preselectProps.maxIterationsIdSetPreResult > JoinedSelector::MaxIterationsForPreResultStoreValuesOptimization()); if ((preResult.storedValuesOptStatus == StoredValuesOptimizationStatus::Enabled) && preselectProps.qresMaxIteratios <= JoinedSelector::MaxIterationsForPreResultStoreValuesOptimization()) { @@ -225,11 +228,15 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect(); // For building join pre-result always use ASC sort orders - for (SortingEntry &se : sortBy) se.desc = false; + for (SortingEntry& se : sortBy) { + se.desc = false; + } } } } // pre-select rejected else if constexpr (std::is_same_v) { + // Main sorting index must be the same during join preselect build and execution + assertrx_throw(ctx.preSelect.Result().sortOrder.index == ctx.sortingContext.sortIndexIfOrdered()); if (ctx.preSelect.Mode() == JoinPreSelectMode::ForInjection && maxIterations > long(ctx.preSelect.MainQueryMaxIterations()) * ctx.preSelect.MainQueryMaxIterations()) { ctx.preSelect.Reject(); @@ -242,9 +249,9 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect= size || qres.GetOperation(qres.Next(i)) != OpOr)) { - const JoinSelectIterator &jIter = qres.Get(i); + const JoinSelectIterator& jIter = qres.Get(i); assertrx_throw(ctx.joinedSelectors && ctx.joinedSelectors->size() > jIter.joinIndex); - JoinedSelector &js = (*ctx.joinedSelectors)[jIter.joinIndex]; + JoinedSelector& js = (*ctx.joinedSelectors)[jIter.joinIndex]; js.AppendSelectIteratorOfJoinIndexData(qres, &maxIterations, ctx.sortingContext.sortId(), fnc_, rdxCtx); } } @@ -252,7 +259,7 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelectitems_.size(); if (ctx.sortingContext.isIndexOrdered() && ctx.sortingContext.enableSortOrders) { - const Index *index = ctx.sortingContext.sortIndex(); + const Index* index = ctx.sortingContext.sortIndex(); assertrx_throw(index); limit = index->SortOrders().size(); } @@ -294,8 +301,8 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect{}, Restricted>{}( - [](auto &comp) { comp.ClearDistinctValues(); }), - [reverse, maxIterations](SelectIterator &it) { it.Start(reverse, maxIterations); }); + [](auto& comp) { comp.ClearDistinctValues(); }), + [reverse, maxIterations](SelectIterator& it) { it.Start(reverse, maxIterations); }); // Let iterators choose most efficient algorithm assertrx_throw(qres.Size()); @@ -356,24 +363,28 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect) { - std::visit(overloaded{[this](JoinPreResult::Values &values) { - for (auto &iref : values) { - if (!iref.ValueInitialized()) iref.SetValue(ns_->items_[iref.Id()]); + std::visit(overloaded{[this](JoinPreResult::Values& values) { + for (auto& iref : values) { + if (!iref.ValueInitialized()) { + iref.SetValue(ns_->items_[iref.Id()]); + } } }, - Restricted{}([](const auto &) {})}, + Restricted{}([](const auto&) {})}, ctx.preSelect.Result().payload); } else { for (size_t i = resultInitSize; i < result.Items().size(); ++i) { - auto &iref = result.Items()[i]; - if (!iref.ValueInitialized()) iref.SetValue(ns_->items_[iref.Id()]); + auto& iref = result.Items()[i]; + if (!iref.ValueInitialized()) { + iref.SetValue(ns_->items_[iref.Id()]); + } } } } if (rx_unlikely(ctx.isMergeQuerySubQuery())) { writeAggregationResultMergeSubQuery(result, aggregators, ctx); } else { - for (auto &aggregator : aggregators) { + for (auto& aggregator : aggregators) { result.aggregationResults.push_back(aggregator.GetResult()); } } @@ -384,7 +395,7 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelectName() : "-"sv); if constexpr (std::is_same_v) { - explain.PutCount(std::visit(overloaded{[](const IdSet &ids) noexcept -> size_t { return ids.size(); }, - [](const JoinPreResult::Values &values) noexcept { return values.size(); }, - [](const SelectIteratorContainer &) -> size_t { throw_as_assert; }}, + explain.PutCount(std::visit(overloaded{[](const IdSet& ids) noexcept -> size_t { return ids.size(); }, + [](const JoinPreResult::Values& values) noexcept { return values.size(); }, + [](const SelectIteratorContainer&) -> size_t { throw_as_assert; }}, ctx.preSelect.Result().payload)); } else { explain.PutCount(result.Count()); @@ -431,60 +442,60 @@ void NsSelecter::operator()(QueryResults &result, SelectCtxWithJoinPreSelect) { if rx_unlikely (logLevel >= LogTrace) { - std::visit(overloaded{[&](const IdSet &ids) { + std::visit(overloaded{[&](const IdSet& ids) { logPrintf(LogInfo, "Built idset preResult (expected %d iterations) with %d ids, q = '%s'", explain.Iterations(), ids.size(), ctx.query.GetSQL()); }, - [&](const JoinPreResult::Values &values) { + [&](const JoinPreResult::Values& values) { logPrintf(LogInfo, "Built values preResult (expected %d iterations) with %d values, q = '%s'", explain.Iterations(), values.size(), ctx.query.GetSQL()); }, - [](const SelectIteratorContainer &) { throw_as_assert; }}, + [](const SelectIteratorContainer&) { throw_as_assert; }}, ctx.preSelect.Result().payload); } } } template -const PayloadValue &getValue(const ItemRef &itemRef, const std::vector &items); +const PayloadValue& getValue(const ItemRef& itemRef, const std::vector& items); template <> -const PayloadValue &getValue(const ItemRef &itemRef, const std::vector &items) { +const PayloadValue& getValue(const ItemRef& itemRef, const std::vector& items) { return items[itemRef.Id()]; } template <> -const PayloadValue &getValue(const ItemRef &itemRef, const std::vector &) { +const PayloadValue& getValue(const ItemRef& itemRef, const std::vector&) { return itemRef.Value(); } template <> class NsSelecter::MainNsValueGetter { public: - explicit MainNsValueGetter(const NamespaceImpl &ns) noexcept : ns_{ns} {} - const PayloadValue &Value(const ItemRef &itemRef) const noexcept { return ns_.items_[itemRef.Id()]; } - ConstPayload Payload(const ItemRef &itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } + explicit MainNsValueGetter(const NamespaceImpl& ns) noexcept : ns_{ns} {} + const PayloadValue& Value(const ItemRef& itemRef) const noexcept { return ns_.items_[itemRef.Id()]; } + ConstPayload Payload(const ItemRef& itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } private: - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; }; template <> class NsSelecter::MainNsValueGetter { public: - explicit MainNsValueGetter(const NamespaceImpl &ns) noexcept : ns_{ns} {} - const PayloadValue &Value(const ItemRef &itemRef) const noexcept { return itemRef.Value(); } - ConstPayload Payload(const ItemRef &itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } + explicit MainNsValueGetter(const NamespaceImpl& ns) noexcept : ns_{ns} {} + const PayloadValue& Value(const ItemRef& itemRef) const noexcept { return itemRef.Value(); } + ConstPayload Payload(const ItemRef& itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } private: - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; }; class NsSelecter::JoinedNsValueGetter { public: - JoinedNsValueGetter(const NamespaceImpl &ns, const joins::NamespaceResults &jr, size_t nsIdx) noexcept + JoinedNsValueGetter(const NamespaceImpl& ns, const joins::NamespaceResults& jr, size_t nsIdx) noexcept : ns_{ns}, joinedResults_{jr}, nsIdx_{nsIdx} {} - const PayloadValue &Value(const ItemRef &itemRef) const { + const PayloadValue& Value(const ItemRef& itemRef) const { const joins::ItemIterator it{&joinedResults_, itemRef.Id()}; const auto jfIt = it.at(nsIdx_); if (jfIt == it.end() || jfIt.ItemsCount() == 0) { @@ -495,38 +506,39 @@ class NsSelecter::JoinedNsValueGetter { } return jfIt[0].Value(); } - ConstPayload Payload(const ItemRef &itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } + ConstPayload Payload(const ItemRef& itemRef) const noexcept { return ConstPayload{ns_.payloadType_, Value(itemRef)}; } private: - const NamespaceImpl &ns_; - const joins::NamespaceResults &joinedResults_; + const NamespaceImpl& ns_; + const joins::NamespaceResults& joinedResults_; const size_t nsIdx_; }; template -It NsSelecter::applyForcedSort(It begin, It end, const ItemComparator &compare, const SelectCtx &ctx, const joins::NamespaceResults *jr) { +It NsSelecter::applyForcedSort(It begin, It end, const ItemComparator& compare, const SelectCtx& ctx, const joins::NamespaceResults* jr) { assertrx_throw(!ctx.sortingContext.entries.empty()); - if (ctx.query.GetMergeQueries().size() > 1) throw Error(errLogic, "Force sort could not be applied to 'merged' queries."); - return std::visit(overloaded{ - [](const SortingContext::ExpressionEntry &) -> It { - throw Error(errLogic, "Force sort could not be performed by expression."); - }, - [&](const SortingContext::FieldEntry &e) { - return applyForcedSortImpl(*ns_, begin, end, compare, ctx.query.forcedSortOrder_, - e.data.expression, MainNsValueGetter{*ns_}); - }, - [&](const SortingContext::JoinedFieldEntry &e) { - assertrx_throw(ctx.joinedSelectors); - assertrx_throw(ctx.joinedSelectors->size() >= e.nsIdx); - assertrx_throw(jr); - const auto &joinedSelector = (*ctx.joinedSelectors)[e.nsIdx]; - return applyForcedSortImpl( - *joinedSelector.RightNs(), begin, end, compare, ctx.query.forcedSortOrder_, std::string{e.field}, - JoinedNsValueGetter{*joinedSelector.RightNs(), *jr, e.nsIdx}); - }, - - }, - ctx.sortingContext.entries[0]); + if (ctx.query.GetMergeQueries().size() > 1) { + throw Error(errLogic, "Force sort could not be applied to 'merged' queries."); + } + return std::visit( + overloaded{ + [](const SortingContext::ExpressionEntry&) -> It { throw Error(errLogic, "Force sort could not be performed by expression."); }, + [&](const SortingContext::FieldEntry& e) { + return applyForcedSortImpl(*ns_, begin, end, compare, ctx.query.forcedSortOrder_, + e.data.expression, MainNsValueGetter{*ns_}); + }, + [&](const SortingContext::JoinedFieldEntry& e) { + assertrx_throw(ctx.joinedSelectors); + assertrx_throw(ctx.joinedSelectors->size() >= e.nsIdx); + assertrx_throw(jr); + const auto& joinedSelector = (*ctx.joinedSelectors)[e.nsIdx]; + return applyForcedSortImpl(*joinedSelector.RightNs(), begin, end, compare, + ctx.query.forcedSortOrder_, std::string{e.field}, + JoinedNsValueGetter{*joinedSelector.RightNs(), *jr, e.nsIdx}); + }, + + }, + ctx.sortingContext.entries[0]); } class ForcedSortMap { @@ -545,15 +557,15 @@ class ForcedSortMap { public: using Base::Base; - const auto *operator->() const { + const auto* operator->() const { return std::visit(overloaded{[](MultiMap::Iterator it) { return it.operator->(); }, [](SingleTypeMap::const_iterator it) { return it.operator->(); }}, - static_cast(*this)); + static_cast(*this)); } - const auto &operator*() const { - return std::visit(overloaded{[](MultiMap::Iterator it) -> const auto & { return *it; }, - [](SingleTypeMap::const_iterator it) -> const auto & { return *it; }}, - static_cast(*this)); + const auto& operator*() const { + return std::visit(overloaded{[](MultiMap::Iterator it) -> const auto& { return *it; }, + [](SingleTypeMap::const_iterator it) -> const auto& { return *it; }}, + static_cast(*this)); } }; @@ -562,15 +574,15 @@ class ForcedSortMap { : data_{k.Type().Is() || k.Type().Is() || k.Type().IsNumeric() ? DataType{MultiMap{size}} : DataType{SingleTypeMap{{}, k.Type()}}} { - std::visit(overloaded{[&](MultiMap &m) { m.emplace(std::move(k), v); }, [&](SingleTypeMap &m) { m.emplace(std::move(k), v); }}, + std::visit(overloaded{[&](MultiMap& m) { m.emplace(std::move(k), v); }, [&](SingleTypeMap& m) { m.emplace(std::move(k), v); }}, data_); } std::pair emplace(Variant k, mapped_type v) & { - return std::visit(overloaded{[&](MultiMap &m) { + return std::visit(overloaded{[&](MultiMap& m) { const auto [iter, success] = m.emplace(std::move(k), v); return std::make_pair(Iterator{iter}, success); }, - [&](SingleTypeMap &m) { + [&](SingleTypeMap& m) { if (!m.type_.IsSame(k.Type())) { throw Error{errQueryExec, "Items of different types in forced sort list"}; } @@ -579,9 +591,9 @@ class ForcedSortMap { }}, data_); } - bool contain(const Variant &k) const { - return std::visit(overloaded{[&k](const MultiMap &m) { return m.find(k) != m.cend(); }, - [&k](const SingleTypeMap &m) { + bool contain(const Variant& k) const { + return std::visit(overloaded{[&k](const MultiMap& m) { return m.find(k) != m.cend(); }, + [&k](const SingleTypeMap& m) { if (!m.type_.IsSame(k.Type())) { throw Error{errQueryExec, "Items of different types in forced sort list"}; } @@ -589,13 +601,13 @@ class ForcedSortMap { }}, data_); } - mapped_type get(const Variant &k) const { - return std::visit(overloaded{[&k](const MultiMap &m) { + mapped_type get(const Variant& k) const { + return std::visit(overloaded{[&k](const MultiMap& m) { const auto it = m.find(k); assertrx_throw(it != m.cend()); return it->second; }, - [&k](const SingleTypeMap &m) { + [&k](const SingleTypeMap& m) { if (!m.type_.IsSame(k.Type())) { throw Error{errQueryExec, "Items of different types in forced sort list"}; } @@ -613,9 +625,9 @@ class ForcedSortMap { template class ForcedMapInserter { public: - explicit ForcedMapInserter(Map &m) noexcept : map_{m} {} + explicit ForcedMapInserter(Map& m) noexcept : map_{m} {} template - void Insert(V &&value) { + void Insert(V&& value) { if (const auto [iter, success] = map_.emplace(std::forward(value), cost_); success) { ++cost_; } else if (iter->second != cost_ - 1) { @@ -629,28 +641,29 @@ class ForcedMapInserter { } private: - Map &map_; + Map& map_; typename Map::mapped_type cost_ = 1; }; template -It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const ItemComparator &compare, - const std::vector &forcedSortOrder, const std::string &fieldName, - const ValueGetter &valueGetter) { +It NsSelecter::applyForcedSortImpl(NamespaceImpl& ns, It begin, It end, const ItemComparator& compare, + const std::vector& forcedSortOrder, const std::string& fieldName, + const ValueGetter& valueGetter) { if (int idx; ns.getIndexByNameOrJsonPath(fieldName, idx)) { - if (ns.indexes_[idx]->Opts().IsArray()) + if (ns.indexes_[idx]->Opts().IsArray()) { throw Error(errQueryExec, "This type of sorting cannot be applied to a field of array type."); + } const KeyValueType fieldType{ns.indexes_[idx]->KeyType()}; if (idx < ns.indexes_.firstCompositePos()) { // implementation for regular indexes fast_hash_map sortMap; ForcedMapInserter inserter{sortMap}; - for (const auto &value : forcedSortOrder) { + for (const auto& value : forcedSortOrder) { inserter.Insert(value.convert(fieldType)); } VariantArray keyRefs; - const auto boundary = std::stable_partition(begin, end, [&](const ItemRef &itemRef) { + const auto boundary = std::stable_partition(begin, end, [&](const ItemRef& itemRef) { valueGetter.Payload(itemRef).Get(idx, keyRefs); if constexpr (desc) { return keyRefs.empty() || (sortMap.find(keyRefs[0]) == sortMap.end()); @@ -669,7 +682,7 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It from = begin; to = boundary; } - std::sort(from, to, [&](const ItemRef &lhs, const ItemRef &rhs) { + std::sort(from, to, [&](const ItemRef& lhs, const ItemRef& rhs) { valueGetter.Payload(lhs).Get(idx, lhsItemValue); assertrx_throw(!lhsItemValue.empty()); const auto lhsIt = sortMap.find(lhsItemValue[0]); @@ -703,16 +716,16 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It return boundary; } else { // implementation for composite indexes - const auto &payloadType = ns.payloadType_; - const FieldsSet &fields = ns.indexes_[idx]->Fields(); + const auto& payloadType = ns.payloadType_; + const FieldsSet& fields = ns.indexes_[idx]->Fields(); unordered_payload_map sortMap(0, PayloadType{payloadType}, FieldsSet{fields}); ForcedMapInserter inserter{sortMap}; for (auto value : forcedSortOrder) { value.convert(fieldType, &payloadType, &fields); - inserter.Insert(static_cast(value)); + inserter.Insert(static_cast(value)); } - const auto boundary = std::stable_partition(begin, end, [&](const ItemRef &itemRef) { + const auto boundary = std::stable_partition(begin, end, [&](const ItemRef& itemRef) { if constexpr (desc) { return (sortMap.find(valueGetter.Value(itemRef)) == sortMap.end()); } else { @@ -728,7 +741,7 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It from = begin; to = boundary; } - std::sort(from, to, [&](const ItemRef &lhs, const ItemRef &rhs) { + std::sort(from, to, [&](const ItemRef& lhs, const ItemRef& rhs) { const auto lhsPos = sortMap.find(valueGetter.Value(lhs))->second; const auto rhsPos = sortMap.find(valueGetter.Value(rhs))->second; if (lhsPos == rhsPos) { @@ -759,7 +772,7 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It } VariantArray keyRefs; - const auto boundary = std::stable_partition(begin, end, [&](const ItemRef &itemRef) { + const auto boundary = std::stable_partition(begin, end, [&](const ItemRef& itemRef) { valueGetter.Payload(itemRef).GetByJsonPath(fieldName, ns.tagsMatcher_, keyRefs, KeyValueType::Undefined{}); if constexpr (desc) { return keyRefs.empty() || !sortMap.contain(keyRefs[0]); @@ -778,7 +791,7 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It from = begin; to = boundary; } - std::sort(from, to, [&](const ItemRef &lhs, const ItemRef &rhs) { + std::sort(from, to, [&](const ItemRef& lhs, const ItemRef& rhs) { valueGetter.Payload(lhs).GetByJsonPath(fieldName, ns.tagsMatcher_, lhsItemValue, KeyValueType::Undefined{}); valueGetter.Payload(rhs).GetByJsonPath(fieldName, ns.tagsMatcher_, rhsItemValue, KeyValueType::Undefined{}); @@ -808,7 +821,7 @@ It NsSelecter::applyForcedSortImpl(NamespaceImpl &ns, It begin, It end, const It } template -void NsSelecter::applyGeneralSort(It itFirst, It itLast, It itEnd, const ItemComparator &comparator, const SelectCtx &ctx) { +void NsSelecter::applyGeneralSort(It itFirst, It itLast, It itEnd, const ItemComparator& comparator, const SelectCtx& ctx) { if (ctx.query.GetMergeQueries().size() > 1) { throw Error(errLogic, "Sorting cannot be applied to merged queries."); } @@ -816,7 +829,7 @@ void NsSelecter::applyGeneralSort(It itFirst, It itLast, It itEnd, const ItemCom std::partial_sort(itFirst, itLast, itEnd, std::cref(comparator)); } -void NsSelecter::setLimitAndOffset(ItemRefVector &queryResult, size_t offset, size_t limit) { +void NsSelecter::setLimitAndOffset(ItemRefVector& queryResult, size_t offset, size_t limit) { const unsigned totalRows = queryResult.size(); if (offset > 0) { auto end = offset < totalRows ? queryResult.begin() + offset : queryResult.end(); @@ -827,31 +840,39 @@ void NsSelecter::setLimitAndOffset(ItemRefVector &queryResult, size_t offset, si } } -void NsSelecter::processLeftJoins(QueryResults &qr, SelectCtx &sctx, size_t startPos, const RdxContext &rdxCtx) { - if (!checkIfThereAreLeftJoins(sctx)) return; +void NsSelecter::processLeftJoins(QueryResults& qr, SelectCtx& sctx, size_t startPos, const RdxContext& rdxCtx) { + if (!checkIfThereAreLeftJoins(sctx)) { + return; + } for (size_t i = startPos; i < qr.Count(); ++i) { IdType rowid = qr[i].GetItemRef().Id(); ConstPayload pl(ns_->payloadType_, ns_->items_[rowid]); - for (auto &joinedSelector : *sctx.joinedSelectors) { - if (joinedSelector.Type() == JoinType::LeftJoin) joinedSelector.Process(rowid, sctx.nsid, pl, true); + for (auto& joinedSelector : *sctx.joinedSelectors) { + if (joinedSelector.Type() == JoinType::LeftJoin) { + joinedSelector.Process(rowid, sctx.nsid, pl, true); + } + } + if (!sctx.inTransaction && (i % kCancelCheckFrequency == 0)) { + ThrowOnCancel(rdxCtx); } - if (!sctx.inTransaction && (i % kCancelCheckFrequency == 0)) ThrowOnCancel(rdxCtx); } } -bool NsSelecter::checkIfThereAreLeftJoins(SelectCtx &sctx) const { - if (!sctx.joinedSelectors) return false; +bool NsSelecter::checkIfThereAreLeftJoins(SelectCtx& sctx) const { + if (!sctx.joinedSelectors) { + return false; + } return std::any_of(sctx.joinedSelectors->begin(), sctx.joinedSelectors->end(), - [](const auto &selector) { return selector.Type() == JoinType::LeftJoin; }); + [](const auto& selector) { return selector.Type() == JoinType::LeftJoin; }); } template -void NsSelecter::sortResults(LoopCtx &ctx, It begin, It end, const SortingOptions &sortingOptions, - const joins::NamespaceResults *jr) { - SelectCtx &sctx = ctx.sctx; +void NsSelecter::sortResults(LoopCtx& ctx, It begin, It end, const SortingOptions& sortingOptions, + const joins::NamespaceResults* jr) { + SelectCtx& sctx = ctx.sctx; ctx.explain.StartSort(); #ifdef RX_WITH_STDLIB_DEBUG - for (const auto &eR : sctx.sortingContext.exprResults) { + for (const auto& eR : sctx.sortingContext.exprResults) { assertrx_dbg(eR.size() == end - begin); } #endif // RX_WITH_STDLIB_DEBUG @@ -886,24 +907,24 @@ void NsSelecter::sortResults(LoopCtx &ctx, It begin, It end, c ctx.explain.StopSort(); } -static size_t resultSize(const QueryResults &qr) noexcept { return qr.Count(); } +static size_t resultSize(const QueryResults& qr) noexcept { return qr.Count(); } -static void resultReserve(QueryResults &qr, size_t s) { qr.Items().reserve(s); } -static void resultReserve(FtMergeStatuses &, size_t) {} +static void resultReserve(QueryResults& qr, size_t s) { qr.Items().reserve(s); } +static void resultReserve(FtMergeStatuses&, size_t) {} template -void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, const RdxContext &rdxCtx) { +void NsSelecter::selectLoop(LoopCtx& ctx, ResultsT& result, const RdxContext& rdxCtx) { static constexpr bool kPreprocessingBeforFT = !std::is_same_v; static const JoinedSelectors emptyJoinedSelectors; const auto selectLoopWard = rdxCtx.BeforeSelectLoop(); - SelectCtxWithJoinPreSelect &sctx = ctx.sctx; - const auto &joinedSelectors = sctx.joinedSelectors ? *sctx.joinedSelectors : emptyJoinedSelectors; - SelectIteratorContainer &qres = ctx.qres; + SelectCtxWithJoinPreSelect& sctx = ctx.sctx; + const auto& joinedSelectors = sctx.joinedSelectors ? *sctx.joinedSelectors : emptyJoinedSelectors; + SelectIteratorContainer& qres = ctx.qres; // Is not using during ft preprocessing size_t initCount = 0; if constexpr (!kPreprocessingBeforFT) { if constexpr (!std::is_same_v) { - if (auto *values = std::get_if(&sctx.preSelect.Result().payload); values) { + if (auto* values = std::get_if(&sctx.preSelect.Result().payload); values) { initCount = values->size(); } else { initCount = resultSize(result); @@ -921,7 +942,7 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co if (qres.Size() == 1 && qres.IsSelectIterator(0) && qres.Get(0).size() == 1) { const unsigned reserve = std::min(unsigned(qres.Get(0).GetMaxIterations()), ctx.count); if constexpr (std::is_same_v) { - if (auto *values = std::get_if(&sctx.preSelect.Result().payload); values) { + if (auto* values = std::get_if(&sctx.preSelect.Result().payload); values) { values->reserve(reserve + initCount); } else { resultReserve(result, initCount + reserve); @@ -934,7 +955,7 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co bool finish = (ctx.count == 0) && !sctx.reqMatchedOnceFlag && !ctx.calcTotal && !sctx.matchedAtLeastOnce; SortingOptions sortingOptions(sctx.sortingContext); - const Index *const firstSortIndex = sctx.sortingContext.sortIndexIfOrdered(); + const Index* const firstSortIndex = sctx.sortingContext.sortIndexIfOrdered(); bool multiSortFinished = !(sortingOptions.multiColumnByBtreeIndex && ctx.count > 0); VariantArray prevValues; @@ -942,10 +963,12 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co assertrx_throw(!qres.Empty()); assertrx_throw(qres.IsSelectIterator(0)); - SelectIterator &firstIterator = qres.begin()->Value(); + SelectIterator& firstIterator = qres.begin()->Value(); IdType rowId = firstIterator.Val(); while (firstIterator.Next(rowId) && !finish) { - if ((rowId % kCancelCheckFrequency == 0) && !sctx.inTransaction) ThrowOnCancel(rdxCtx); + if ((rowId % kCancelCheckFrequency == 0) && !sctx.inTransaction) { + ThrowOnCancel(rdxCtx); + } rowId = firstIterator.Val(); IdType properRowId = rowId; @@ -957,8 +980,10 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co } assertrx_throw(static_cast(properRowId) < ns_->items_.size()); - PayloadValue &pv = ns_->items_[properRowId]; - if (pv.IsFree()) continue; + PayloadValue& pv = ns_->items_[properRowId]; + if (pv.IsFree()) { + continue; + } if (qres.Process(pv, &finish, &rowId, properRowId, !ctx.start && ctx.count)) { sctx.matchedAtLeastOnce = true; // Check distinct condition: @@ -966,14 +991,14 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co // be removed qres.VisitForEach( Skip{}, - [rowId](SelectIterator &sit) { + [rowId](SelectIterator& sit) { if (sit.distinct) { sit.ExcludeLastSet(rowId); } }, Restricted>{}( - [&pv, properRowId](auto &comp) { comp.ExcludeDistinctValues(pv, properRowId); })); + [&pv, properRowId](auto& comp) { comp.ExcludeDistinctValues(pv, properRowId); })); if constexpr (!kPreprocessingBeforFT) { uint8_t proc = ft_ctx_ ? ft_ctx_->Proc(firstIterator.Pos()) : 0; if ((ctx.start || (ctx.count == 0)) && sortingOptions.multiColumnByBtreeIndex) { @@ -1009,9 +1034,10 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co } else if (ctx.count) { addSelectResult(proc, rowId, properRowId, sctx, ctx.aggregators, result, ctx.preselectForFt); --ctx.count; - if (!ctx.count && sortingOptions.multiColumn && !multiSortFinished) + if (!ctx.count && sortingOptions.multiColumn && !multiSortFinished) { getSortIndexValue(sctx.sortingContext, properRowId, prevValues, proc, sctx.nsid < result.joined_.size() ? &result.joined_[sctx.nsid] : nullptr, joinedSelectors); + } } if (!ctx.count && !ctx.calcTotal && multiSortFinished) { break; @@ -1030,6 +1056,7 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co bool toPreResultValues = false; if constexpr (std::is_same_v) { if (auto values = std::get_if(&sctx.preSelect.Result().payload); values) { + toPreResultValues = true; if (sctx.isForceAll) { assertrx_throw(!ctx.qPreproc.Start() || !initCount); if (ctx.qPreproc.Start() <= values->size()) { @@ -1075,35 +1102,35 @@ void NsSelecter::selectLoop(LoopCtx &ctx, ResultsT &result, co } } -void NsSelecter::getSortIndexValue(const SortingContext &sortCtx, IdType rowId, VariantArray &value, uint8_t proc, - const joins::NamespaceResults *joinResults, const JoinedSelectors &js) { +void NsSelecter::getSortIndexValue(const SortingContext& sortCtx, IdType rowId, VariantArray& value, uint8_t proc, + const joins::NamespaceResults* joinResults, const JoinedSelectors& js) { std::visit( overloaded{ - [&](const SortingContext::ExpressionEntry &e) { + [&](const SortingContext::ExpressionEntry& e) { assertrx_throw(e.expression < sortCtx.expressions.size()); ConstPayload pv(ns_->payloadType_, ns_->items_[rowId]); value = VariantArray{Variant{sortCtx.expressions[e.expression].Calculate(rowId, pv, joinResults, js, proc, ns_->tagsMatcher_)}}; }, - [&](const SortingContext::JoinedFieldEntry &e) { + [&](const SortingContext::JoinedFieldEntry& e) { assertrx_throw(joinResults); value = SortExpression::GetJoinedFieldValues(rowId, *joinResults, js, e.nsIdx, e.field, e.index); }, - [&](const SortingContext::FieldEntry &e) { + [&](const SortingContext::FieldEntry& e) { if (e.rawData.ptr) { value = VariantArray{e.rawData.type.EvaluateOneOf( - [&e, rowId](KeyValueType::Bool) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, - [&e, rowId](KeyValueType::Int) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, + [&e, rowId](KeyValueType::Bool) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, + [&e, rowId](KeyValueType::Int) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, [&e, rowId](KeyValueType::Int64) noexcept { - return Variant(*(static_cast(e.rawData.ptr) + rowId)); + return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, [&e, rowId](KeyValueType::Double) noexcept { - return Variant(*(static_cast(e.rawData.ptr) + rowId)); + return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, [&e, rowId](KeyValueType::String) noexcept { - return Variant(p_string(static_cast(e.rawData.ptr) + rowId), Variant::no_hold_t{}); + return Variant(p_string(static_cast(e.rawData.ptr) + rowId), Variant::no_hold_t{}); }, - [&e, rowId](KeyValueType::Uuid) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, + [&e, rowId](KeyValueType::Uuid) noexcept { return Variant(*(static_cast(e.rawData.ptr) + rowId)); }, [](OneOf) -> Variant { throw_as_assert; })}; @@ -1119,13 +1146,13 @@ void NsSelecter::getSortIndexValue(const SortingContext &sortCtx, IdType rowId, sortCtx.getFirstColumnEntry()); } -void NsSelecter::calculateSortExpressions(uint8_t proc, IdType rowId, IdType properRowId, SelectCtx &sctx, const QueryResults &result) { +void NsSelecter::calculateSortExpressions(uint8_t proc, IdType rowId, IdType properRowId, SelectCtx& sctx, const QueryResults& result) { static const JoinedSelectors emptyJoinedSelectors; - const auto &exprs = sctx.sortingContext.expressions; - auto &exprResults = sctx.sortingContext.exprResults; + const auto& exprs = sctx.sortingContext.expressions; + auto& exprResults = sctx.sortingContext.exprResults; assertrx_throw(exprs.size() == exprResults.size()); const ConstPayload pv(ns_->payloadType_, ns_->items_[properRowId]); - const auto &joinedSelectors = sctx.joinedSelectors ? *sctx.joinedSelectors : emptyJoinedSelectors; + const auto& joinedSelectors = sctx.joinedSelectors ? *sctx.joinedSelectors : emptyJoinedSelectors; const auto joinedResultPtr = sctx.nsid < result.joined_.size() ? &result.joined_[sctx.nsid] : nullptr; for (size_t i = 0; i < exprs.size(); ++i) { exprResults[i].push_back(exprs[i].Calculate(rowId, pv, joinedResultPtr, joinedSelectors, proc, ns_->tagsMatcher_)); @@ -1133,17 +1160,25 @@ void NsSelecter::calculateSortExpressions(uint8_t proc, IdType rowId, IdType pro } template -void NsSelecter::addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, SelectCtxWithJoinPreSelect &sctx, - h_vector &aggregators, QueryResults &result, bool preselectForFt) { - if (preselectForFt) return; - for (auto &aggregator : aggregators) aggregator.Aggregate(ns_->items_[properRowId]); - if constexpr (aggregationsOnly) return; +void NsSelecter::addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, SelectCtxWithJoinPreSelect& sctx, + h_vector& aggregators, QueryResults& result, bool preselectForFt) { + if (preselectForFt) { + return; + } + for (auto& aggregator : aggregators) { + aggregator.Aggregate(ns_->items_[properRowId]); + } + if constexpr (aggregationsOnly) { + return; + } // Due to how aggregationsOnly is calculated the aggregators here can either be empty or contain only one value with the Distinct type - if (!aggregators.empty() && !aggregators.front().DistinctChanged()) return; + if (!aggregators.empty() && !aggregators.front().DistinctChanged()) { + return; + } if constexpr (std::is_same_v) { - std::visit(overloaded{[rowId](IdSet &ids) { ids.AddUnordered(rowId); }, - [&](JoinPreResult::Values &values) { + std::visit(overloaded{[rowId](IdSet& ids) { ids.AddUnordered(rowId); }, + [&](JoinPreResult::Values& values) { if (!sctx.sortingContext.expressions.empty()) { values.emplace_back(properRowId, sctx.sortingContext.exprResults[0].size(), proc, sctx.nsid); calculateSortExpressions(proc, rowId, properRowId, sctx, result); @@ -1151,7 +1186,7 @@ void NsSelecter::addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, values.emplace_back(properRowId, ns_->items_[properRowId], proc, sctx.nsid); } }, - [](const SelectIteratorContainer &) { throw_as_assert; }}, + [](const SelectIteratorContainer&) { throw_as_assert; }}, sctx.preSelect.Result().payload); } else { if (!sctx.sortingContext.expressions.empty()) { @@ -1170,9 +1205,11 @@ void NsSelecter::addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, } } -void NsSelecter::checkStrictModeAgg(StrictMode strictMode, const std::string &name, const std::string &nsName, - const TagsMatcher &tagsMatcher) const { - if (int index = IndexValueType::SetByJsonPath; ns_->tryGetIndexByName(name, index)) return; +void NsSelecter::checkStrictModeAgg(StrictMode strictMode, const std::string& name, const std::string& nsName, + const TagsMatcher& tagsMatcher) const { + if (int index = IndexValueType::SetByJsonPath; ns_->tryGetIndexByName(name, index)) { + return; + } if (strictMode == StrictModeIndexes) { throw Error(errParams, @@ -1189,12 +1226,12 @@ void NsSelecter::checkStrictModeAgg(StrictMode strictMode, const std::string &na } } -h_vector NsSelecter::getAggregators(const std::vector &aggEntries, StrictMode strictMode) const { +h_vector NsSelecter::getAggregators(const std::vector& aggEntries, StrictMode strictMode) const { static constexpr int NotFilled = -2; h_vector ret; h_vector distinctIndexes; - for (const auto &ag : aggEntries) { + for (const auto& ag : aggEntries) { if (ag.Type() == AggCount || ag.Type() == AggCountCached) { continue; } @@ -1203,7 +1240,7 @@ h_vector NsSelecter::getAggregators(const std::vector sortingEntries; sortingEntries.reserve(ag.Sorting().size()); - for (const auto &s : ag.Sorting()) { + for (const auto& s : ag.Sorting()) { sortingEntries.push_back({(iequals("count"sv, s.expression) ? Aggregator::SortingEntry::Count : NotFilled), s.desc}); } int idx = -1; @@ -1239,14 +1276,20 @@ h_vector NsSelecter::getAggregators(const std::vectorpayloadType_, fields, ag.Type(), ag.Fields(), sortingEntries, ag.Limit(), ag.Offset(), compositeIndexFields); } - if (distinctIndexes.size() <= 1) return ret; - for (const Aggregator &agg : ret) { - if (agg.Type() == AggDistinct) continue; - for (const std::string &name : agg.Names()) { + if (distinctIndexes.size() <= 1) { + return ret; + } + for (const Aggregator& agg : ret) { + if (agg.Type() == AggDistinct) { + continue; + } + for (const std::string& name : agg.Names()) { if (std::find_if(distinctIndexes.cbegin(), distinctIndexes.cend(), [&ret, &name](size_t idx) { return ret[idx].Names()[0] == name; }) == distinctIndexes.cend()) { throw Error(errQueryExec, "Cannot be combined several distinct and non distinct aggregator on index %s", name); @@ -1257,7 +1300,7 @@ h_vector NsSelecter::getAggregators(const std::vector &joinedSelectors, bool &skipSortingEntry, StrictMode strictMode) { +void NsSelecter::prepareSortJoinedIndex(size_t nsIdx, std::string_view column, int& index, + const std::vector& joinedSelectors, bool& skipSortingEntry, StrictMode strictMode) { assertrx_throw(!column.empty()); index = IndexValueType::SetByJsonPath; assertrx_throw(nsIdx < joinedSelectors.size()); - const auto &js = joinedSelectors[nsIdx]; - std::visit(overloaded{[](const JoinPreResult::Values &values) noexcept -> const PayloadType & { return values.payloadType; }, + const auto& js = joinedSelectors[nsIdx]; + std::visit(overloaded{[](const JoinPreResult::Values& values) noexcept -> const PayloadType& { return values.payloadType; }, Restricted{}( - [&js](const auto &) noexcept -> const PayloadType & { return js.rightNs_->payloadType_; })}, + [&js](const auto&) noexcept -> const PayloadType& { return js.rightNs_->payloadType_; })}, js.PreResult().payload) .FieldByName(std::string{column}, index); if (index == IndexValueType::SetByJsonPath) { skipSortingEntry |= !validateField( strictMode, column, js.joinQuery_.NsName(), - std::visit(overloaded{[](const JoinPreResult::Values &values) noexcept -> const TagsMatcher & { return values.tagsMatcher; }, + std::visit(overloaded{[](const JoinPreResult::Values& values) noexcept -> const TagsMatcher& { return values.tagsMatcher; }, Restricted{}( - [&js](const auto &) noexcept -> const TagsMatcher & { return js.rightNs_->tagsMatcher_; })}, + [&js](const auto&) noexcept -> const TagsMatcher& { return js.rightNs_->tagsMatcher_; })}, js.PreResult().payload)); } } -bool NsSelecter::validateField(StrictMode strictMode, std::string_view name, std::string_view nsName, const TagsMatcher &tagsMatcher) { +bool NsSelecter::validateField(StrictMode strictMode, std::string_view name, std::string_view nsName, const TagsMatcher& tagsMatcher) { if (strictMode == StrictModeIndexes) { throw Error(errParams, "Current query strict mode allows sort by index fields only. There are no indexes with name '%s' in namespace '%s'", @@ -1309,21 +1352,21 @@ bool NsSelecter::validateField(StrictMode strictMode, std::string_view name, std return true; } -static void removeQuotesFromExpression(std::string &expression) { +static void removeQuotesFromExpression(std::string& expression) { expression.erase(std::remove(expression.begin(), expression.end(), '"'), expression.end()); } -void NsSelecter::prepareSortingContext(SortingEntries &sortBy, SelectCtx &ctx, bool isFt, bool availableSelectBySortIndex) { +void NsSelecter::prepareSortingContext(SortingEntries& sortBy, SelectCtx& ctx, bool isFt, bool availableSelectBySortIndex) { using namespace SortExprFuncs; const auto strictMode = ctx.inTransaction ? StrictModeNone : ((ctx.query.GetStrictMode() == StrictModeNotSet) ? ns_->config_.strictMode : ctx.query.GetStrictMode()); static const JoinedSelectors emptyJoinedSelectors; - const auto &joinedSelectors = ctx.joinedSelectors ? *ctx.joinedSelectors : emptyJoinedSelectors; + const auto& joinedSelectors = ctx.joinedSelectors ? *ctx.joinedSelectors : emptyJoinedSelectors; ctx.sortingContext.entries.clear(); ctx.sortingContext.expressions.clear(); for (size_t i = 0; i < sortBy.size(); ++i) { - SortingEntry &sortingEntry(sortBy[i]); + SortingEntry& sortingEntry(sortBy[i]); assertrx_throw(!sortingEntry.expression.empty()); SortExpression expr{SortExpression::Parse(sortingEntry.expression, joinedSelectors)}; if (expr.ByIndexField()) { @@ -1332,7 +1375,7 @@ void NsSelecter::prepareSortingContext(SortingEntries &sortBy, SelectCtx &ctx, b sortingEntry.index = IndexValueType::SetByJsonPath; ns_->getIndexByNameOrJsonPath(sortingEntry.expression, sortingEntry.index); if (sortingEntry.index >= 0) { - reindexer::Index *sortIndex = ns_->indexes_[sortingEntry.index].get(); + reindexer::Index* sortIndex = ns_->indexes_[sortingEntry.index].get(); entry.index = sortIndex; entry.rawData = SortingContext::RawDataParams(sortIndex->ColumnData(), ns_->payloadType_, sortingEntry.index); entry.opts = &sortIndex->Opts().collateOpts_; @@ -1356,9 +1399,9 @@ void NsSelecter::prepareSortingContext(SortingEntries &sortBy, SelectCtx &ctx, b } ctx.sortingContext.entries.emplace_back(std::move(entry)); } else if (expr.ByJoinedIndexField()) { - const auto &je{expr.GetJoinedIndex()}; + const auto& je{expr.GetJoinedIndex()}; SortingContext::JoinedFieldEntry entry{sortingEntry, je.nsIdx, je.column, IndexValueType::SetByJsonPath}; - const auto &js = joinedSelectors[entry.nsIdx]; + const auto& js = joinedSelectors[entry.nsIdx]; assertrx_throw(!std::holds_alternative(js.PreResult().payload)); bool skip{false}; prepareSortIndex(*js.RightNs(), entry.field, entry.index, skip, strictMode); @@ -1373,45 +1416,45 @@ void NsSelecter::prepareSortingContext(SortingEntries &sortBy, SelectCtx &ctx, b struct { bool skipSortingEntry; StrictMode strictMode; - const JoinedSelectors &joinedSelectors; + const JoinedSelectors& joinedSelectors; } lCtx{false, strictMode, joinedSelectors}; expr.VisitForEach( Skip{}, - [this, &lCtx](SortExprFuncs::Index &exprIndex) { + [this, &lCtx](SortExprFuncs::Index& exprIndex) { prepareSortIndex(*ns_, exprIndex.column, exprIndex.index, lCtx.skipSortingEntry, lCtx.strictMode); }, - [&lCtx](JoinedIndex &exprIndex) { + [&lCtx](JoinedIndex& exprIndex) { prepareSortJoinedIndex(exprIndex.nsIdx, exprIndex.column, exprIndex.index, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); }, - [isFt](Rank &) { + [isFt](Rank&) { if (!isFt) { throw Error(errLogic, "Sorting by rank() is only available for full-text query"); } }, - [this, &lCtx](DistanceFromPoint &exprIndex) { + [this, &lCtx](DistanceFromPoint& exprIndex) { prepareSortIndex(*ns_, exprIndex.column, exprIndex.index, lCtx.skipSortingEntry, lCtx.strictMode); }, - [&lCtx](DistanceJoinedIndexFromPoint &exprIndex) { + [&lCtx](DistanceJoinedIndexFromPoint& exprIndex) { prepareSortJoinedIndex(exprIndex.nsIdx, exprIndex.column, exprIndex.index, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); }, - [this, &lCtx](DistanceBetweenIndexes &exprIndex) { + [this, &lCtx](DistanceBetweenIndexes& exprIndex) { prepareSortIndex(*ns_, exprIndex.column1, exprIndex.index1, lCtx.skipSortingEntry, lCtx.strictMode); prepareSortIndex(*ns_, exprIndex.column2, exprIndex.index2, lCtx.skipSortingEntry, lCtx.strictMode); }, - [this, &lCtx](DistanceBetweenIndexAndJoinedIndex &exprIndex) { + [this, &lCtx](DistanceBetweenIndexAndJoinedIndex& exprIndex) { prepareSortIndex(*ns_, exprIndex.column, exprIndex.index, lCtx.skipSortingEntry, lCtx.strictMode); prepareSortJoinedIndex(exprIndex.jNsIdx, exprIndex.jColumn, exprIndex.jIndex, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); }, - [&lCtx](DistanceBetweenJoinedIndexes &exprIndex) { + [&lCtx](DistanceBetweenJoinedIndexes& exprIndex) { prepareSortJoinedIndex(exprIndex.nsIdx1, exprIndex.column1, exprIndex.index1, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); prepareSortJoinedIndex(exprIndex.nsIdx2, exprIndex.column2, exprIndex.index2, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); }, - [&lCtx](DistanceBetweenJoinedIndexesSameNs &exprIndex) { + [&lCtx](DistanceBetweenJoinedIndexesSameNs& exprIndex) { prepareSortJoinedIndex(exprIndex.nsIdx, exprIndex.column1, exprIndex.index1, lCtx.joinedSelectors, lCtx.skipSortingEntry, lCtx.strictMode); prepareSortJoinedIndex(exprIndex.nsIdx, exprIndex.column2, exprIndex.index2, lCtx.joinedSelectors, @@ -1453,7 +1496,7 @@ class CostCalculator { curCost_ = 0; } bool IsInOrSequence() const noexcept { return isInSequence_; } - void Add(const SelectKeyResults &results, bool isTargetSortIndex) noexcept { + void Add(const SelectKeyResults& results, bool isTargetSortIndex) noexcept { if constexpr (countingPolicy == CostCountingPolicy::ExceptTargetSortIdxSeq) { if (!isInSequence_ && isTargetSortIndex) { return; @@ -1462,10 +1505,10 @@ class CostCalculator { onlyTargetSortIdxInSequence_ = onlyTargetSortIdxInSequence_ && isTargetSortIndex; Add(results); } - void Add(const SelectKeyResults &results) noexcept { + void Add(const SelectKeyResults& results) noexcept { std::visit( - overloaded{[this](const SelectKeyResultsVector &selRes) { - for (const SelectKeyResult &res : selRes) { + overloaded{[this](const SelectKeyResultsVector& selRes) { + for (const SelectKeyResult& res : selRes) { if (isInSequence_) { curCost_ += res.GetMaxIterations(totalCost_); } else { @@ -1481,7 +1524,7 @@ class CostCalculator { } size_t TotalCost() const noexcept { return totalCost_; } void MarkInapposite() noexcept { hasInappositeEntries_ = true; } - bool OnNewEntry(const QueryEntries &qentries, size_t i, size_t next) { + bool OnNewEntry(const QueryEntries& qentries, size_t i, size_t next) { const OpType op = qentries.GetOperation(i); switch (op) { case OpAnd: { @@ -1519,7 +1562,7 @@ class CostCalculator { size_t totalCost_ = std::numeric_limits::max(); }; -size_t NsSelecter::calculateNormalCost(const QueryEntries &qentries, SelectCtx &ctx, const RdxContext &rdxCtx) { +size_t NsSelecter::calculateNormalCost(const QueryEntries& qentries, SelectCtx& ctx, const RdxContext& rdxCtx) { const size_t totalItemsCount = ns_->itemsCount(); CostCalculator costCalculator(totalItemsCount); enum { SortIndexNotFound = 0, SortIndexFound, SortIndexHasUnorderedConditions } sortIndexSearchState = SortIndexNotFound; @@ -1527,16 +1570,16 @@ size_t NsSelecter::calculateNormalCost(const QueryEntries &qentries, SelectCtx & next = qentries.Next(i); const bool calculateEntry = costCalculator.OnNewEntry(qentries, i, next); qentries.Visit( - i, [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry &) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry &) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, + i, [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry&) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, Skip{}, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket &) + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry &) + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry &) + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&](const QueryEntry &qe) { + [&](const QueryEntry& qe) { if (!qe.IsFieldIndexed()) { costCalculator.MarkInapposite(); return; @@ -1563,7 +1606,7 @@ size_t NsSelecter::calculateNormalCost(const QueryEntries &qentries, SelectCtx & return; } - auto &index = ns_->indexes_[qe.IndexNo()]; + auto& index = ns_->indexes_[qe.IndexNo()]; if (IsFullText(index->Type())) { costCalculator.MarkInapposite(); return; @@ -1578,7 +1621,7 @@ size_t NsSelecter::calculateNormalCost(const QueryEntries &qentries, SelectCtx & try { SelectKeyResults results = index->SelectKey(qe.Values(), qe.Condition(), 0, opts, nullptr, rdxCtx); costCalculator.Add(results, qe.IndexNo() == ctx.sortingContext.uncommitedIndex); - } catch (const Error &) { + } catch (const Error&) { costCalculator.MarkInapposite(); } }); @@ -1591,7 +1634,7 @@ size_t NsSelecter::calculateNormalCost(const QueryEntries &qentries, SelectCtx & return costCalculator.TotalCost(); } -size_t NsSelecter::calculateOptimizedCost(size_t costNormal, const QueryEntries &qentries, SelectCtx &ctx, const RdxContext &rdxCtx) { +size_t NsSelecter::calculateOptimizedCost(size_t costNormal, const QueryEntries& qentries, SelectCtx& ctx, const RdxContext& rdxCtx) { // 'costOptimized == costNormal + 1' reduces internal iterations count for the tree in the res.GetMaxIterations() call CostCalculator costCalculator(costNormal + 1); for (size_t next, i = 0, sz = qentries.Size(); i != sz; i = next) { @@ -1601,15 +1644,15 @@ size_t NsSelecter::calculateOptimizedCost(size_t costNormal, const QueryEntries } qentries.Visit( i, Skip{}, - [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry &) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry &) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket &) + [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry&) RX_POST_LMBD_ALWAYS_INLINE { throw_as_assert; }, + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry &) + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry &) + [&costCalculator] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE noexcept { costCalculator.MarkInapposite(); }, - [&](const QueryEntry &qe) { + [&](const QueryEntry& qe) { if (!qe.IsFieldIndexed() || qe.IndexNo() != ctx.sortingContext.uncommitedIndex) { costCalculator.MarkInapposite(); return; @@ -1626,7 +1669,7 @@ size_t NsSelecter::calculateOptimizedCost(size_t costNormal, const QueryEntries SelectKeyResults results = ns_->indexes_[qe.IndexNo()]->SelectKey(qe.Values(), qe.Condition(), 0, opts, nullptr, rdxCtx); costCalculator.Add(results); - } catch (const Error &) { + } catch (const Error&) { costCalculator.MarkInapposite(); } }); @@ -1635,12 +1678,12 @@ size_t NsSelecter::calculateOptimizedCost(size_t costNormal, const QueryEntries return costCalculator.TotalCost(); } -bool NsSelecter::isSortOptimizationEffective(const QueryEntries &qentries, SelectCtx &ctx, const RdxContext &rdxCtx) { +bool NsSelecter::isSortOptimizationEffective(const QueryEntries& qentries, SelectCtx& ctx, const RdxContext& rdxCtx) { if (qentries.Size() == 0) { return true; } if (qentries.Size() == 1 && qentries.Is(0)) { - const auto &qe = qentries.Get(0); + const auto& qe = qentries.Get(0); if (qe.IndexNo() == ctx.sortingContext.uncommitedIndex) { return SelectIteratorContainer::IsExpectingOrderedResults(qe); } @@ -1681,14 +1724,14 @@ bool NsSelecter::isSortOptimizationEffective(const QueryEntries &qentries, Selec return costOptimized <= costNormal; } -void NsSelecter::writeAggregationResultMergeSubQuery(QueryResults &result, h_vector &aggregators, SelectCtx &ctx) { +void NsSelecter::writeAggregationResultMergeSubQuery(QueryResults& result, h_vector& aggregators, SelectCtx& ctx) { if (result.aggregationResults.size() < aggregators.size()) { throw Error(errQueryExec, "Merged query(%s) aggregators count (%d) does not match to the parent query aggregations (%d)", ctx.query.GetSQL(false), aggregators.size(), result.aggregationResults.size()); } for (size_t i = 0; i < aggregators.size(); i++) { AggregationResult r = aggregators[i].GetResult(); - AggregationResult &parentRes = result.aggregationResults[i]; + AggregationResult& parentRes = result.aggregationResults[i]; if (r.type != parentRes.type || r.fields != parentRes.fields) { std::stringstream strParentRes; std::stringstream strR; @@ -1740,13 +1783,13 @@ void NsSelecter::writeAggregationResultMergeSubQuery(QueryResults &result, h_vec } } -RX_NO_INLINE void NsSelecter::throwIncorrectRowIdInSortOrders(int rowId, const Index &firstSortIndex, const SelectIterator &firstIterator) { +RX_NO_INLINE void NsSelecter::throwIncorrectRowIdInSortOrders(int rowId, const Index& firstSortIndex, const SelectIterator& firstIterator) { throw Error(errLogic, "FirstIterator: %s, firstSortIndex: %s, firstSortIndex size: %d, rowId: %d", firstIterator.name, firstSortIndex.Name(), static_cast(firstSortIndex.SortOrders().size()), rowId); } -template void NsSelecter::operator()(QueryResults &, SelectCtxWithJoinPreSelect &, const RdxContext &); -template void NsSelecter::operator()(QueryResults &, SelectCtxWithJoinPreSelect &, const RdxContext &); -template void NsSelecter::operator()(QueryResults &, SelectCtxWithJoinPreSelect &, const RdxContext &); +template void NsSelecter::operator()(QueryResults&, SelectCtxWithJoinPreSelect&, const RdxContext&); +template void NsSelecter::operator()(QueryResults&, SelectCtxWithJoinPreSelect&, const RdxContext&); +template void NsSelecter::operator()(QueryResults&, SelectCtxWithJoinPreSelect&, const RdxContext&); } // namespace reindexer diff --git a/cpp_src/core/nsselecter/nsselecter.h b/cpp_src/core/nsselecter/nsselecter.h index 487a1b901..0a1a1d2ec 100644 --- a/cpp_src/core/nsselecter/nsselecter.h +++ b/cpp_src/core/nsselecter/nsselecter.h @@ -11,10 +11,10 @@ enum class IsMergeQuery : bool { Yes = true, No = false }; enum class IsFTQuery { Yes, No, NotSet }; struct SelectCtx { - explicit SelectCtx(const Query &query_, const Query *parentQuery_) noexcept : query(query_), parentQuery(parentQuery_) {} - const Query &query; - JoinedSelectors *joinedSelectors = nullptr; - SelectFunctionsHolder *functions = nullptr; + explicit SelectCtx(const Query& query_, const Query* parentQuery_) noexcept : query(query_), parentQuery(parentQuery_) {} + const Query& query; + JoinedSelectors* joinedSelectors = nullptr; + SelectFunctionsHolder* functions = nullptr; ExplainCalc::Duration preResultTimeTotal = ExplainCalc::Duration::zero(); SortingContext sortingContext; @@ -29,7 +29,7 @@ struct SelectCtx { IsFTQuery isFtQuery = IsFTQuery::NotSet; QueryType crashReporterQueryType = QuerySelect; - const Query *parentQuery = nullptr; + const Query* parentQuery = nullptr; ExplainCalc explain; bool requiresCrashTracking = false; std::vector subQueriesExplains; @@ -39,16 +39,16 @@ struct SelectCtx { template struct SelectCtxWithJoinPreSelect : public SelectCtx { - explicit SelectCtxWithJoinPreSelect(const Query &query, const Query *parentQuery, JoinPreSelCtx preSel) noexcept + explicit SelectCtxWithJoinPreSelect(const Query& query, const Query* parentQuery, JoinPreSelCtx preSel) noexcept : SelectCtx(query, parentQuery), preSelect{std::move(preSel)} {} JoinPreSelCtx preSelect; }; template <> struct SelectCtxWithJoinPreSelect : public SelectCtx { - explicit SelectCtxWithJoinPreSelect(const Query &query, const Query *parentQuery) noexcept : SelectCtx(query, parentQuery) {} + explicit SelectCtxWithJoinPreSelect(const Query& query, const Query* parentQuery) noexcept : SelectCtx(query, parentQuery) {} }; -SelectCtxWithJoinPreSelect(const Query &, const Query *) -> SelectCtxWithJoinPreSelect; +SelectCtxWithJoinPreSelect(const Query&, const Query*) -> SelectCtxWithJoinPreSelect; class ItemComparator; class ExplainCalc; @@ -60,68 +60,68 @@ class NsSelecter { class JoinedNsValueGetter; public: - NsSelecter(NamespaceImpl *parent) noexcept : ns_(parent) {} + NsSelecter(NamespaceImpl* parent) noexcept : ns_(parent) {} template - void operator()(QueryResults &result, SelectCtxWithJoinPreSelect &ctx, const RdxContext &); + void operator()(QueryResults& result, SelectCtxWithJoinPreSelect& ctx, const RdxContext&); private: template struct LoopCtx { - LoopCtx(SelectIteratorContainer &sIt, SelectCtxWithJoinPreSelect &ctx, const QueryPreprocessor &qpp, - h_vector &agg, ExplainCalc &expl) + LoopCtx(SelectIteratorContainer& sIt, SelectCtxWithJoinPreSelect& ctx, const QueryPreprocessor& qpp, + h_vector& agg, ExplainCalc& expl) : qres(sIt), sctx(ctx), qPreproc(qpp), aggregators(agg), explain(expl) {} - SelectIteratorContainer &qres; + SelectIteratorContainer& qres; bool calcTotal = false; - SelectCtxWithJoinPreSelect &sctx; - const QueryPreprocessor &qPreproc; - h_vector &aggregators; - ExplainCalc &explain; + SelectCtxWithJoinPreSelect& sctx; + const QueryPreprocessor& qPreproc; + h_vector& aggregators; + ExplainCalc& explain; unsigned start = QueryEntry::kDefaultOffset; unsigned count = QueryEntry::kDefaultLimit; bool preselectForFt = false; }; template - void selectLoop(LoopCtx &ctx, ResultsT &result, const RdxContext &); + void selectLoop(LoopCtx& ctx, ResultsT& result, const RdxContext&); template - It applyForcedSort(It begin, It end, const ItemComparator &, const SelectCtx &ctx, const joins::NamespaceResults *); + It applyForcedSort(It begin, It end, const ItemComparator&, const SelectCtx& ctx, const joins::NamespaceResults*); template - static It applyForcedSortImpl(NamespaceImpl &, It begin, It end, const ItemComparator &, const std::vector &forcedSortOrder, - const std::string &fieldName, const ValueGetter &); + static It applyForcedSortImpl(NamespaceImpl&, It begin, It end, const ItemComparator&, const std::vector& forcedSortOrder, + const std::string& fieldName, const ValueGetter&); template - void applyGeneralSort(It itFirst, It itLast, It itEnd, const ItemComparator &, const SelectCtx &ctx); + void applyGeneralSort(It itFirst, It itLast, It itEnd, const ItemComparator&, const SelectCtx& ctx); - void calculateSortExpressions(uint8_t proc, IdType rowId, IdType properRowId, SelectCtx &, const QueryResults &); + void calculateSortExpressions(uint8_t proc, IdType rowId, IdType properRowId, SelectCtx&, const QueryResults&); template - void addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, SelectCtxWithJoinPreSelect &sctx, - h_vector &aggregators, QueryResults &result, bool preselectForFt); - - h_vector getAggregators(const std::vector &aggEntrys, StrictMode strictMode) const; - void setLimitAndOffset(ItemRefVector &result, size_t offset, size_t limit); - void prepareSortingContext(SortingEntries &sortBy, SelectCtx &ctx, bool isFt, bool availableSelectBySortIndex); - static void prepareSortIndex(const NamespaceImpl &, std::string_view column, int &index, bool &skipSortingEntry, StrictMode); - static void prepareSortJoinedIndex(size_t nsIdx, std::string_view column, int &index, const std::vector &, - bool &skipSortingEntry, StrictMode); - void getSortIndexValue(const SortingContext &sortCtx, IdType rowId, VariantArray &value, uint8_t proc, const joins::NamespaceResults *, - const JoinedSelectors &); - void processLeftJoins(QueryResults &qr, SelectCtx &sctx, size_t startPos, const RdxContext &); - bool checkIfThereAreLeftJoins(SelectCtx &sctx) const; + void addSelectResult(uint8_t proc, IdType rowId, IdType properRowId, SelectCtxWithJoinPreSelect& sctx, + h_vector& aggregators, QueryResults& result, bool preselectForFt); + + h_vector getAggregators(const std::vector& aggEntrys, StrictMode strictMode) const; + void setLimitAndOffset(ItemRefVector& result, size_t offset, size_t limit); + void prepareSortingContext(SortingEntries& sortBy, SelectCtx& ctx, bool isFt, bool availableSelectBySortIndex); + static void prepareSortIndex(const NamespaceImpl&, std::string_view column, int& index, bool& skipSortingEntry, StrictMode); + static void prepareSortJoinedIndex(size_t nsIdx, std::string_view column, int& index, const std::vector&, + bool& skipSortingEntry, StrictMode); + void getSortIndexValue(const SortingContext& sortCtx, IdType rowId, VariantArray& value, uint8_t proc, const joins::NamespaceResults*, + const JoinedSelectors&); + void processLeftJoins(QueryResults& qr, SelectCtx& sctx, size_t startPos, const RdxContext&); + bool checkIfThereAreLeftJoins(SelectCtx& sctx) const; template - void sortResults(LoopCtx &sctx, It begin, It end, const SortingOptions &sortingOptions, - const joins::NamespaceResults *); - - size_t calculateNormalCost(const QueryEntries &qe, SelectCtx &ctx, const RdxContext &rdxCtx); - size_t calculateOptimizedCost(size_t costNormal, const QueryEntries &qe, SelectCtx &ctx, const RdxContext &rdxCtx); - bool isSortOptimizationEffective(const QueryEntries &qe, SelectCtx &ctx, const RdxContext &rdxCtx); - static bool validateField(StrictMode strictMode, std::string_view name, std::string_view nsName, const TagsMatcher &tagsMatcher); - void checkStrictModeAgg(StrictMode strictMode, const std::string &name, const std::string &nsName, - const TagsMatcher &tagsMatcher) const; - - void writeAggregationResultMergeSubQuery(QueryResults &result, h_vector &aggregators, SelectCtx &ctx); - [[noreturn]] RX_NO_INLINE void throwIncorrectRowIdInSortOrders(int rowId, const Index &firstSortIndex, - const SelectIterator &firstIterator); - NamespaceImpl *ns_; + void sortResults(LoopCtx& sctx, It begin, It end, const SortingOptions& sortingOptions, + const joins::NamespaceResults*); + + size_t calculateNormalCost(const QueryEntries& qe, SelectCtx& ctx, const RdxContext& rdxCtx); + size_t calculateOptimizedCost(size_t costNormal, const QueryEntries& qe, SelectCtx& ctx, const RdxContext& rdxCtx); + bool isSortOptimizationEffective(const QueryEntries& qe, SelectCtx& ctx, const RdxContext& rdxCtx); + static bool validateField(StrictMode strictMode, std::string_view name, std::string_view nsName, const TagsMatcher& tagsMatcher); + void checkStrictModeAgg(StrictMode strictMode, const std::string& name, const std::string& nsName, + const TagsMatcher& tagsMatcher) const; + + void writeAggregationResultMergeSubQuery(QueryResults& result, h_vector& aggregators, SelectCtx& ctx); + [[noreturn]] RX_NO_INLINE void throwIncorrectRowIdInSortOrders(int rowId, const Index& firstSortIndex, + const SelectIterator& firstIterator); + NamespaceImpl* ns_; SelectFunction::Ptr fnc_; FtCtx::Ptr ft_ctx_; }; diff --git a/cpp_src/core/nsselecter/querypreprocessor.cc b/cpp_src/core/nsselecter/querypreprocessor.cc index 519ae66c4..e4c57e877 100644 --- a/cpp_src/core/nsselecter/querypreprocessor.cc +++ b/cpp_src/core/nsselecter/querypreprocessor.cc @@ -15,7 +15,7 @@ namespace reindexer { -QueryPreprocessor::QueryPreprocessor(QueryEntries &&queries, NamespaceImpl *ns, const SelectCtx &ctx) +QueryPreprocessor::QueryPreprocessor(QueryEntries&& queries, NamespaceImpl* ns, const SelectCtx& ctx) : QueryEntries(std::move(queries)), ns_(*ns), query_{ctx.query}, @@ -29,11 +29,13 @@ QueryPreprocessor::QueryPreprocessor(QueryEntries &&queries, NamespaceImpl *ns, if (forcedSortOrder_ && (start_ > QueryEntry::kDefaultOffset || count_ < QueryEntry::kDefaultLimit)) { assertrx_throw(!query_.sortingEntries_.empty()); static const std::vector emptyJoinedSelectors; - const auto &sEntry = query_.sortingEntries_[0]; + const auto& sEntry = query_.sortingEntries_[0]; if (SortExpression::Parse(sEntry.expression, emptyJoinedSelectors).ByIndexField()) { VariantArray values; values.reserve(query_.forcedSortOrder_.size()); - for (const auto &v : query_.forcedSortOrder_) values.push_back(v); + for (const auto& v : query_.forcedSortOrder_) { + values.push_back(v); + } desc_ = sEntry.desc; QueryField fld{sEntry.expression}; SetQueryField(fld, ns_); @@ -52,14 +54,20 @@ QueryPreprocessor::QueryPreprocessor(QueryEntries &&queries, NamespaceImpl *ns, } } -void QueryPreprocessor::ExcludeFtQuery(const RdxContext &rdxCtx) { - if (queryEntryAddedByForcedSortOptimization_ || Size() <= 1) return; +void QueryPreprocessor::ExcludeFtQuery(const RdxContext& rdxCtx) { + if (queryEntryAddedByForcedSortOptimization_ || Size() <= 1) { + return; + } for (auto it = begin(), next = it, endIt = end(); it != endIt; it = next) { ++next; if (it->Is() && it->Value().IsFieldIndexed()) { - auto &index = ns_.indexes_[it->Value().IndexNo()]; - if (!IsFastFullText(index->Type())) continue; - if (it->operation != OpAnd || (next != endIt && next->operation == OpOr) || !index->EnablePreselectBeforeFt()) break; + auto& index = ns_.indexes_[it->Value().IndexNo()]; + if (!IsFastFullText(index->Type())) { + continue; + } + if (it->operation != OpAnd || (next != endIt && next->operation == OpOr) || !index->EnablePreselectBeforeFt()) { + break; + } ftPreselect_ = index->FtPreselect(rdxCtx); start_ = QueryEntry::kDefaultOffset; count_ = QueryEntry::kDefaultLimit; @@ -72,9 +80,11 @@ void QueryPreprocessor::ExcludeFtQuery(const RdxContext &rdxCtx) { } } -bool QueryPreprocessor::NeedNextEvaluation(unsigned start, unsigned count, bool &matchedAtLeastOnce, - QresExplainHolder &qresHolder) noexcept { - if (evaluationsCount_++) return false; +bool QueryPreprocessor::NeedNextEvaluation(unsigned start, unsigned count, bool& matchedAtLeastOnce, + QresExplainHolder& qresHolder) noexcept { + if (evaluationsCount_++) { + return false; + } if (queryEntryAddedByForcedSortOptimization_) { container_.back().operation = desc_ ? OpAnd : OpNot; assertrx_throw(start <= start_); @@ -83,7 +93,9 @@ bool QueryPreprocessor::NeedNextEvaluation(unsigned start, unsigned count, bool count_ = count; return count_ || (reqMatchedOnce_ && !matchedAtLeastOnce); } else if (ftEntry_) { - if (!matchedAtLeastOnce) return false; + if (!matchedAtLeastOnce) { + return false; + } qresHolder.BackupContainer(); if (isMergeQuery_) { if (QueryEntry::kDefaultLimit - query_.Offset() > query_.Limit()) { @@ -107,8 +119,10 @@ bool QueryPreprocessor::NeedNextEvaluation(unsigned start, unsigned count, bool return false; } -void QueryPreprocessor::checkStrictMode(const QueryField &field) const { - if (field.IsFieldIndexed()) return; +void QueryPreprocessor::checkStrictMode(const QueryField& field) const { + if (field.IsFieldIndexed()) { + return; + } switch (strictMode_) { case StrictModeIndexes: throw Error(errQueryExec, @@ -130,8 +144,8 @@ void QueryPreprocessor::checkStrictMode(const QueryField &field) const { class JoinOnExplainEnabled; class JoinOnExplainDisabled; -int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to, int maxMaxIters, span &maxIterations, - bool inTransaction, bool enableSortOrders, const RdxContext &rdxCtx) const { +int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to, int maxMaxIters, span& maxIterations, + bool inTransaction, bool enableSortOrders, const RdxContext& rdxCtx) const { int res = maxMaxIters; int current = maxMaxIters; for (size_t cur = from; cur < to; cur = Next(cur)) { @@ -139,12 +153,12 @@ int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to maxMaxIters, Visit( cur, - [&](const QueryEntriesBracket &) { + [&](const QueryEntriesBracket&) { return calculateMaxIterations(cur + 1, Next(cur), maxMaxIters, maxIterations, inTransaction, enableSortOrders, rdxCtx); }, - [&](const QueryEntry &qe) { + [&](const QueryEntry& qe) { if (qe.IndexNo() >= 0) { - Index &index = *ns_.indexes_[qe.IndexNo()]; + Index& index = *ns_.indexes_[qe.IndexNo()]; if (IsFullText(index.Type()) || isStore(index.Type())) { return maxMaxIters; } @@ -157,9 +171,9 @@ int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to opts.inTransaction = inTransaction; const auto selIters = index.SelectKey(qe.Values(), qe.Condition(), 0, opts, nullptr, rdxCtx); - if (auto *selRes = std::get_if(&selIters); selRes) { + if (auto* selRes = std::get_if(&selIters); selRes) { int res = 0; - for (const auto &sIt : *selRes) { + for (const auto& sIt : *selRes) { res += sIt.GetMaxIterations(); } return res; @@ -169,10 +183,10 @@ int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to return maxMaxIters; } }, - [maxMaxIters](const BetweenFieldsQueryEntry &) noexcept { return maxMaxIters; }, - [maxMaxIters](const JoinQueryEntry &) noexcept { return maxMaxIters; }, - [](const SubQueryEntry &) -> int { throw_as_assert; }, [](const SubQueryFieldEntry &) -> int { throw_as_assert; }, - [maxMaxIters](const AlwaysTrue &) noexcept { return maxMaxIters; }, [&](const AlwaysFalse &) noexcept { return 0; })); + [maxMaxIters](const BetweenFieldsQueryEntry&) noexcept { return maxMaxIters; }, + [maxMaxIters](const JoinQueryEntry&) noexcept { return maxMaxIters; }, [](const SubQueryEntry&) -> int { throw_as_assert; }, + [](const SubQueryFieldEntry&) -> int { throw_as_assert; }, + [maxMaxIters](const AlwaysTrue&) noexcept { return maxMaxIters; }, [&](const AlwaysFalse&) noexcept { return 0; })); switch (GetOperation(cur)) { case OpAnd: res = std::min(res, current); @@ -195,8 +209,8 @@ int QueryPreprocessor::calculateMaxIterations(const size_t from, const size_t to return res; } -void QueryPreprocessor::InjectConditionsFromJoins(JoinedSelectors &js, OnConditionInjections &expalainOnInjections, LogLevel logLevel, - bool inTransaction, bool enableSortOrders, const RdxContext &rdxCtx) { +void QueryPreprocessor::InjectConditionsFromJoins(JoinedSelectors& js, OnConditionInjections& expalainOnInjections, LogLevel logLevel, + bool inTransaction, bool enableSortOrders, const RdxContext& rdxCtx) { h_vector maxIterations(Size()); span maxItersSpan(maxIterations.data(), maxIterations.size()); const int maxIters = calculateMaxIterations(0, Size(), ns_.itemsCount(), maxItersSpan, inTransaction, enableSortOrders, rdxCtx); @@ -263,11 +277,11 @@ bool QueryPreprocessor::removeAlwaysTrue() { bool QueryPreprocessor::containsJoin(size_t n) noexcept { return Visit( - n, [](const JoinQueryEntry &) noexcept { return true; }, [](const QueryEntry &) noexcept { return false; }, - [](const BetweenFieldsQueryEntry &) noexcept { return false; }, [](const AlwaysTrue &) noexcept { return false; }, - [](const AlwaysFalse &) noexcept { return false; }, [](const SubQueryEntry &) noexcept { return false; }, - [](const SubQueryFieldEntry &) noexcept { return false; }, - [&](const QueryEntriesBracket &) noexcept { + n, [](const JoinQueryEntry&) noexcept { return true; }, [](const QueryEntry&) noexcept { return false; }, + [](const BetweenFieldsQueryEntry&) noexcept { return false; }, [](const AlwaysTrue&) noexcept { return false; }, + [](const AlwaysFalse&) noexcept { return false; }, [](const SubQueryEntry&) noexcept { return false; }, + [](const SubQueryFieldEntry&) noexcept { return false; }, + [&](const QueryEntriesBracket&) noexcept { for (size_t i = n, e = Next(n); i < e; ++i) { if (Is(i)) { return true; @@ -362,7 +376,9 @@ void QueryPreprocessor::Reduce(bool isFt) { changed = LookupQueryIndexes() || changed; changed = removeAlwaysFalse() || changed; changed = removeAlwaysTrue() || changed; - if (!isFt) changed = SubstituteCompositeIndexes() || changed; + if (!isFt) { + changed = SubstituteCompositeIndexes() || changed; + } } while (changed); } @@ -374,8 +390,12 @@ bool QueryPreprocessor::canRemoveBracket(size_t i) const { } const size_t next = Next(i); const OpType op = GetOperation(i); - if (op != OpAnd && GetOperation(i + 1) != OpAnd) return false; - if (next == Next(i + 1)) return true; + if (op != OpAnd && GetOperation(i + 1) != OpAnd) { + return false; + } + if (next == Next(i + 1)) { + return true; + } return op == OpAnd && (next == Size() || GetOperation(next) != OpOr); } @@ -385,7 +405,9 @@ size_t QueryPreprocessor::removeBrackets(size_t begin, size_t end) { } size_t deleted = 0; for (size_t i = begin; i < end - deleted; i = Next(i)) { - if (!IsSubTree(i)) continue; + if (!IsSubTree(i)) { + continue; + } deleted += removeBrackets(i + 1, Next(i)); if (canRemoveBracket(i)) { if (const OpType op = GetOperation(i); op != OpAnd) { @@ -405,16 +427,17 @@ size_t QueryPreprocessor::lookupQueryIndexes(uint16_t dst, uint16_t srcBegin, ui for (size_t src = srcBegin, nextSrc; src < srcEnd; src = nextSrc) { nextSrc = Next(src); const auto mergeResult = container_[src].Visit( - [](const SubQueryEntry &) -> MergeResult { throw_as_assert; }, - [](const SubQueryFieldEntry &) -> MergeResult { throw_as_assert; }, - [&](const QueryEntriesBracket &) { - if (dst != src) container_[dst] = std::move(container_[src]); + [](const SubQueryEntry&) -> MergeResult { throw_as_assert; }, [](const SubQueryFieldEntry&) -> MergeResult { throw_as_assert; }, + [&](const QueryEntriesBracket&) { + if (dst != src) { + container_[dst] = std::move(container_[src]); + } const size_t mergedInBracket = lookupQueryIndexes(dst + 1, src + 1, nextSrc); container_[dst].Value().Erase(mergedInBracket); merged += mergedInBracket; return MergeResult::NotMerged; }, - [&](QueryEntry &entry) { + [&](QueryEntry& entry) { if (entry.IsFieldIndexed()) { // try to merge entries with AND operator if ((GetOperation(src) == OpAnd) && (nextSrc >= srcEnd || GetOperation(nextSrc) != OpOr)) { @@ -423,9 +446,9 @@ size_t QueryPreprocessor::lookupQueryIndexes(uint16_t dst, uint16_t srcBegin, ui iidx.resize(entry.IndexNo() + 1); std::fill(iidx.begin() + oldSize, iidx.begin() + iidx.size(), 0); } - auto &iidxRef = iidx[entry.IndexNo()]; - const Index &index = *ns_.indexes_[entry.IndexNo()]; - const auto &indexOpts = index.Opts(); + auto& iidxRef = iidx[entry.IndexNo()]; + const Index& index = *ns_.indexes_[entry.IndexNo()]; + const auto& indexOpts = index.Opts(); if (iidxRef > 0 && !indexOpts.IsArray()) { const auto orderedFlag = index.IsOrdered() ? MergeOrdered::Yes : MergeOrdered::No; const auto mergeRes = IsComposite(index.Type()) @@ -449,23 +472,33 @@ size_t QueryPreprocessor::lookupQueryIndexes(uint16_t dst, uint16_t srcBegin, ui } } } - if (dst != src) container_[dst] = std::move(container_[src]); + if (dst != src) { + container_[dst] = std::move(container_[src]); + } return MergeResult::NotMerged; }, - [dst, src, this](const JoinQueryEntry &) { - if (dst != src) container_[dst] = std::move(container_[src]); + [dst, src, this](const JoinQueryEntry&) { + if (dst != src) { + container_[dst] = std::move(container_[src]); + } return MergeResult::NotMerged; }, - [dst, src, this](const BetweenFieldsQueryEntry &) { - if (dst != src) container_[dst] = std::move(container_[src]); + [dst, src, this](const BetweenFieldsQueryEntry&) { + if (dst != src) { + container_[dst] = std::move(container_[src]); + } return MergeResult::NotMerged; }, - [dst, src, this](const AlwaysFalse &) { - if (dst != src) container_[dst] = std::move(container_[src]); + [dst, src, this](const AlwaysFalse&) { + if (dst != src) { + container_[dst] = std::move(container_[src]); + } return MergeResult::NotMerged; }, - [dst, src, this](const AlwaysTrue &) { - if (dst != src) container_[dst] = std::move(container_[src]); + [dst, src, this](const AlwaysTrue&) { + if (dst != src) { + container_[dst] = std::move(container_[src]); + } return MergeResult::NotMerged; }); switch (mergeResult) { @@ -485,8 +518,8 @@ void QueryPreprocessor::CheckUniqueFtQuery() const { bool found = false; VisitForEach( Skip{}, - [](const SubQueryEntry &) { throw_as_assert; }, [](const SubQueryFieldEntry &) { throw_as_assert; }, - [&](const QueryEntry &qe) { + [](const SubQueryEntry&) { throw_as_assert; }, [](const SubQueryFieldEntry&) { throw_as_assert; }, + [&](const QueryEntry& qe) { if (qe.IsFieldIndexed() && IsFullText(ns_.indexes_[qe.IndexNo()]->Type())) { if (found) { throw Error{errQueryExec, "Query cannot contain more than one full text condition"}; @@ -507,16 +540,16 @@ bool QueryPreprocessor::ContainsFullTextIndexes() const { return false; } -const std::vector *QueryPreprocessor::getCompositeIndex(int field) const noexcept { +const std::vector* QueryPreprocessor::getCompositeIndex(int field) const noexcept { if (auto f = ns_.indexesToComposites_.find(field); f != ns_.indexesToComposites_.end()) { return &f->second; } return nullptr; } -static void createCompositeKeyValues(span> values, Payload &pl, VariantArray &ret, +static void createCompositeKeyValues(span> values, Payload& pl, VariantArray& ret, uint32_t resultSetSize, uint32_t n) { - const auto &v = values[n]; + const auto& v = values[n]; for (auto it = v.second.cbegin(), end = v.second.cend(); it != end; ++it) { pl.Set(v.first, *it); if (n + 1 < values.size()) { @@ -531,7 +564,7 @@ static void createCompositeKeyValues(span> va } } -static VariantArray createCompositeKeyValues(span> values, const PayloadType &plType, +static VariantArray createCompositeKeyValues(span> values, const PayloadType& plType, uint32_t resultSetSize) { PayloadValue d(plType.TotalSize()); Payload pl(plType, d); @@ -551,7 +584,7 @@ size_t QueryPreprocessor::substituteCompositeIndexes(const size_t from, const si CompositeSearcher searcher(ns_); for (size_t cur = from, end = to; cur < end; cur = Next(cur), end = to - deleted) { if (IsSubTree(cur)) { - const auto &bracket = Get(cur); + const auto& bracket = Get(cur); auto bracketSize = bracket.Size(); deleted += substituteCompositeIndexes(cur + 1, cur + bracketSize); continue; @@ -563,13 +596,13 @@ size_t QueryPreprocessor::substituteCompositeIndexes(const size_t from, const si if ((next < end && GetOperation(next) == OpOr)) { continue; } - auto &qe = Get(cur); + auto& qe = Get(cur); if ((qe.Condition() != CondEq && qe.Condition() != CondSet) || !qe.IsFieldIndexed() || qe.IndexNo() >= ns_.payloadType_.NumFields()) { continue; } - const std::vector *found = getCompositeIndex(qe.IndexNo()); + const std::vector* found = getCompositeIndex(qe.IndexNo()); if (!found || found->empty()) { continue; } @@ -580,12 +613,12 @@ size_t QueryPreprocessor::substituteCompositeIndexes(const size_t from, const si h_vector, 4> values; auto resIdx = searcher.GetResult(); while (resIdx >= 0) { - auto &res = searcher[resIdx]; + auto& res = searcher[resIdx]; values.clear(); uint32_t resultSetSize = 1; uint32_t maxSetSize = 0; for (auto i : res.entries) { - auto &qe = Get(i); + auto& qe = Get(i); if rx_unlikely (!res.fields.contains(qe.IndexNo())) { throw Error(errLogic, "Error during composite index's fields substitution (this should not happen)"); } @@ -603,7 +636,7 @@ size_t QueryPreprocessor::substituteCompositeIndexes(const size_t from, const si } } for (auto i : res.entries) { - auto &qe = Get(i); + auto& qe = Get(i); qe.ConvertValuesToFieldType(); const int idxNo = qe.IndexNo(); values.emplace_back(idxNo, std::move(qe).Values()); @@ -629,10 +662,10 @@ size_t QueryPreprocessor::substituteCompositeIndexes(const size_t from, const si void QueryPreprocessor::initIndexedQueries(size_t begin, size_t end) { for (auto cur = begin; cur != end; cur = Next(cur)) { Visit( - cur, Skip{}, [](const SubQueryEntry &) { throw_as_assert; }, - [](const SubQueryFieldEntry &) { throw_as_assert; }, - [this, cur](const QueryEntriesBracket &) { initIndexedQueries(cur + 1, Next(cur)); }, - [this](BetweenFieldsQueryEntry &entry) { + cur, Skip{}, [](const SubQueryEntry&) { throw_as_assert; }, + [](const SubQueryFieldEntry&) { throw_as_assert; }, + [this, cur](const QueryEntriesBracket&) { initIndexedQueries(cur + 1, Next(cur)); }, + [this](BetweenFieldsQueryEntry& entry) { if (!entry.FieldsHaveBeenSet()) { SetQueryField(entry.LeftFieldData(), ns_); SetQueryField(entry.RightFieldData(), ns_); @@ -640,7 +673,7 @@ void QueryPreprocessor::initIndexedQueries(size_t begin, size_t end) { checkStrictMode(entry.LeftFieldData()); checkStrictMode(entry.RightFieldData()); }, - [this](QueryEntry &qe) { + [this](QueryEntry& qe) { if (!qe.FieldsHaveBeenSet()) { SetQueryField(qe.FieldData(), ns_); } @@ -651,8 +684,10 @@ void QueryPreprocessor::initIndexedQueries(size_t begin, size_t end) { } SortingEntries QueryPreprocessor::detectOptimalSortOrder() const { - if (!AvailableSelectBySortIndex()) return {}; - if (const Index *maxIdx = findMaxIndex(cbegin(), cend())) { + if (!AvailableSelectBySortIndex()) { + return {}; + } + if (const Index* maxIdx = findMaxIndex(cbegin(), cend())) { SortingEntries sortingEntries; sortingEntries.emplace_back(maxIdx->Name(), false); return sortingEntries; @@ -660,11 +695,11 @@ SortingEntries QueryPreprocessor::detectOptimalSortOrder() const { return {}; } -const Index *QueryPreprocessor::findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end) const { +const Index* QueryPreprocessor::findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end) const { thread_local h_vector foundIndexes; foundIndexes.clear(); findMaxIndex(begin, end, foundIndexes); - boost::sort::pdqsort(foundIndexes.begin(), foundIndexes.end(), [](const FoundIndexInfo &l, const FoundIndexInfo &r) noexcept { + boost::sort::pdqsort(foundIndexes.begin(), foundIndexes.end(), [](const FoundIndexInfo& l, const FoundIndexInfo& r) noexcept { if (l.isFitForSortOptimization > r.isFitForSortOptimization) { return true; } @@ -680,15 +715,15 @@ const Index *QueryPreprocessor::findMaxIndex(QueryEntries::const_iterator begin, } void QueryPreprocessor::findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end, - h_vector &foundIndexes) const { + h_vector& foundIndexes) const { for (auto it = begin; it != end; ++it) { - const auto foundIdx = it->Visit([](const SubQueryEntry &) -> FoundIndexInfo { throw_as_assert; }, - [](const SubQueryFieldEntry &) -> FoundIndexInfo { throw_as_assert; }, - [this, &it, &foundIndexes](const QueryEntriesBracket &) { + const auto foundIdx = it->Visit([](const SubQueryEntry&) -> FoundIndexInfo { throw_as_assert; }, + [](const SubQueryFieldEntry&) -> FoundIndexInfo { throw_as_assert; }, + [this, &it, &foundIndexes](const QueryEntriesBracket&) { findMaxIndex(it.cbegin(), it.cend(), foundIndexes); return FoundIndexInfo(); }, - [this](const QueryEntry &entry) -> FoundIndexInfo { + [this](const QueryEntry& entry) -> FoundIndexInfo { if (entry.IsFieldIndexed() && !entry.Distinct()) { const auto idxPtr = ns_.indexes_[entry.IndexNo()].get(); if (idxPtr->IsOrdered() && !idxPtr->Opts().IsArray()) { @@ -701,13 +736,13 @@ void QueryPreprocessor::findMaxIndex(QueryEntries::const_iterator begin, QueryEn } return {}; }, - [](const JoinQueryEntry &) noexcept { return FoundIndexInfo(); }, - [](const BetweenFieldsQueryEntry &) noexcept { return FoundIndexInfo(); }, - [](const AlwaysFalse &) noexcept { return FoundIndexInfo(); }, - [](const AlwaysTrue &) noexcept { return FoundIndexInfo(); }); + [](const JoinQueryEntry&) noexcept { return FoundIndexInfo(); }, + [](const BetweenFieldsQueryEntry&) noexcept { return FoundIndexInfo(); }, + [](const AlwaysFalse&) noexcept { return FoundIndexInfo(); }, + [](const AlwaysTrue&) noexcept { return FoundIndexInfo(); }); if (foundIdx.index) { auto found = std::find_if(foundIndexes.begin(), foundIndexes.end(), - [foundIdx](const FoundIndexInfo &i) { return i.index == foundIdx.index; }); + [foundIdx](const FoundIndexInfo& i) { return i.index == foundIdx.index; }); if (found == foundIndexes.end()) { foundIndexes.emplace_back(foundIdx); } else { @@ -721,23 +756,23 @@ namespace { class CompositeLess : less_composite_ref { public: - CompositeLess(const PayloadType &type, const FieldsSet &fields) noexcept : less_composite_ref(type, fields) {} + CompositeLess(const PayloadType& type, const FieldsSet& fields) noexcept : less_composite_ref(type, fields) {} - bool operator()(const Variant &lhs, const Variant &rhs) const { + bool operator()(const Variant& lhs, const Variant& rhs) const { assertrx_dbg(lhs.Type().Is()); assertrx_dbg(rhs.Type().Is()); - return less_composite_ref::operator()(static_cast(lhs), static_cast(rhs)); + return less_composite_ref::operator()(static_cast(lhs), static_cast(rhs)); } }; class CompositeEqual : equal_composite_ref { public: - CompositeEqual(const PayloadType &type, const FieldsSet &fields) noexcept : equal_composite_ref(type, fields) {} + CompositeEqual(const PayloadType& type, const FieldsSet& fields) noexcept : equal_composite_ref(type, fields) {} - bool operator()(const Variant &lhs, const Variant &rhs) const { + bool operator()(const Variant& lhs, const Variant& rhs) const { assertrx_dbg(lhs.Type().Is()); assertrx_dbg(rhs.Type().Is()); - return equal_composite_ref::operator()(static_cast(lhs), static_cast(rhs)); + return equal_composite_ref::operator()(static_cast(lhs), static_cast(rhs)); } }; @@ -751,20 +786,20 @@ using MergeEqualT = std::conditional_t -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, - const CmpArgs &...args) { +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, + const CmpArgs&... args) { // intersect 2 queryentries on the same index if rx_unlikely (lqe.Values().empty() || rqe.Values().empty()) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } - auto &&[first, second] = lqe.Values().size() < rqe.Values().size() ? std::make_pair(std::move(lqe).Values(), std::move(rqe).Values()) + auto&& [first, second] = lqe.Values().size() < rqe.Values().size() ? std::make_pair(std::move(lqe).Values(), std::move(rqe).Values()) : std::make_pair(std::move(rqe).Values(), std::move(lqe).Values()); if (first.size() == 1) { - const Variant &firstV = first[0]; + const Variant& firstV = first[0]; const MergeEqualT equalTo{args...}; - for (const Variant &secondV : second) { + for (const Variant& secondV : second) { if (equalTo(firstV, secondV)) { lqe.SetCondAndValues(CondEq, VariantArray{std::move(first[0])}); // NOLINT (bugprone-use-after-move) lqe.Distinct(distinct); @@ -780,7 +815,7 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryE if (second.size() < kMinArraySizeToUseHashSet) { // Intersect via binary search + sort for small vectors boost::sort::pdqsort(first.begin(), first.end(), MergeLessT{args...}); - for (auto &&v : second) { + for (auto&& v : second) { if (std::binary_search(first.begin(), first.end(), v, MergeLessT{args...})) { setValues.emplace_back(std::move(v)); } @@ -789,10 +824,10 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryE // Intersect via hash_set for large vectors fast_hash_set_variant set{args...}; set.reserve(first.size()); - for (auto &&v : first) { + for (auto&& v : first) { set.emplace(std::move(v)); } - for (auto &&v : second) { + for (auto&& v : second) { if (set.erase(v)) { setValues.emplace_back(std::move(v)); } @@ -801,11 +836,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryE } else { // Intersect via hash_set for the composite values unordered_payload_ref_set set{first.size(), hash_composite_ref{args...}, equal_composite_ref{args...}}; - for (auto &v : first) { - set.emplace(static_cast(v)); + for (auto& v : first) { + set.emplace(static_cast(v)); } - for (auto &&v : second) { - if (set.erase(static_cast(v))) { + for (auto&& v : second) { + if (set.erase(static_cast(v))) { setValues.emplace_back(std::move(v)); } } @@ -821,23 +856,23 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetSet(QueryE } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetSet(NeedSwitch needSwitch, QueryEntry &allSet, QueryEntry &set, - bool distinct, size_t position, const CmpArgs &...args) { +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetSet(NeedSwitch needSwitch, QueryEntry& allSet, QueryEntry& set, + bool distinct, size_t position, const CmpArgs&... args) { if rx_unlikely (allSet.Values().empty() || set.Values().empty()) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } const MergeEqualT equalTo{args...}; const auto lvIt = allSet.Values().begin(); - const Variant &lv = *lvIt; + const Variant& lv = *lvIt; for (auto it = lvIt + 1, endIt = allSet.Values().end(); it != endIt; ++it) { if (!equalTo(lv, *it)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } } - QueryEntry &dst = needSwitch == NeedSwitch::Yes ? set : allSet; - for (const Variant &rv : set.Values()) { + QueryEntry& dst = needSwitch == NeedSwitch::Yes ? set : allSet; + for (const Variant& rv : set.Values()) { if (equalTo(lv, rv)) { dst.Distinct(distinct); dst.SetCondAndValues(CondEq, VariantArray{std::move(std::move(allSet).Values()[0])}); @@ -849,22 +884,22 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetSet(Nee } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetAllSet(QueryEntry &lqe, QueryEntry &rqe, bool distinct, - size_t position, const CmpArgs &...args) { +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetAllSet(QueryEntry& lqe, QueryEntry& rqe, bool distinct, + size_t position, const CmpArgs&... args) { if rx_unlikely (lqe.Values().empty() || rqe.Values().empty()) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } const MergeEqualT equalTo{args...}; const auto lvIt = lqe.Values().begin(); - const Variant &lv = *lvIt; + const Variant& lv = *lvIt; for (auto it = lvIt + 1, endIt = lqe.Values().end(); it != endIt; ++it) { if (!equalTo(lv, *it)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } } - for (const Variant &rv : rqe.Values()) { + for (const Variant& rv : rqe.Values()) { if (!equalTo(lv, rv)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; @@ -875,7 +910,7 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetAllSet( return MergeResult::Merged; } -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAny(NeedSwitch needSwitch, QueryEntry &any, QueryEntry ¬Any, +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAny(NeedSwitch needSwitch, QueryEntry& any, QueryEntry& notAny, bool distinct, size_t position) { if (notAny.Condition() == CondEmpty) { SetValue(position, AlwaysFalse{}); @@ -889,7 +924,7 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAny(NeedSwitc } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetNotSet(NeedSwitch needSwitch, QueryEntry &set, QueryEntry ¬Set, +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetNotSet(NeedSwitch needSwitch, QueryEntry& set, QueryEntry& notSet, F filter, bool distinct, size_t position, MergeOrdered mergeOrdered) { if rx_unlikely (set.Values().empty()) { @@ -898,7 +933,7 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetNotSet(Nee } { auto updatableValues = set.UpdatableValues(); - VariantArray &values = updatableValues; + VariantArray& values = updatableValues; values.erase(std::remove_if(values.begin(), values.end(), filter), values.end()); } if rx_unlikely (set.Values().empty()) { @@ -917,16 +952,16 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesSetNotSet(Nee } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetNotSet(NeedSwitch needSwitch, QueryEntry &allSet, - QueryEntry ¬Set, F filter, bool distinct, - size_t position, const CmpArgs &...args) { +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetNotSet(NeedSwitch needSwitch, QueryEntry& allSet, + QueryEntry& notSet, F filter, bool distinct, + size_t position, const CmpArgs&... args) { if rx_unlikely (allSet.Values().empty()) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } const MergeEqualT equalTo{args...}; const auto lvIt = allSet.Values().begin(); - const Variant &lv = *lvIt; + const Variant& lv = *lvIt; for (auto it = lvIt + 1, endIt = allSet.Values().end(); it != endIt; ++it) { if (!equalTo(lv, *it)) { SetValue(position, AlwaysFalse{}); @@ -937,17 +972,17 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesAllSetNotSet( SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; } - QueryEntry &dst = needSwitch == NeedSwitch::Yes ? notSet : allSet; + QueryEntry& dst = needSwitch == NeedSwitch::Yes ? notSet : allSet; dst.Distinct(distinct); dst.SetCondAndValues(CondEq, VariantArray{std::move(std::move(allSet).Values()[0])}); return MergeResult::Merged; } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLt(QueryEntry &lqe, QueryEntry &rqe, bool distinct, - const CmpArgs &...args) { - const Variant &lv = lqe.Values()[0]; - const Variant &rv = rqe.Values()[0]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLt(QueryEntry& lqe, QueryEntry& rqe, bool distinct, + const CmpArgs&... args) { + const Variant& lv = lqe.Values()[0]; + const Variant& rv = rqe.Values()[0]; const MergeLessT less{args...}; if (less(rv, lv)) { lqe.SetCondAndValues(rqe.Condition(), std::move(rqe).Values()); // NOLINT (bugprone-use-after-move) @@ -959,10 +994,10 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLt(QueryEntry } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesGt(QueryEntry &lqe, QueryEntry &rqe, bool distinct, - const CmpArgs &...args) { - const Variant &lv = lqe.Values()[0]; - const Variant &rv = rqe.Values()[0]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesGt(QueryEntry& lqe, QueryEntry& rqe, bool distinct, + const CmpArgs&... args) { + const Variant& lv = lqe.Values()[0]; + const Variant& rv = rqe.Values()[0]; if (MergeLessT{args...}(lv, rv)) { lqe.SetCondAndValues(rqe.Condition(), std::move(rqe).Values()); // NOLINT (bugprone-use-after-move) } else if (MergeEqualT{args...}(lv, rv) && (lqe.Condition() != rqe.Condition())) { @@ -973,10 +1008,10 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesGt(QueryEntry } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLtGt(QueryEntry <, QueryEntry >, size_t position, - const CmpArgs &...args) { - const Variant <V = lt.Values()[0]; - const Variant >V = gt.Values()[0]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLtGt(QueryEntry& lt, QueryEntry& gt, size_t position, + const CmpArgs&... args) { + const Variant& ltV = lt.Values()[0]; + const Variant& gtV = gt.Values()[0]; if (MergeLessT{args...}(gtV, ltV)) { return MergeResult::NotMerged; } else { @@ -986,13 +1021,13 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLtGt(QueryEnt } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLeGe(NeedSwitch needSwitch, QueryEntry &le, QueryEntry &ge, - bool distinct, size_t position, const CmpArgs &...args) { - const Variant &leV = le.Values()[0]; - const Variant &geV = ge.Values()[0]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLeGe(NeedSwitch needSwitch, QueryEntry& le, QueryEntry& ge, + bool distinct, size_t position, const CmpArgs&... args) { + const Variant& leV = le.Values()[0]; + const Variant& geV = ge.Values()[0]; const MergeLessT less{args...}; - QueryEntry &target = needSwitch == NeedSwitch::Yes ? ge : le; - QueryEntry &source = needSwitch == NeedSwitch::Yes ? le : ge; + QueryEntry& target = needSwitch == NeedSwitch::Yes ? ge : le; + QueryEntry& source = needSwitch == NeedSwitch::Yes ? le : ge; if (less(leV, geV)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; @@ -1006,11 +1041,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesLeGe(NeedSwit } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLt(NeedSwitch needSwitch, QueryEntry &range, QueryEntry <, - bool distinct, size_t position, const CmpArgs &...args) { - const Variant <V = lt.Values()[0]; - const Variant &rngL = range.Values()[0]; - const Variant &rngR = range.Values()[1]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLt(NeedSwitch needSwitch, QueryEntry& range, QueryEntry& lt, + bool distinct, size_t position, const CmpArgs&... args) { + const Variant& ltV = lt.Values()[0]; + const Variant& rngL = range.Values()[0]; + const Variant& rngR = range.Values()[1]; const MergeLessT less{args...}; if (!less(rngL, ltV)) { SetValue(position, AlwaysFalse{}); @@ -1027,11 +1062,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLt(NeedS } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGt(NeedSwitch needSwitch, QueryEntry &range, QueryEntry >, - bool distinct, size_t position, const CmpArgs &...args) { - const Variant >V = gt.Values()[0]; - const Variant &rngL = range.Values()[0]; - const Variant &rngR = range.Values()[1]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGt(NeedSwitch needSwitch, QueryEntry& range, QueryEntry& gt, + bool distinct, size_t position, const CmpArgs&... args) { + const Variant& gtV = gt.Values()[0]; + const Variant& rngL = range.Values()[0]; + const Variant& rngR = range.Values()[1]; const MergeLessT less{args...}; if (!less(gtV, rngR)) { SetValue(position, AlwaysFalse{}); @@ -1048,13 +1083,13 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGt(NeedS } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLe(NeedSwitch needSwitch, QueryEntry &range, QueryEntry &le, - bool distinct, size_t position, const CmpArgs &...args) { - const Variant &leV = le.Values()[0]; - const Variant &rngL = range.Values()[0]; - const Variant &rngR = range.Values()[1]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLe(NeedSwitch needSwitch, QueryEntry& range, QueryEntry& le, + bool distinct, size_t position, const CmpArgs&... args) { + const Variant& leV = le.Values()[0]; + const Variant& rngL = range.Values()[0]; + const Variant& rngR = range.Values()[1]; const MergeLessT less{args...}; - QueryEntry &target = needSwitch == NeedSwitch::Yes ? le : range; + QueryEntry& target = needSwitch == NeedSwitch::Yes ? le : range; if (less(leV, rngL)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; @@ -1074,13 +1109,13 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeLe(NeedS } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGe(NeedSwitch needSwitch, QueryEntry &range, QueryEntry &ge, - bool distinct, size_t position, const CmpArgs &...args) { - const Variant &geV = ge.Values()[0]; - const Variant &rngL = range.Values()[0]; - const Variant &rngR = range.Values()[1]; +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGe(NeedSwitch needSwitch, QueryEntry& range, QueryEntry& ge, + bool distinct, size_t position, const CmpArgs&... args) { + const Variant& geV = ge.Values()[0]; + const Variant& rngL = range.Values()[0]; + const Variant& rngR = range.Values()[1]; const MergeLessT less{args...}; - QueryEntry &target = needSwitch == NeedSwitch::Yes ? ge : range; + QueryEntry& target = needSwitch == NeedSwitch::Yes ? ge : range; if (less(rngR, geV)) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; @@ -1100,11 +1135,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRangeGe(NeedS } template -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRange(QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, - const CmpArgs &...args) { +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRange(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, + const CmpArgs&... args) { const MergeLessT less{args...}; - QueryEntry &left = less(lqe.Values()[0], rqe.Values()[0]) ? rqe : lqe; - QueryEntry &right = less(rqe.Values()[1], lqe.Values()[1]) ? rqe : lqe; + QueryEntry& left = less(lqe.Values()[0], rqe.Values()[0]) ? rqe : lqe; + QueryEntry& right = less(rqe.Values()[1], lqe.Values()[1]) ? rqe : lqe; if (less(right.Values()[1], left.Values()[0])) { SetValue(position, AlwaysFalse{}); return MergeResult::Annihilated; @@ -1118,7 +1153,7 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesRange(QueryEn return MergeResult::Merged; } -QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesDWithin(QueryEntry &lqe, QueryEntry &rqe, bool distinct, +QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesDWithin(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position) { Point lp, rp; double ld, rd; @@ -1151,9 +1186,9 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntriesDWithin(Query template QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, size_t rhs, MergeOrdered mergeOrdered, - const CmpArgs &...args) { - auto &lqe = Get(lhs); - auto &rqe = Get(rhs); + const CmpArgs&... args) { + auto& lqe = Get(lhs); + auto& rqe = Get(rhs); const bool distinct = lqe.Distinct() || rqe.Distinct(); const MergeLessT less{args...}; switch (lqe.Condition()) { @@ -1167,24 +1202,24 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, return mergeQueryEntriesAllSetSet(NeedSwitch::Yes, rqe, lqe, distinct, lhs, args...); case CondLt: return mergeQueryEntriesSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return !less(v, rv); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return !less(v, rv); }, distinct, lhs, mergeOrdered); case CondLe: return mergeQueryEntriesSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return less(rv, v); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return less(rv, v); }, distinct, lhs, mergeOrdered); case CondGe: return mergeQueryEntriesSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return less(v, rv); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return less(v, rv); }, distinct, lhs, mergeOrdered); case CondGt: return mergeQueryEntriesSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return !less(rv, v); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return !less(rv, v); }, distinct, lhs, mergeOrdered); case CondRange: return mergeQueryEntriesSetNotSet( NeedSwitch::No, lqe, rqe, - [&rv1 = rqe.Values()[0], &rv2 = rqe.Values()[1], &less](const Variant &v) { return less(v, rv1) || less(rv2, v); }, + [&rv1 = rqe.Values()[0], &rv2 = rqe.Values()[1], &less](const Variant& v) { return less(v, rv1) || less(rv2, v); }, distinct, lhs, mergeOrdered); case CondAny: return mergeQueryEntriesAny(NeedSwitch::No, rqe, lqe, distinct, lhs); @@ -1205,24 +1240,24 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, return mergeQueryEntriesAllSetAllSet(lqe, rqe, distinct, lhs, args...); case CondLt: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return !less(v, rv); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return !less(v, rv); }, distinct, lhs, args...); case CondLe: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return less(rv, v); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return less(rv, v); }, distinct, lhs, args...); case CondGe: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return less(v, rv); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return less(v, rv); }, distinct, lhs, args...); case CondGt: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant &v) { return !less(rv, v); }, distinct, lhs, + NeedSwitch::No, lqe, rqe, [&rv = rqe.Values()[0], &less](const Variant& v) { return !less(rv, v); }, distinct, lhs, args...); case CondRange: return mergeQueryEntriesAllSetNotSet( NeedSwitch::No, lqe, rqe, - [&rv1 = rqe.Values()[0], &rv2 = rqe.Values()[1], &less](const Variant &v) { return less(v, rv1) || less(rv2, v); }, + [&rv1 = rqe.Values()[0], &rv2 = rqe.Values()[1], &less](const Variant& v) { return less(v, rv1) || less(rv2, v); }, distinct, lhs, args...); case CondAny: return mergeQueryEntriesAny(NeedSwitch::No, rqe, lqe, distinct, lhs); @@ -1239,11 +1274,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, case CondEq: case CondSet: return mergeQueryEntriesSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return !less(v, lv); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return !less(v, lv); }, distinct, lhs, mergeOrdered); case CondAllSet: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return !less(v, lv); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return !less(v, lv); }, distinct, lhs, args...); case CondAny: return mergeQueryEntriesAny(NeedSwitch::No, rqe, lqe, distinct, lhs); @@ -1268,11 +1303,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, case CondEq: case CondSet: return mergeQueryEntriesSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return less(lv, v); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return less(lv, v); }, distinct, lhs, mergeOrdered); case CondAllSet: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return less(lv, v); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return less(lv, v); }, distinct, lhs, args...); case CondLt: case CondLe: @@ -1298,11 +1333,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, case CondEq: case CondSet: return mergeQueryEntriesSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return !less(lv, v); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return !less(lv, v); }, distinct, lhs, mergeOrdered); case CondAllSet: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return !less(lv, v); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return !less(lv, v); }, distinct, lhs, args...); case CondGt: case CondGe: @@ -1327,11 +1362,11 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, case CondEq: case CondSet: return mergeQueryEntriesSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return less(v, lv); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return less(v, lv); }, distinct, lhs, mergeOrdered); case CondAllSet: return mergeQueryEntriesAllSetNotSet( - NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant &v) { return less(v, lv); }, distinct, lhs, + NeedSwitch::Yes, rqe, lqe, [&lv = lqe.Values()[0], &less](const Variant& v) { return less(v, lv); }, distinct, lhs, args...); case CondGt: case CondGe: @@ -1358,12 +1393,12 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, case CondSet: return mergeQueryEntriesSetNotSet( NeedSwitch::Yes, rqe, lqe, - [&lv1 = lqe.Values()[0], &lv2 = lqe.Values()[1], &less](const Variant &v) { return less(v, lv1) || less(lv2, v); }, + [&lv1 = lqe.Values()[0], &lv2 = lqe.Values()[1], &less](const Variant& v) { return less(v, lv1) || less(lv2, v); }, distinct, lhs, mergeOrdered); case CondAllSet: return mergeQueryEntriesAllSetNotSet( NeedSwitch::Yes, rqe, lqe, - [&lv1 = lqe.Values()[0], &lv2 = lqe.Values()[1], &less](const Variant &v) { return less(v, lv1) || less(lv2, v); }, + [&lv1 = lqe.Values()[0], &lv2 = lqe.Values()[1], &less](const Variant& v) { return less(v, lv1) || less(lv2, v); }, distinct, lhs, args...); case CondLt: return mergeQueryEntriesRangeLt(NeedSwitch::No, lqe, rqe, distinct, lhs, args...); @@ -1431,26 +1466,28 @@ QueryPreprocessor::MergeResult QueryPreprocessor::mergeQueryEntries(size_t lhs, return MergeResult::NotMerged; } -void QueryPreprocessor::AddDistinctEntries(const h_vector &aggregators) { +void QueryPreprocessor::AddDistinctEntries(const h_vector& aggregators) { bool wasAdded = false; - for (auto &ag : aggregators) { - if (ag.Type() != AggDistinct) continue; + for (auto& ag : aggregators) { + if (ag.Type() != AggDistinct) { + continue; + } assertrx_throw(ag.Names().size() == 1); Append(wasAdded ? OpOr : OpAnd, ag.Names()[0], QueryEntry::DistinctTag{}); - auto &qe = Get(LastAppendedElement()); + auto& qe = Get(LastAppendedElement()); SetQueryField(qe.FieldData(), ns_); checkStrictMode(qe.FieldData()); wasAdded = true; } } -std::pair QueryPreprocessor::queryValuesFromOnCondition(std::string &explainStr, AggType &oAggType, - NamespaceImpl &rightNs, Query joinQuery, +std::pair QueryPreprocessor::queryValuesFromOnCondition(std::string& explainStr, AggType& oAggType, + NamespaceImpl& rightNs, Query joinQuery, JoinPreResult::CPtr joinPreresult, - const QueryJoinEntry &joinEntry, CondType condition, - int mainQueryMaxIterations, const RdxContext &rdxCtx) { + const QueryJoinEntry& joinEntry, CondType condition, + int mainQueryMaxIterations, const RdxContext& rdxCtx) { size_t limit = 0; - const auto &rNsCfg = rightNs.config(); + const auto& rNsCfg = rightNs.config(); if (rNsCfg.maxPreselectSize == 0) { limit = std::max(rNsCfg.minPreselectSize, rightNs.itemsCount() * rNsCfg.maxPreselectPart); } else if (rNsCfg.maxPreselectPart == 0.0) { @@ -1462,8 +1499,12 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( joinQuery.Explain(query_.NeedExplain()); joinQuery.Limit(limit + 2); joinQuery.Offset(QueryEntry::kDefaultOffset); - joinQuery.sortingEntries_.clear(); + joinQuery.sortingEntries_.clear(); joinQuery.forcedSortOrder_.clear(); + if (joinPreresult->sortOrder.index) { + joinQuery.sortingEntries_.emplace_back(joinPreresult->sortOrder.sortingEntry); + } + joinQuery.aggregations_.clear(); switch (condition) { case CondEq: @@ -1497,7 +1538,7 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( return {CondAny, {}}; } assertrx_throw(qr.aggregationResults.size() == 1); - auto &aggRes = qr.aggregationResults[0]; + auto& aggRes = qr.aggregationResults[0]; explainStr = qr.explainResults; switch (condition) { case CondEq: @@ -1505,9 +1546,9 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( assertrx_throw(aggRes.type == AggDistinct); VariantArray values; values.reserve(aggRes.distincts.size()); - for (Variant &distValue : aggRes.distincts) { + for (Variant& distValue : aggRes.distincts) { if (distValue.Type().Is()) { - ConstPayload pl(aggRes.payloadType, distValue.operator const PayloadValue &()); + ConstPayload pl(aggRes.payloadType, distValue.operator const PayloadValue&()); values.emplace_back(pl.GetComposite(aggRes.distinctsFields, joinEntry.RightCompositeFieldsTypes())); } else { values.emplace_back(std::move(distValue)); @@ -1535,9 +1576,9 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( } } -std::pair QueryPreprocessor::queryValuesFromOnCondition(CondType condition, const QueryJoinEntry &joinEntry, - const JoinedSelector &joinedSelector, - const CollateOpts &collate) { +std::pair QueryPreprocessor::queryValuesFromOnCondition(CondType condition, const QueryJoinEntry& joinEntry, + const JoinedSelector& joinedSelector, + const CollateOpts& collate) { switch (condition) { case CondEq: case CondSet: @@ -1546,13 +1587,13 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( case CondLe: case CondGt: case CondGe: { - const JoinPreResult::Values &values = std::get(joinedSelector.PreResult().payload); + const JoinPreResult::Values& values = std::get(joinedSelector.PreResult().payload); VariantArray buffer, keyValues; - for (const ItemRef &item : values) { + for (const ItemRef& item : values) { assertrx_throw(!item.Value().IsFree()); const ConstPayload pl{values.payloadType, item.Value()}; pl.GetByFieldsSet(joinEntry.RightFields(), buffer, joinEntry.RightFieldType(), joinEntry.RightCompositeFieldsTypes()); - for (Variant &v : buffer) { + for (Variant& v : buffer) { if (keyValues.empty()) { keyValues.emplace_back(std::move(v)); } else { @@ -1570,7 +1611,7 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( } } return {condition, std::move(keyValues)}; - } break; + } case CondAny: case CondRange: case CondAllSet: @@ -1583,41 +1624,41 @@ std::pair QueryPreprocessor::queryValuesFromOnCondition( } template -void QueryPreprocessor::briefDump(size_t from, size_t to, const std::vector &joinedSelectors, WrSerializer &ser) const { +void QueryPreprocessor::briefDump(size_t from, size_t to, const std::vector& joinedSelectors, WrSerializer& ser) const { { for (auto it = from; it < to; it = Next(it)) { if (it != from || container_[it].operation != OpAnd) { ser << container_[it].operation << ' '; } - container_[it].Visit([](const SubQueryEntry &) { throw_as_assert; }, [](const SubQueryFieldEntry &) { throw_as_assert; }, - [&](const QueryEntriesBracket &b) { + container_[it].Visit([](const SubQueryEntry&) { throw_as_assert; }, [](const SubQueryFieldEntry&) { throw_as_assert; }, + [&](const QueryEntriesBracket& b) { ser << "("; briefDump(it + 1, Next(it), joinedSelectors, ser); dumpEqualPositions(0, ser, b.equalPositions); ser << ")"; }, - [&ser](const QueryEntry &qe) { ser << qe.DumpBrief() << ' '; }, - [&joinedSelectors, &ser](const JoinQueryEntry &jqe) { ser << jqe.Dump(joinedSelectors) << ' '; }, - [&ser](const BetweenFieldsQueryEntry &qe) { ser << qe.Dump() << ' '; }, - [&ser](const AlwaysFalse &) { ser << "AlwaysFalse" << ' '; }, - [&ser](const AlwaysTrue &) { ser << "AlwaysTrue" << ' '; }); + [&ser](const QueryEntry& qe) { ser << qe.DumpBrief() << ' '; }, + [&joinedSelectors, &ser](const JoinQueryEntry& jqe) { ser << jqe.Dump(joinedSelectors) << ' '; }, + [&ser](const BetweenFieldsQueryEntry& qe) { ser << qe.Dump() << ' '; }, + [&ser](const AlwaysFalse&) { ser << "AlwaysFalse" << ' '; }, + [&ser](const AlwaysTrue&) { ser << "AlwaysTrue" << ' '; }); } } } template -size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to, JoinedSelectors &js, - OnConditionInjections &explainOnInjections, int embracedMaxIterations, - h_vector &maxIterations, bool inTransaction, bool enableSortOrders, - const RdxContext &rdxCtx) { +size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to, JoinedSelectors& js, + OnConditionInjections& explainOnInjections, int embracedMaxIterations, + h_vector& maxIterations, bool inTransaction, bool enableSortOrders, + const RdxContext& rdxCtx) { using namespace std::string_view_literals; size_t injectedCount = 0; for (size_t cur = from; cur < to; cur = Next(cur)) { container_[cur].Visit( - [](const SubQueryEntry &) { throw_as_assert; }, [](const SubQueryFieldEntry &) { throw_as_assert; }, + [](const SubQueryEntry&) { throw_as_assert; }, [](const SubQueryFieldEntry&) { throw_as_assert; }, Skip{}, - [&](const QueryEntriesBracket &) { + [&](const QueryEntriesBracket&) { const size_t injCount = injectConditionsFromJoins(cur + 1, Next(cur), js, explainOnInjections, maxIterations[cur], maxIterations, inTransaction, enableSortOrders, rdxCtx); @@ -1625,11 +1666,11 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to injectedCount += injCount; assertrx_throw(to <= container_.size()); }, - [&](const JoinQueryEntry &jqe) { + [&](const JoinQueryEntry& jqe) { const auto joinIndex = jqe.joinIndex; assertrx_throw(js.size() > joinIndex); - JoinedSelector &joinedSelector = js[joinIndex]; - const JoinPreResult &preResult = joinedSelector.PreResult(); + JoinedSelector& joinedSelector = js[joinIndex]; + const JoinPreResult& preResult = joinedSelector.PreResult(); assertrx_throw(joinedSelector.PreSelectMode() == JoinPreSelectMode::Execute); const bool byValues = std::holds_alternative(preResult.payload); @@ -1638,7 +1679,7 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to // Checking if we are able to preselect something from RightNs, or there are preselected results if (!byValues) { - const auto &rNsCfg = joinedSelector.RightNs()->config(); + const auto& rNsCfg = joinedSelector.RightNs()->config(); if (rNsCfg.maxPreselectSize == 0 && rNsCfg.maxPreselectPart == 0.0) { explainJoinOn.Skipped("maxPreselectSize and maxPreselectPart == 0"sv); return; @@ -1649,12 +1690,12 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to return; } } - const auto &joinEntries = joinedSelector.joinQuery_.joinEntries_; + const auto& joinEntries = joinedSelector.joinQuery_.joinEntries_; // LeftJoin-s shall not be in QueryEntries container_ by construction assertrx_throw(joinedSelector.Type() == InnerJoin || joinedSelector.Type() == OrInnerJoin); // Checking if we have anything to inject into main Where clause bool foundANDOrOR = false; - for (const auto &je : joinEntries) { + for (const auto& je : joinEntries) { if (je.Operation() != OpNot) { foundANDOrOR = true; break; @@ -1667,7 +1708,9 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to OpType op = GetOperation(cur); if (joinedSelector.Type() == OrInnerJoin) { - if (op == OpNot) throw Error(errQueryExec, "OR INNER JOIN with operation NOT"); + if (op == OpNot) { + throw Error(errQueryExec, "OR INNER JOIN with operation NOT"); + } op = OpOr; joinedSelector.SetType(InnerJoin); } @@ -1698,7 +1741,7 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to bool prevIsSkipped = false; size_t orChainLength = 0; for (size_t i = 0, s = joinEntries.size(); i < s; ++i) { - const QueryJoinEntry &joinEntry = joinEntries[i]; + const QueryJoinEntry& joinEntry = joinEntries[i]; auto explainEntry = explainJoinOn.AppendOnEntryExplain(); explainEntry.InitialCondition(joinEntry, joinedSelector); CondType condition = joinEntry.Condition(); @@ -1751,7 +1794,7 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to assertrx_throw(joinedSelector.itemQuery_.Entries().Is(i)); assertrx_throw(joinedSelector.itemQuery_.Entries().Get(i).FieldName() == joinEntry.RightFieldName()); static const CollateOpts collate; - const CollateOpts *collatePtr = &collate; + const CollateOpts* collatePtr = &collate; if (joinEntry.IsLeftFieldIndexed()) { collatePtr = &ns_.indexes_[joinEntry.LeftIdxNo()]->Opts().collateOpts_; } @@ -1806,6 +1849,7 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to : queryValuesFromOnCondition(explainSelect, selectAggType, *joinedSelector.RightNs(), joinedSelector.JoinQuery(), joinedSelector.PreResultPtr(), joinEntry, condition, embracedMaxIterations, rdxCtx)); + explainEntry.ExplainSelect(std::move(explainSelect), selectAggType); } } @@ -1836,7 +1880,7 @@ size_t QueryPreprocessor::injectConditionsFromJoins(const size_t from, size_t to maxIterations.insert(maxIterations.begin() + (cur - count), embracedMaxIterations); explainJoinOn.Succeed( - [this, cur, count, &js](WrSerializer &ser) { briefDump(cur - count, Next(cur - count), js, ser); }); + [this, cur, count, &js](WrSerializer& ser) { briefDump(cur - count, Next(cur - count), js, ser); }); ++cur; injectedCount += count + 1; @@ -1854,18 +1898,18 @@ class JoinOnExplainDisabled { struct OnEntryExplain { OnEntryExplain() noexcept = default; - RX_ALWAYS_INLINE void InitialCondition(const QueryJoinEntry &, const JoinedSelector &) const noexcept {} - RX_ALWAYS_INLINE void Succeed(const QueryEntry &) const noexcept {} + RX_ALWAYS_INLINE void InitialCondition(const QueryJoinEntry&, const JoinedSelector&) const noexcept {} + RX_ALWAYS_INLINE void Succeed(const QueryEntry&) const noexcept {} RX_ALWAYS_INLINE void Skipped(std::string_view) const noexcept {} RX_ALWAYS_INLINE void OrChainPart(bool) const noexcept {} - RX_ALWAYS_INLINE void ExplainSelect(std::string &&, AggType) const noexcept {} + RX_ALWAYS_INLINE void ExplainSelect(std::string&&, AggType) const noexcept {} }; public: - [[nodiscard]] RX_ALWAYS_INLINE static JoinOnExplainDisabled AppendJoinOnExplain(OnConditionInjections &) noexcept { return {}; } + [[nodiscard]] RX_ALWAYS_INLINE static JoinOnExplainDisabled AppendJoinOnExplain(OnConditionInjections&) noexcept { return {}; } - RX_ALWAYS_INLINE void Init(const JoinQueryEntry &, const JoinedSelectors &, bool) const noexcept {} - RX_ALWAYS_INLINE void Succeed(const std::function &) const noexcept {} + RX_ALWAYS_INLINE void Init(const JoinQueryEntry&, const JoinedSelectors&, bool) const noexcept {} + RX_ALWAYS_INLINE void Succeed(const std::function&) const noexcept {} RX_ALWAYS_INLINE void Skipped(std::string_view) const noexcept {} RX_ALWAYS_INLINE void ReserveOnEntries(size_t) const noexcept {} [[nodiscard]] RX_ALWAYS_INLINE OnEntryExplain AppendOnEntryExplain() const noexcept { return {}; } @@ -1876,17 +1920,17 @@ class JoinOnExplainDisabled { class JoinOnExplainEnabled { using time_point_t = ExplainCalc::Clock::time_point; struct OnEntryExplain { - OnEntryExplain(ConditionInjection &explainEntry) noexcept : startTime_(ExplainCalc::Clock::now()), explainEntry_(explainEntry) {} + OnEntryExplain(ConditionInjection& explainEntry) noexcept : startTime_(ExplainCalc::Clock::now()), explainEntry_(explainEntry) {} ~OnEntryExplain() noexcept { explainEntry_.totalTime_ = ExplainCalc::Clock::now() - startTime_; } - OnEntryExplain(const OnEntryExplain &) = delete; - OnEntryExplain(OnEntryExplain &&) = delete; - OnEntryExplain &operator=(const OnEntryExplain &) = delete; - OnEntryExplain &operator=(OnEntryExplain &&) = delete; + OnEntryExplain(const OnEntryExplain&) = delete; + OnEntryExplain(OnEntryExplain&&) = delete; + OnEntryExplain& operator=(const OnEntryExplain&) = delete; + OnEntryExplain& operator=(OnEntryExplain&&) = delete; - void InitialCondition(const QueryJoinEntry &joinEntry, const JoinedSelector &joinedSelector) { + void InitialCondition(const QueryJoinEntry& joinEntry, const JoinedSelector& joinedSelector) { explainEntry_.initCond = joinEntry.DumpCondition(joinedSelector); } - void Succeed(const QueryEntry &newEntry) { + void Succeed(const QueryEntry& newEntry) { explainEntry_.succeed = true; explainEntry_.reason = ""; explainEntry_.newCond = newEntry.DumpBrief(); @@ -1901,36 +1945,36 @@ class JoinOnExplainEnabled { } void OrChainPart(bool orChainPart) noexcept { explainEntry_.orChainPart_ = orChainPart; } - void ExplainSelect(std::string &&explain, AggType aggType) noexcept { + void ExplainSelect(std::string&& explain, AggType aggType) noexcept { explainEntry_.explain = std::move(explain); explainEntry_.aggType = aggType; } private: time_point_t startTime_; - ConditionInjection &explainEntry_; + ConditionInjection& explainEntry_; }; - JoinOnExplainEnabled(JoinOnInjection &joinOn) noexcept : explainJoinOn_(joinOn), startTime_(ExplainCalc::Clock::now()) {} + JoinOnExplainEnabled(JoinOnInjection& joinOn) noexcept : explainJoinOn_(joinOn), startTime_(ExplainCalc::Clock::now()) {} public: - JoinOnExplainEnabled(const JoinOnExplainEnabled &) = delete; - JoinOnExplainEnabled(JoinOnExplainEnabled &&) = delete; - JoinOnExplainEnabled &operator=(const JoinOnExplainEnabled &) = delete; - JoinOnExplainEnabled &operator=(JoinOnExplainEnabled &&) = delete; + JoinOnExplainEnabled(const JoinOnExplainEnabled&) = delete; + JoinOnExplainEnabled(JoinOnExplainEnabled&&) = delete; + JoinOnExplainEnabled& operator=(const JoinOnExplainEnabled&) = delete; + JoinOnExplainEnabled& operator=(JoinOnExplainEnabled&&) = delete; - [[nodiscard]] static JoinOnExplainEnabled AppendJoinOnExplain(OnConditionInjections &explainOnInjections) { + [[nodiscard]] static JoinOnExplainEnabled AppendJoinOnExplain(OnConditionInjections& explainOnInjections) { return {explainOnInjections.emplace_back()}; } ~JoinOnExplainEnabled() noexcept { explainJoinOn_.totalTime_ = ExplainCalc::Clock::now() - startTime_; } - void Init(const JoinQueryEntry &jqe, const JoinedSelectors &js, bool byValues) { - const JoinedSelector &joinedSelector = js[jqe.joinIndex]; + void Init(const JoinQueryEntry& jqe, const JoinedSelectors& js, bool byValues) { + const JoinedSelector& joinedSelector = js[jqe.joinIndex]; explainJoinOn_.rightNsName = joinedSelector.RightNsName(); explainJoinOn_.joinCond = jqe.DumpOnCondition(js); explainJoinOn_.type = byValues ? JoinOnInjection::ByValue : JoinOnInjection::Select; } - void Succeed(const std::function &setInjectedCond) { + void Succeed(const std::function& setInjectedCond) { explainJoinOn_.succeed = true; setInjectedCond(explainJoinOn_.injectedCond); } @@ -1942,11 +1986,11 @@ class JoinOnExplainEnabled { } void ReserveOnEntries(size_t count) { explainJoinOn_.conditions.reserve(count); } - [[nodiscard]] OnEntryExplain AppendOnEntryExplain() { return {explainJoinOn_.conditions.emplace_back()}; }; + [[nodiscard]] OnEntryExplain AppendOnEntryExplain() { return {explainJoinOn_.conditions.emplace_back()}; } void FailOnEntriesAsOrChain(size_t orChainLength) { using namespace std::string_view_literals; - auto &conditions = explainJoinOn_.conditions; + auto& conditions = explainJoinOn_.conditions; assertrx_throw(conditions.size() >= orChainLength); // Marking On-injections as fail for removed entries. for (size_t jsz = conditions.size(), j = jsz - orChainLength; j < jsz; ++j) { @@ -1956,18 +2000,18 @@ class JoinOnExplainEnabled { } private: - JoinOnInjection &explainJoinOn_; + JoinOnInjection& explainJoinOn_; time_point_t startTime_; }; -void QueryPreprocessor::setQueryIndex(QueryField &qField, int idxNo, const NamespaceImpl &ns) { - const auto &idx = *ns.indexes_[idxNo]; +void QueryPreprocessor::setQueryIndex(QueryField& qField, int idxNo, const NamespaceImpl& ns) { + const auto& idx = *ns.indexes_[idxNo]; QueryField::CompositeTypesVecT compositeFieldsTypes; if (idxNo >= ns.indexes_.firstCompositePos()) { #ifndef NDEBUG const bool ftIdx = IsFullText(idx.Type()); #endif - const auto &fields = idx.Fields(); + const auto& fields = idx.Fields(); compositeFieldsTypes.reserve(fields.size()); for (const auto f : fields) { if rx_likely (f != IndexValueType::SetByJsonPath) { @@ -1983,7 +2027,7 @@ void QueryPreprocessor::setQueryIndex(QueryField &qField, int idxNo, const Names qField.SetIndexData(idxNo, FieldsSet(idx.Fields()), idx.KeyType(), idx.SelectKeyType(), std::move(compositeFieldsTypes)); } -void QueryPreprocessor::SetQueryField(QueryField &qField, const NamespaceImpl &ns) { +void QueryPreprocessor::SetQueryField(QueryField& qField, const NamespaceImpl& ns) { int idxNo = IndexValueType::SetByJsonPath; if (ns.getIndexByNameOrJsonPath(qField.FieldName(), idxNo)) { setQueryIndex(qField, idxNo, ns); diff --git a/cpp_src/core/nsselecter/querypreprocessor.h b/cpp_src/core/nsselecter/querypreprocessor.h index d9c61b935..7c348a13f 100644 --- a/cpp_src/core/nsselecter/querypreprocessor.h +++ b/cpp_src/core/nsselecter/querypreprocessor.h @@ -17,8 +17,8 @@ class QueryPreprocessor : private QueryEntries { public: enum class ValuesType : bool { Scalar, Composite }; - QueryPreprocessor(QueryEntries &&, NamespaceImpl *, const SelectCtx &); - const QueryEntries &GetQueryEntries() const noexcept { return *this; } + QueryPreprocessor(QueryEntries&&, NamespaceImpl*, const SelectCtx&); + const QueryEntries& GetQueryEntries() const noexcept { return *this; } bool LookupQueryIndexes() { const unsigned lookupEnd = queryEntryAddedByForcedSortOptimization_ ? container_.size() - 1 : container_.size(); assertrx_throw(lookupEnd <= uint32_t(std::numeric_limits::max() - 1)); @@ -44,21 +44,23 @@ class QueryPreprocessor : private QueryEntries { return substituteCompositeIndexes(0, container_.size() - queryEntryAddedByForcedSortOptimization_) != 0; } void InitIndexedQueries() { initIndexedQueries(0, Size()); } - void AddDistinctEntries(const h_vector &); - bool NeedNextEvaluation(unsigned start, unsigned count, bool &matchedAtLeastOnce, QresExplainHolder &qresHolder) noexcept; + void AddDistinctEntries(const h_vector&); + bool NeedNextEvaluation(unsigned start, unsigned count, bool& matchedAtLeastOnce, QresExplainHolder& qresHolder) noexcept; unsigned Start() const noexcept { return start_; } unsigned Count() const noexcept { return count_; } bool MoreThanOneEvaluation() const noexcept { return queryEntryAddedByForcedSortOptimization_; } bool AvailableSelectBySortIndex() const noexcept { return !queryEntryAddedByForcedSortOptimization_ || !forcedStage(); } - void InjectConditionsFromJoins(JoinedSelectors &js, OnConditionInjections &expalainOnInjections, LogLevel, bool inTransaction, - bool enableSortOrders, const RdxContext &rdxCtx); + void InjectConditionsFromJoins(JoinedSelectors& js, OnConditionInjections& expalainOnInjections, LogLevel, bool inTransaction, + bool enableSortOrders, const RdxContext& rdxCtx); void Reduce(bool isFt); using QueryEntries::Size; using QueryEntries::Dump; using QueryEntries::ToDsl; template - [[nodiscard]] SortingEntries GetSortingEntries(const SelectCtxWithJoinPreSelect &) const { - if (ftEntry_) return {}; + [[nodiscard]] SortingEntries GetSortingEntries(const SelectCtxWithJoinPreSelect&) const { + if (ftEntry_) { + return {}; + } // DO NOT use deducted sort order in the following cases: // - query contains explicity specified sort order // - query contains FullText query. @@ -72,17 +74,17 @@ class QueryPreprocessor : private QueryEntries { } bool IsFtExcluded() const noexcept { return ftEntry_.has_value(); } - void ExcludeFtQuery(const RdxContext &); - FtMergeStatuses &GetFtMergeStatuses() noexcept { + void ExcludeFtQuery(const RdxContext&); + FtMergeStatuses& GetFtMergeStatuses() noexcept { assertrx_throw(ftPreselect_); return *ftPreselect_; } - FtPreselectT &&MoveFtPreselect() noexcept { + FtPreselectT&& MoveFtPreselect() noexcept { assertrx_throw(ftPreselect_); return std::move(*ftPreselect_); } bool IsFtPreselected() const noexcept { return ftPreselect_ && !ftEntry_; } - static void SetQueryField(QueryField &, const NamespaceImpl &); + static void SetQueryField(QueryField&, const NamespaceImpl&); private: enum class NeedSwitch : bool { Yes = true, No = false }; @@ -92,73 +94,71 @@ class QueryPreprocessor : private QueryEntries { enum class ConditionType { Incompatible = 0, Compatible = 1 }; FoundIndexInfo() noexcept : index(nullptr), size(0), isFitForSortOptimization(0) {} - FoundIndexInfo(const Index *i, ConditionType ct) noexcept : index(i), size(i->Size()), isFitForSortOptimization(unsigned(ct)) {} + FoundIndexInfo(const Index* i, ConditionType ct) noexcept : index(i), size(i->Size()), isFitForSortOptimization(unsigned(ct)) {} - const Index *index; + const Index* index; uint64_t size : 63; uint64_t isFitForSortOptimization : 1; }; - static void setQueryIndex(QueryField &, int idxNo, const NamespaceImpl &); + static void setQueryIndex(QueryField&, int idxNo, const NamespaceImpl&); [[nodiscard]] SortingEntries detectOptimalSortOrder() const; [[nodiscard]] bool forcedStage() const noexcept { return evaluationsCount_ == (desc_ ? 1 : 0); } [[nodiscard]] size_t lookupQueryIndexes(uint16_t dst, uint16_t srcBegin, uint16_t srcEnd); [[nodiscard]] size_t substituteCompositeIndexes(size_t from, size_t to); template - MergeResult mergeQueryEntries(size_t lhs, size_t rhs, MergeOrdered, const CmpArgs &...); + MergeResult mergeQueryEntries(size_t lhs, size_t rhs, MergeOrdered, const CmpArgs&...); template - MergeResult mergeQueryEntriesSetSet(QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesSetSet(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesAllSetSet(NeedSwitch, QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, - const CmpArgs &...); + MergeResult mergeQueryEntriesAllSetSet(NeedSwitch, QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesAllSetAllSet(QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, const CmpArgs &...); - MergeResult mergeQueryEntriesAny(NeedSwitch, QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position); + MergeResult mergeQueryEntriesAllSetAllSet(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, const CmpArgs&...); + MergeResult mergeQueryEntriesAny(NeedSwitch, QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position); template - MergeResult mergeQueryEntriesSetNotSet(NeedSwitch, QueryEntry &lqe, QueryEntry &rqe, F filter, bool distinct, size_t position, + MergeResult mergeQueryEntriesSetNotSet(NeedSwitch, QueryEntry& lqe, QueryEntry& rqe, F filter, bool distinct, size_t position, MergeOrdered); template - MergeResult mergeQueryEntriesAllSetNotSet(NeedSwitch, QueryEntry &lqe, QueryEntry &rqe, F filter, bool distinct, size_t position, - const CmpArgs &...); - MergeResult mergeQueryEntriesDWithin(QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position); + MergeResult mergeQueryEntriesAllSetNotSet(NeedSwitch, QueryEntry& lqe, QueryEntry& rqe, F filter, bool distinct, size_t position, + const CmpArgs&...); + MergeResult mergeQueryEntriesDWithin(QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position); template - MergeResult mergeQueryEntriesLt(QueryEntry &lqe, QueryEntry &rqe, bool distinct, const CmpArgs &...); + MergeResult mergeQueryEntriesLt(QueryEntry& lqe, QueryEntry& rqe, bool distinct, const CmpArgs&...); template - MergeResult mergeQueryEntriesGt(QueryEntry &lqe, QueryEntry &rqe, bool distinct, const CmpArgs &...); + MergeResult mergeQueryEntriesGt(QueryEntry& lqe, QueryEntry& rqe, bool distinct, const CmpArgs&...); template - MergeResult mergeQueryEntriesLtGt(QueryEntry &lqe, QueryEntry &rqe, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesLtGt(QueryEntry& lqe, QueryEntry& rqe, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesLeGe(NeedSwitch, QueryEntry &lqe, QueryEntry &rqe, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesLeGe(NeedSwitch, QueryEntry& lqe, QueryEntry& rqe, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesRangeLt(NeedSwitch, QueryEntry &range, QueryEntry &ge, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesRangeLt(NeedSwitch, QueryEntry& range, QueryEntry& ge, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesRangeLe(NeedSwitch, QueryEntry &range, QueryEntry &ge, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesRangeLe(NeedSwitch, QueryEntry& range, QueryEntry& ge, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesRangeGt(NeedSwitch, QueryEntry &range, QueryEntry &ge, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesRangeGt(NeedSwitch, QueryEntry& range, QueryEntry& ge, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesRangeGe(NeedSwitch, QueryEntry &range, QueryEntry &ge, bool distinct, size_t position, const CmpArgs &...); + MergeResult mergeQueryEntriesRangeGe(NeedSwitch, QueryEntry& range, QueryEntry& ge, bool distinct, size_t position, const CmpArgs&...); template - MergeResult mergeQueryEntriesRange(QueryEntry &range, QueryEntry &ge, bool distinct, size_t position, const CmpArgs &...); - [[nodiscard]] const std::vector *getCompositeIndex(int field) const noexcept; + MergeResult mergeQueryEntriesRange(QueryEntry& range, QueryEntry& ge, bool distinct, size_t position, const CmpArgs&...); + [[nodiscard]] const std::vector* getCompositeIndex(int field) const noexcept; void initIndexedQueries(size_t begin, size_t end); - [[nodiscard]] const Index *findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end) const; + [[nodiscard]] const Index* findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end) const; void findMaxIndex(QueryEntries::const_iterator begin, QueryEntries::const_iterator end, - h_vector &foundIndexes) const; + h_vector& foundIndexes) const; /** @brief recurrently checks and injects Join ON conditions * @returns injected conditions and EntryBrackets count */ template - size_t injectConditionsFromJoins(size_t from, size_t to, JoinedSelectors &, OnConditionInjections &, int embracedMaxIterations, - h_vector &maxIterations, bool inTransaction, bool enableSortOrders, const RdxContext &); - [[nodiscard]] std::pair queryValuesFromOnCondition(std::string &outExplainStr, AggType &, - NamespaceImpl &rightNs, Query joinQuery, JoinPreResult::CPtr, - const QueryJoinEntry &, CondType, int mainQueryMaxIterations, - const RdxContext &); - [[nodiscard]] std::pair queryValuesFromOnCondition(CondType condition, const QueryJoinEntry &, - const JoinedSelector &, const CollateOpts &); - void checkStrictMode(const QueryField &) const; - [[nodiscard]] int calculateMaxIterations(const size_t from, const size_t to, int maxMaxIters, span &maxIterations, - bool inTransaction, bool enableSortOrders, const RdxContext &) const; + size_t injectConditionsFromJoins(size_t from, size_t to, JoinedSelectors&, OnConditionInjections&, int embracedMaxIterations, + h_vector& maxIterations, bool inTransaction, bool enableSortOrders, const RdxContext&); + [[nodiscard]] std::pair queryValuesFromOnCondition(std::string& outExplainStr, AggType&, NamespaceImpl& rightNs, + Query joinQuery, JoinPreResult::CPtr, const QueryJoinEntry&, + CondType, int mainQueryMaxIterations, const RdxContext&); + [[nodiscard]] std::pair queryValuesFromOnCondition(CondType condition, const QueryJoinEntry&, + const JoinedSelector&, const CollateOpts&); + void checkStrictMode(const QueryField&) const; + [[nodiscard]] int calculateMaxIterations(const size_t from, const size_t to, int maxMaxIters, span& maxIterations, + bool inTransaction, bool enableSortOrders, const RdxContext&) const; [[nodiscard]] bool removeBrackets(); [[nodiscard]] size_t removeBrackets(size_t begin, size_t end); [[nodiscard]] bool canRemoveBracket(size_t i) const; @@ -169,10 +169,10 @@ class QueryPreprocessor : private QueryEntries { [[nodiscard]] bool containsJoin(size_t) noexcept; template - void briefDump(size_t from, size_t to, const std::vector &joinedSelectors, WrSerializer &ser) const; + void briefDump(size_t from, size_t to, const std::vector& joinedSelectors, WrSerializer& ser) const; - NamespaceImpl &ns_; - const Query &query_; + NamespaceImpl& ns_; + const Query& query_; StrictMode strictMode_; bool queryEntryAddedByForcedSortOptimization_ = false; bool desc_ = false; diff --git a/cpp_src/core/nsselecter/selectiterator.cc b/cpp_src/core/nsselecter/selectiterator.cc index 816cbcf9b..4007c17bf 100644 --- a/cpp_src/core/nsselecter/selectiterator.cc +++ b/cpp_src/core/nsselecter/selectiterator.cc @@ -39,10 +39,16 @@ std::string_view SelectIterator::TypeName() const noexcept { std::string SelectIterator::Dump() const { std::string ret = name + ' ' + std::string(TypeName()) + "("; - for (auto &it : *this) { - if (it.useBtree_) ret += "btree;"; - if (it.isRange_) ret += "range;"; - if (it.bsearch_) ret += "bsearch;"; + for (auto& it : *this) { + if (it.useBtree_) { + ret += "btree;"; + } + if (it.isRange_) { + ret += "range;"; + } + if (it.bsearch_) { + ret += "bsearch;"; + } ret += ","; if (ret.length() > 256) { ret += "..."; diff --git a/cpp_src/core/nsselecter/selectiterator.h b/cpp_src/core/nsselecter/selectiterator.h index 25e2381ea..07941f405 100644 --- a/cpp_src/core/nsselecter/selectiterator.h +++ b/cpp_src/core/nsselecter/selectiterator.h @@ -23,7 +23,7 @@ class SelectIterator : public SelectKeyResult { UnbuiltSortOrdersIndex, }; - SelectIterator(SelectKeyResult &&res, bool dist, std::string &&n, IteratorFieldKind fKind, bool forcedFirst = false) noexcept + SelectIterator(SelectKeyResult&& res, bool dist, std::string&& n, IteratorFieldKind fKind, bool forcedFirst = false) noexcept : SelectKeyResult(std::move(res)), distinct(dist), name(std::move(n)), @@ -140,7 +140,9 @@ class SelectIterator : public SelectKeyResult { res = nextUnbuiltSortOrders(); break; } - if (res) ++matchedCount_; + if (res) { + ++matchedCount_; + } return res; } @@ -184,9 +186,11 @@ class SelectIterator : public SelectKeyResult { /// Appends result to an existing set. /// @param other - results to add. - void Append(SelectKeyResult &&other) { + void Append(SelectKeyResult&& other) { reserve(size() + other.size()); - for (auto &r : other) emplace_back(std::move(r)); + for (auto& r : other) { + emplace_back(std::move(r)); + } other.clear(); } /// Cost value used for sorting: object with a smaller @@ -216,7 +220,7 @@ class SelectIterator : public SelectKeyResult { /// mode if it's more efficient than just comparing /// each object in sequence. void SetExpectMaxIterations(int expectedIterations) noexcept { - for (SingleSelectKeyResult &r : *this) { + for (SingleSelectKeyResult& r : *this) { if (!r.isRange_ && r.ids_.size() > 1) { int itersloop = r.ids_.size(); int itersbsearch = int((std::log2(r.ids_.size()) - 1) * expectedIterations); @@ -240,7 +244,9 @@ class SelectIterator : public SelectKeyResult { // from minHint which is the least rowId. // Generic next implementation bool nextFwd(IdType minHint) noexcept { - if (minHint > lastVal_) lastVal_ = minHint - 1; + if (minHint > lastVal_) { + lastVal_ = minHint - 1; + } int minVal = INT_MAX; for (auto it = begin(), endIt = end(); it != endIt; ++it) { if (it->useBtree_) { @@ -274,7 +280,9 @@ class SelectIterator : public SelectKeyResult { return lastVal_ != INT_MAX; } bool nextRev(IdType maxHint) noexcept { - if (maxHint < lastVal_) lastVal_ = maxHint + 1; + if (maxHint < lastVal_) { + lastVal_ = maxHint + 1; + } int maxVal = INT_MIN; for (auto it = begin(), endIt = end(); it != endIt; ++it) { @@ -306,18 +314,26 @@ class SelectIterator : public SelectKeyResult { } // Single range next implementation bool nextFwdSingleRange(IdType minHint) noexcept { - if (minHint > lastVal_) lastVal_ = minHint - 1; + if (minHint > lastVal_) { + lastVal_ = minHint - 1; + } const auto begIt = begin(); - if (lastVal_ < begIt->rBegin_) lastVal_ = begIt->rBegin_ - 1; + if (lastVal_ < begIt->rBegin_) { + lastVal_ = begIt->rBegin_ - 1; + } lastVal_ = (lastVal_ < begIt->rEnd_) ? lastVal_ + 1 : begIt->rEnd_; - if (lastVal_ == begIt->rEnd_) lastVal_ = INT_MAX; + if (lastVal_ == begIt->rEnd_) { + lastVal_ = INT_MAX; + } return (lastVal_ != INT_MAX); } // Single idset next implementation bool nextFwdSingleIdset(IdType minHint) noexcept { - if (minHint > lastVal_) lastVal_ = minHint - 1; + if (minHint > lastVal_) { + lastVal_ = minHint - 1; + } auto it = begin(); if (it->useBtree_) { if (it->itset_ != it->setend_ && *it->itset_ <= lastVal_) { @@ -338,17 +354,25 @@ class SelectIterator : public SelectKeyResult { return !(lastVal_ == INT_MAX); } bool nextRevSingleRange(IdType maxHint) noexcept { - if (maxHint < lastVal_) lastVal_ = maxHint + 1; + if (maxHint < lastVal_) { + lastVal_ = maxHint + 1; + } const auto begIt = begin(); - if (lastVal_ > begIt->rrBegin_) lastVal_ = begIt->rrBegin_ + 1; + if (lastVal_ > begIt->rrBegin_) { + lastVal_ = begIt->rrBegin_ + 1; + } lastVal_ = (lastVal_ > begIt->rrEnd_) ? lastVal_ - 1 : begIt->rrEnd_; - if (lastVal_ == begIt->rrEnd_) lastVal_ = INT_MIN; + if (lastVal_ == begIt->rrEnd_) { + lastVal_ = INT_MIN; + } return (lastVal_ != INT_MIN); } bool nextRevSingleIdset(IdType maxHint) noexcept { - if (maxHint < lastVal_) lastVal_ = maxHint + 1; + if (maxHint < lastVal_) { + lastVal_ = maxHint + 1; + } auto it = begin(); diff --git a/cpp_src/core/nsselecter/selectiteratorcontainer.cc b/cpp_src/core/nsselecter/selectiteratorcontainer.cc index e3fa0ec14..21eddbe6e 100644 --- a/cpp_src/core/nsselecter/selectiteratorcontainer.cc +++ b/cpp_src/core/nsselecter/selectiteratorcontainer.cc @@ -24,7 +24,9 @@ void SelectIteratorContainer::SortByCost(int expectedIterations) { if (indexes[i] != i) { size_t positionOfTmp = i + 1; for (; positionOfTmp < indexes.size(); ++positionOfTmp) { - if (indexes[positionOfTmp] == i) break; + if (indexes[positionOfTmp] == i) { + break; + } } assertrx_throw(positionOfTmp < indexes.size()); Container::value_type tmp = std::move(container_[i]); @@ -67,8 +69,8 @@ void SelectIteratorContainer::sortByCost(span indexes, span co break; case 2: { auto it = indexes.begin() + from; - auto &a = *(it++); - auto &b = *(it); + auto& a = *(it++); + auto& b = *(it); if (costs[a] > costs[b]) { std::swap(a, b); } @@ -76,12 +78,18 @@ void SelectIteratorContainer::sortByCost(span indexes, span co } case 3: { auto it = indexes.begin() + from; - auto &a = *(it++); - auto &b = *(it++); - auto &c = *(it); - if (costs[a] > costs[b]) std::swap(a, b); - if (costs[b] > costs[c]) std::swap(b, c); - if (costs[a] > costs[b]) std::swap(a, b); + auto& a = *(it++); + auto& b = *(it++); + auto& c = *(it); + if (costs[a] > costs[b]) { + std::swap(a, b); + } + if (costs[b] > costs[c]) { + std::swap(b, c); + } + if (costs[a] > costs[b]) { + std::swap(a, b); + } break; } default: @@ -101,7 +109,7 @@ bool SelectIteratorContainer::markBracketsHavingJoins(iterator begin, iterator e OneOf>) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(JoinSelectIterator &) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }) || + [] RX_PRE_LMBD_ALWAYS_INLINE(JoinSelectIterator&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }) || result; } return result; @@ -109,7 +117,7 @@ bool SelectIteratorContainer::markBracketsHavingJoins(iterator begin, iterator e bool SelectIteratorContainer::haveJoins(size_t i) const noexcept { return container_[i].Visit( - [] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket &b) RX_POST_LMBD_ALWAYS_INLINE noexcept { return b.haveJoins; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket& b) RX_POST_LMBD_ALWAYS_INLINE noexcept { return b.haveJoins; }, [] RX_PRE_LMBD_ALWAYS_INLINE(OneOf>) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, @@ -153,14 +161,14 @@ void SelectIteratorContainer::moveJoinsToTheBeginingOfORs(span indexes double SelectIteratorContainer::cost(span indexes, unsigned cur, int expectedIterations) const noexcept { return container_[indexes[cur]].Visit( - [&] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket &) + [&] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return cost(indexes, cur + 1, cur + Size(indexes[cur]), expectedIterations); }, Restricted>{}( - [expectedIterations] RX_PRE_LMBD_ALWAYS_INLINE(const auto &c) + [expectedIterations] RX_PRE_LMBD_ALWAYS_INLINE(const auto& c) RX_POST_LMBD_ALWAYS_INLINE noexcept { return c.Cost(expectedIterations); }), - [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinSelectIterator &jit) RX_POST_LMBD_ALWAYS_INLINE noexcept { return jit.Cost(); }, - [expectedIterations] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysTrue &) + [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinSelectIterator& jit) RX_POST_LMBD_ALWAYS_INLINE noexcept { return jit.Cost(); }, + [expectedIterations] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysTrue&) RX_POST_LMBD_ALWAYS_INLINE noexcept -> double { return expectedIterations; }); } @@ -176,7 +184,9 @@ double SelectIteratorContainer::fullCost(span indexes, unsigned cur, u int expectedIterations) const noexcept { double result = 0.0; for (unsigned i = from; i <= cur; i += Size(indexes[i])) { - if (GetOperation(indexes[i]) != OpOr) from = i; + if (GetOperation(indexes[i]) != OpOr) { + from = i; + } } for (; from <= cur || (from < to && GetOperation(indexes[from]) == OpOr); from += Size(indexes[from])) { result += cost(indexes, from, expectedIterations); @@ -190,7 +200,9 @@ bool SelectIteratorContainer::isIdset(const_iterator it, const_iterator end) { bool SelectIteratorContainer::HasIdsets() const { for (const_iterator it = cbegin(), end = cend(); it != end; ++it) { - if (isIdset(it, end)) return true; + if (isIdset(it, end)) { + return true; + } } return false; } @@ -203,7 +215,9 @@ void SelectIteratorContainer::CheckFirstQuery() { Container::iterator src = (++it).PlainIterator() - 1; const Container::iterator dst = begin().PlainIterator(); auto tmp = std::move(*src); - for (; src != dst; --src) *src = std::move(*(src - 1)); + for (; src != dst; --src) { + *src = std::move(*(src - 1)); + } *dst = std::move(tmp); } return; @@ -223,7 +237,7 @@ void SelectIteratorContainer::SetExpectMaxIterations(int expectedIterations) { } } -SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry &qe, const NamespaceImpl &ns, StrictMode strictMode) { +SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry& qe, const NamespaceImpl& ns, StrictMode strictMode) { if (!qe.HaveEmptyField()) { return ComparatorNotIndexed{qe.FieldName(), qe.Condition(), qe.Values(), ns.payloadType_, qe.Fields().getTagsPath(0), qe.Distinct()}; @@ -243,9 +257,9 @@ SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry &qe } template -void SelectIteratorContainer::processField(FieldsComparator &fc, const QueryField &field, const NamespaceImpl &ns) const { +void SelectIteratorContainer::processField(FieldsComparator& fc, const QueryField& field, const NamespaceImpl& ns) const { if (field.IsFieldIndexed()) { - auto &index = ns.indexes_[field.IndexNo()]; + auto& index = ns.indexes_[field.IndexNo()]; if constexpr (left) { fc.SetCollateOpts(index->Opts().collateOpts_); fc.SetLeftField(field.Fields(), field.FieldType(), index->Opts().IsArray()); @@ -264,17 +278,19 @@ void SelectIteratorContainer::processField(FieldsComparator &fc, const QueryFiel } } -SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry &qe, bool enableSortIndexOptimize, const NamespaceImpl &ns, - unsigned sortId, bool isQueryFt, SelectFunction::Ptr &selectFnc, - bool &isIndexFt, bool &isIndexSparse, FtCtx::Ptr &ftCtx, - QueryPreprocessor &qPreproc, const RdxContext &rdxCtx) { - auto &index = ns.indexes_[qe.IndexNo()]; +SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry& qe, bool enableSortIndexOptimize, const NamespaceImpl& ns, + unsigned sortId, bool isQueryFt, SelectFunction::Ptr& selectFnc, + bool& isIndexFt, bool& isIndexSparse, FtCtx::Ptr& ftCtx, + QueryPreprocessor& qPreproc, const RdxContext& rdxCtx) { + auto& index = ns.indexes_[qe.IndexNo()]; isIndexFt = IsFullText(index->Type()); isIndexSparse = index->Opts().IsSparse(); Index::SelectOpts opts; opts.itemsCountInNamespace = ns.itemsCount(); - if (!ns.SortOrdersBuilt()) opts.disableIdSetCache = 1; + if (!ns.SortOrdersBuilt()) { + opts.disableIdSetCache = 1; + } if (isQueryFt) { opts.forceComparator = 1; } @@ -293,10 +309,14 @@ SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry &qe opts.inTransaction = ctx_->inTransaction; auto ctx = selectFnc ? selectFnc->CreateCtx(qe.IndexNo()) : BaseFunctionCtx::Ptr{}; - if (ctx && ctx->type == BaseFunctionCtx::kFtCtx) ftCtx = reindexer::static_ctx_pointer_cast(ctx); + if (ctx && ctx->type == BaseFunctionCtx::kFtCtx) { + ftCtx = reindexer::static_ctx_pointer_cast(ctx); + } if (index->Opts().GetCollateMode() == CollateUTF8 || isIndexFt) { - for (auto &key : qe.Values()) key.EnsureUTF8(); + for (auto& key : qe.Values()) { + key.EnsureUTF8(); + } } PerfStatCalculatorMT calc(index->GetSelectPerfCounter(), ns.enablePerfCounters_); if (qPreproc.IsFtPreselected()) { @@ -306,13 +326,21 @@ SelectKeyResults SelectIteratorContainer::processQueryEntry(const QueryEntry &qe } } -void SelectIteratorContainer::processJoinEntry(const JoinQueryEntry &jqe, OpType op) { - auto &js = (*ctx_->joinedSelectors)[jqe.joinIndex]; - if (js.JoinQuery().joinEntries_.empty()) throw Error(errQueryExec, "Join without ON conditions"); - if (js.JoinQuery().joinEntries_[0].Operation() == OpOr) throw Error(errQueryExec, "The first ON condition cannot have OR operation"); - if (js.Type() != InnerJoin && js.Type() != OrInnerJoin) throw Error(errLogic, "Not INNER JOIN in QueryEntry"); +void SelectIteratorContainer::processJoinEntry(const JoinQueryEntry& jqe, OpType op) { + auto& js = (*ctx_->joinedSelectors)[jqe.joinIndex]; + if (js.JoinQuery().joinEntries_.empty()) { + throw Error(errQueryExec, "Join without ON conditions"); + } + if (js.JoinQuery().joinEntries_[0].Operation() == OpOr) { + throw Error(errQueryExec, "The first ON condition cannot have OR operation"); + } + if (js.Type() != InnerJoin && js.Type() != OrInnerJoin) { + throw Error(errLogic, "Not INNER JOIN in QueryEntry"); + } if (js.Type() == OrInnerJoin) { - if (op == OpNot) throw Error(errQueryExec, "NOT operator with or_inner_join"); + if (op == OpNot) { + throw Error(errQueryExec, "NOT operator with or_inner_join"); + } js.SetType(InnerJoin); op = OpOr; } @@ -322,12 +350,12 @@ void SelectIteratorContainer::processJoinEntry(const JoinQueryEntry &jqe, OpType Append(op, JoinSelectIterator{static_cast(jqe.joinIndex)}); } -void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults &&selectResults, OpType op, const NamespaceImpl &ns, - const QueryEntry &qe, bool isIndexFt, bool isIndexSparse, +void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults&& selectResults, OpType op, const NamespaceImpl& ns, + const QueryEntry& qe, bool isIndexFt, bool isIndexSparse, std::optional nextOp) { std::visit( overloaded{ - [&](SelectKeyResultsVector &selResults) { + [&](SelectKeyResultsVector& selResults) { if (selResults.empty()) { if (op == OpAnd) { SelectKeyResult zeroScan; @@ -336,7 +364,7 @@ void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults &&select } return; } - for (SelectKeyResult &res : selResults) { + for (SelectKeyResult& res : selResults) { switch (op) { case OpOr: { const iterator last = lastAppendedOrClosed(); @@ -345,7 +373,7 @@ void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults &&select } if (last->Is() && !last->Value().distinct && last->operation != OpNot) { using namespace std::string_view_literals; - SelectIterator &it = last->Value(); + SelectIterator& it = last->Value(); it.Append(std::move(res)); it.name.append(" or "sv).append(qe.FieldName()); break; @@ -360,13 +388,17 @@ void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults &&select isIndexFt); if (qe.IsFieldIndexed() && !isIndexSparse) { // last appended is always a SelectIterator - SelectIterator &lastAppended = lastAppendedOrClosed()->Value(); + SelectIterator& lastAppended = lastAppendedOrClosed()->Value(); lastAppended.SetNotOperationFlag(op == OpNot); if (!nextOp.has_value() || nextOp.value() != OpOr) { const auto maxIterations = lastAppended.GetMaxIterations(); const int cur = op == OpNot ? ns.items_.size() - maxIterations : maxIterations; - if (cur && cur < maxIterations_) maxIterations_ = cur; - if (!cur) wasZeroIterations_ = true; + if (cur && cur < maxIterations_) { + maxIterations_ = cur; + } + if (!cur) { + wasZeroIterations_ = true; + } } } break; @@ -380,19 +412,19 @@ void SelectIteratorContainer::processQueryEntryResults(SelectKeyResults &&select } }, Restricted>{}([&](auto &c) { + Template>{}([&](auto& c) { c.SetNotOperationFlag(op == OpNot); Append(op, std::move(c)); })}, selectResults.AsVariant()); } -void SelectIteratorContainer::processEqualPositions(const std::vector &equalPositions, const NamespaceImpl &ns, - const QueryEntries &queries) { - for (const auto &eqPos : equalPositions) { +void SelectIteratorContainer::processEqualPositions(const std::vector& equalPositions, const NamespaceImpl& ns, + const QueryEntries& queries) { + for (const auto& eqPos : equalPositions) { EqualPositionComparator cmp{ns.payloadType_}; for (size_t i = 0, s = eqPos.size(); i < s; ++i) { - const QueryEntry &qe = queries.Get(eqPos[i]); + const QueryEntry& qe = queries.Get(eqPos[i]); if (qe.Condition() == CondEmpty || (qe.Condition() == CondSet && qe.Values().empty())) { throw Error(errLogic, "Condition IN(with empty parameter list), IS NULL, IS EMPTY not allowed for equal position!"); } @@ -409,17 +441,19 @@ void SelectIteratorContainer::processEqualPositions(const std::vector SelectIteratorContainer::prepareEqualPositions(const QueryEntries &queries, +std::vector SelectIteratorContainer::prepareEqualPositions(const QueryEntries& queries, size_t begin, size_t end) { static const auto getFieldsStr = [](auto begin, auto end) { std::stringstream str; for (auto it = begin; it != end; ++it) { - if (it != begin) str << ", "; + if (it != begin) { + str << ", "; + } str << *it; } return str.str(); }; - const auto &eqPos = (begin == 0 ? queries.equalPositions : queries.Get(begin - 1).equalPositions); + const auto& eqPos = (begin == 0 ? queries.equalPositions : queries.Get(begin - 1).equalPositions); std::vector result{eqPos.size()}; for (size_t i = 0; i < eqPos.size(); ++i) { if (eqPos[i].size() < 2) { @@ -435,15 +469,17 @@ std::vector SelectIteratorContainer::pr for (size_t j = begin, next; j < end; j = next) { next = queries.Next(j); queries.Visit( - j, Skip{}, [](const SubQueryEntry &) { throw_as_assert; }, - [](const SubQueryFieldEntry &) { throw_as_assert; }, - [&](const QueryEntry &eq) { + j, Skip{}, [](const SubQueryEntry&) { throw_as_assert; }, + [](const SubQueryFieldEntry&) { throw_as_assert; }, + [&](const QueryEntry& eq) { if (foundFields.find(eq.FieldName()) != foundFields.end()) { throw Error(errParams, "Equal position field '%s' found twice in enclosing bracket; equal position fields: [%s]", eq.FieldName(), getEpFieldsStr()); } const auto it = epFields.find(eq.FieldName()); - if (it == epFields.end()) return; + if (it == epFields.end()) { + return; + } if (queries.GetOperation(j) != OpAnd || (next < end && queries.GetOperation(next) == OpOr)) { throw Error(errParams, "Only AND operation allowed for equal position; equal position field with not AND operation: '%s'; " @@ -453,7 +489,7 @@ std::vector SelectIteratorContainer::pr result[i].push_back(j); foundFields.insert(epFields.extract(it)); }, - [&](const BetweenFieldsQueryEntry &eq) { // TODO equal positions for BetweenFieldsQueryEntry #1092 + [&](const BetweenFieldsQueryEntry& eq) { // TODO equal positions for BetweenFieldsQueryEntry #1092 if (epFields.find(eq.LeftFieldName()) != epFields.end()) { throw Error( errParams, @@ -476,16 +512,16 @@ std::vector SelectIteratorContainer::pr return result; } -void SelectIteratorContainer::PrepareIteratorsForSelectLoop(QueryPreprocessor &qPreproc, unsigned sortId, bool isFt, - const NamespaceImpl &ns, SelectFunction::Ptr &selectFnc, FtCtx::Ptr &ftCtx, - const RdxContext &rdxCtx) { +void SelectIteratorContainer::PrepareIteratorsForSelectLoop(QueryPreprocessor& qPreproc, unsigned sortId, bool isFt, + const NamespaceImpl& ns, SelectFunction::Ptr& selectFnc, FtCtx::Ptr& ftCtx, + const RdxContext& rdxCtx) { prepareIteratorsForSelectLoop(qPreproc, 0, qPreproc.Size(), sortId, isFt, ns, selectFnc, ftCtx, rdxCtx); } -bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor &qPreproc, size_t begin, size_t end, unsigned sortId, - bool isQueryFt, const NamespaceImpl &ns, SelectFunction::Ptr &selectFnc, - FtCtx::Ptr &ftCtx, const RdxContext &rdxCtx) { - const auto &queries = qPreproc.GetQueryEntries(); +bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor& qPreproc, size_t begin, size_t end, unsigned sortId, + bool isQueryFt, const NamespaceImpl& ns, SelectFunction::Ptr& selectFnc, + FtCtx::Ptr& ftCtx, const RdxContext& rdxCtx) { + const auto& queries = qPreproc.GetQueryEntries(); auto equalPositions = prepareEqualPositions(queries, begin, end); bool sortIndexFound = false; bool containFT = false; @@ -494,8 +530,8 @@ bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor &q const OpType op = queries.GetOperation(i); containFT = queries.Visit( - i, [](const SubQueryEntry &) -> bool { throw_as_assert; }, [](const SubQueryFieldEntry &) -> bool { throw_as_assert; }, - [&](const QueryEntriesBracket &) { + i, [](const SubQueryEntry&) -> bool { throw_as_assert; }, [](const SubQueryFieldEntry&) -> bool { throw_as_assert; }, + [&](const QueryEntriesBracket&) { OpenBracket(op); const bool contFT = prepareIteratorsForSelectLoop(qPreproc, i + 1, next, sortId, isQueryFt, ns, selectFnc, ftCtx, rdxCtx); @@ -505,7 +541,7 @@ bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor &q CloseBracket(); return contFT; }, - [&](const QueryEntry &qe) { + [&](const QueryEntry& qe) { const bool isFT = qe.IsFieldIndexed() && IsFullText(ns.indexes_[qe.IndexNo()]->Type()); if (isFT && (op == OpOr || (next < end && queries.GetOperation(next) == OpOr))) { throw Error(errLogic, "OR operation is not allowed with fulltext index"); @@ -544,24 +580,24 @@ bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor &q processQueryEntryResults(std::move(selectResults), op, ns, qe, isIndexFt, isIndexSparse, nextOp); return isFT; }, - [this, op](const JoinQueryEntry &jqe) { + [this, op](const JoinQueryEntry& jqe) { processJoinEntry(jqe, op); return false; }, - [&](const BetweenFieldsQueryEntry &qe) { + [&](const BetweenFieldsQueryEntry& qe) { FieldsComparator fc{qe.LeftFieldName(), qe.Condition(), qe.RightFieldName(), ns.payloadType_}; processField(fc, qe.LeftFieldData(), ns); processField(fc, qe.RightFieldData(), ns); Append(op, std::move(fc)); return false; }, - [this, op](const AlwaysFalse &) { + [this, op](const AlwaysFalse&) { SelectKeyResult zeroScan; zeroScan.emplace_back(0, 0); Append(op, SelectIterator{std::move(zeroScan), false, "always_false", IteratorFieldKind::None, true}); return false; }, - [this, op](const AlwaysTrue &) { + [this, op](const AlwaysTrue&) { Append(op, AlwaysTrue{}); return false; }) || @@ -572,7 +608,7 @@ bool SelectIteratorContainer::prepareIteratorsForSelectLoop(QueryPreprocessor &q } template -RX_ALWAYS_INLINE bool SelectIteratorContainer::checkIfSatisfyCondition(SelectIterator &it, bool *finish, IdType rowId) { +RX_ALWAYS_INLINE bool SelectIteratorContainer::checkIfSatisfyCondition(SelectIterator& it, bool* finish, IdType rowId) { if constexpr (reverse) { while (it.Val() > rowId && it.Next(rowId)) { } @@ -591,16 +627,16 @@ RX_ALWAYS_INLINE bool SelectIteratorContainer::checkIfSatisfyCondition(SelectIte } } -RX_ALWAYS_INLINE bool SelectIteratorContainer::checkIfSatisfyCondition(JoinSelectIterator &it, PayloadValue &pv, IdType properRowId, +RX_ALWAYS_INLINE bool SelectIteratorContainer::checkIfSatisfyCondition(JoinSelectIterator& it, PayloadValue& pv, IdType properRowId, bool match) { assertrx_throw(ctx_->joinedSelectors); ConstPayload pl(*pt_, pv); - auto &joinedSelector = (*ctx_->joinedSelectors)[it.joinIndex]; + auto& joinedSelector = (*ctx_->joinedSelectors)[it.joinIndex]; return joinedSelector.Process(properRowId, ctx_->nsid, pl, match); } template -bool SelectIteratorContainer::checkIfSatisfyAllConditions(iterator begin, iterator end, PayloadValue &pv, bool *finish, IdType rowId, +bool SelectIteratorContainer::checkIfSatisfyAllConditions(iterator begin, iterator end, PayloadValue& pv, bool* finish, IdType rowId, IdType properRowId, bool match) { bool result = true; bool currentFinish = false; @@ -611,22 +647,24 @@ bool SelectIteratorContainer::checkIfSatisfyAllConditions(iterator begin, iterat // suggest that all JOINs in chain of OR ... OR ... OR ... OR will be before all not JOINs (see SortByCost) if (result) { // check what it does not holds join - if (it->Visit([] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket &b) + if (it->Visit([] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket& b) RX_POST_LMBD_ALWAYS_INLINE noexcept { return !b.haveJoins; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinSelectIterator &) - RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinSelectIterator&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, [] RX_PRE_LMBD_ALWAYS_INLINE( OneOf>) - RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; })) + RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; })) { continue; + } } } else { - if (!result) break; + if (!result) { + break; + } } bool lastFinish = false; const bool lastResult = it->Visit( - [&] RX_PRE_LMBD_ALWAYS_INLINE(SelectIteratorsBracket &) RX_POST_LMBD_ALWAYS_INLINE { + [&] RX_PRE_LMBD_ALWAYS_INLINE(SelectIteratorsBracket&) RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyAllConditions(it.begin(), it.end(), pv, &lastFinish, rowId, properRowId, match); }, @@ -636,8 +674,8 @@ bool SelectIteratorContainer::checkIfSatisfyAllConditions(iterator begin, iterat RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyCondition(jit, pv, properRowId, match); }, Restricted>{}( - [&pv, properRowId] RX_PRE_LMBD_ALWAYS_INLINE(auto &c) RX_POST_LMBD_ALWAYS_INLINE { return c.Compare(pv, properRowId); }), - [] RX_PRE_LMBD_ALWAYS_INLINE(AlwaysTrue &) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }); + [&pv, properRowId] RX_PRE_LMBD_ALWAYS_INLINE(auto& c) RX_POST_LMBD_ALWAYS_INLINE { return c.Compare(pv, properRowId); }), + [] RX_PRE_LMBD_ALWAYS_INLINE(AlwaysTrue&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }); if (op == OpOr) { result |= lastResult; currentFinish &= (!result && lastFinish); @@ -649,7 +687,9 @@ bool SelectIteratorContainer::checkIfSatisfyAllConditions(iterator begin, iterat currentFinish = false; } } - if (!result) *finish = currentFinish; + if (!result) { + *finish = currentFinish; + } return result; } @@ -660,15 +700,23 @@ IdType SelectIteratorContainer::getNextItemId(const_iterator begin, const_iterat switch (it->operation) { case OpOr: { auto next = it->Visit( - [it, from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket &) + [it, from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket&) RX_POST_LMBD_ALWAYS_INLINE { return getNextItemId(it.cbegin(), it.cend(), from); }, - [from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator &sit) RX_POST_LMBD_ALWAYS_INLINE { + [from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator& sit) RX_POST_LMBD_ALWAYS_INLINE { if constexpr (reverse) { - if (sit.End()) return std::numeric_limits::lowest(); - if (sit.Val() < from) return sit.Val() + 1; + if (sit.End()) { + return std::numeric_limits::lowest(); + } + if (sit.Val() < from) { + return sit.Val() + 1; + } } else { - if (sit.End()) return std::numeric_limits::max(); - if (sit.Val() > from) return sit.Val() - 1; + if (sit.End()) { + return std::numeric_limits::max(); + } + if (sit.Val() > from) { + return sit.Val() - 1; + } } return from; }, @@ -676,7 +724,7 @@ IdType SelectIteratorContainer::getNextItemId(const_iterator begin, const_iterat const OneOf>) RX_POST_LMBD_ALWAYS_INLINE { return from; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse &) RX_POST_LMBD_ALWAYS_INLINE { + [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse&) RX_POST_LMBD_ALWAYS_INLINE { return reverse ? std::numeric_limits::lowest() : std::numeric_limits::max(); }); if constexpr (reverse) { @@ -688,15 +736,23 @@ IdType SelectIteratorContainer::getNextItemId(const_iterator begin, const_iterat case OpAnd: from = result; result = it->Visit( - [it, from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket &) + [it, from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIteratorsBracket&) RX_POST_LMBD_ALWAYS_INLINE { return getNextItemId(it.cbegin(), it.cend(), from); }, - [from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator &sit) RX_POST_LMBD_ALWAYS_INLINE { + [from] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator& sit) RX_POST_LMBD_ALWAYS_INLINE { if constexpr (reverse) { - if (sit.End()) return std::numeric_limits::lowest(); - if (sit.Val() < from) return sit.Val() + 1; + if (sit.End()) { + return std::numeric_limits::lowest(); + } + if (sit.Val() < from) { + return sit.Val() + 1; + } } else { - if (sit.End()) return std::numeric_limits::max(); - if (sit.Val() > from) return sit.Val() - 1; + if (sit.End()) { + return std::numeric_limits::max(); + } + if (sit.Val() > from) { + return sit.Val() - 1; + } } return from; }, @@ -704,7 +760,7 @@ IdType SelectIteratorContainer::getNextItemId(const_iterator begin, const_iterat const OneOf>) RX_POST_LMBD_ALWAYS_INLINE { return from; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse &) RX_POST_LMBD_ALWAYS_INLINE { + [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse&) RX_POST_LMBD_ALWAYS_INLINE { return reverse ? std::numeric_limits::lowest() : std::numeric_limits::max(); }); break; @@ -716,7 +772,7 @@ IdType SelectIteratorContainer::getNextItemId(const_iterator begin, const_iterat } template -bool SelectIteratorContainer::Process(PayloadValue &pv, bool *finish, IdType *rowId, IdType properRowId, bool match) { +bool SelectIteratorContainer::Process(PayloadValue& pv, bool* finish, IdType* rowId, IdType properRowId, bool match) { if (auto it = begin(); checkIfSatisfyAllConditions(++it, end(), pv, finish, *rowId, properRowId, match)) { return true; } @@ -724,10 +780,10 @@ bool SelectIteratorContainer::Process(PayloadValue &pv, bool *finish, IdType *ro return false; } -template bool SelectIteratorContainer::Process(PayloadValue &, bool *, IdType *, IdType, bool); -template bool SelectIteratorContainer::Process(PayloadValue &, bool *, IdType *, IdType, bool); -template bool SelectIteratorContainer::Process(PayloadValue &, bool *, IdType *, IdType, bool); -template bool SelectIteratorContainer::Process(PayloadValue &, bool *, IdType *, IdType, bool); +template bool SelectIteratorContainer::Process(PayloadValue&, bool*, IdType*, IdType, bool); +template bool SelectIteratorContainer::Process(PayloadValue&, bool*, IdType*, IdType, bool); +template bool SelectIteratorContainer::Process(PayloadValue&, bool*, IdType*, IdType, bool); +template bool SelectIteratorContainer::Process(PayloadValue&, bool*, IdType*, IdType, bool); std::string SelectIteratorContainer::Dump() const { WrSerializer ser; @@ -736,7 +792,7 @@ std::string SelectIteratorContainer::Dump() const { } void SelectIteratorContainer::dump(size_t level, const_iterator begin, const_iterator end, - const std::vector &joinedSelectors, WrSerializer &ser) { + const std::vector& joinedSelectors, WrSerializer& ser) { for (const_iterator it = begin; it != end; ++it) { for (size_t i = 0; i < level; ++i) { ser << " "; @@ -745,7 +801,7 @@ void SelectIteratorContainer::dump(size_t level, const_iterator begin, const_ite ser << it->operation << ' '; } it->Visit( - [&](const SelectIteratorsBracket &) { + [&](const SelectIteratorsBracket&) { ser << "(\n"; dump(level + 1, it.cbegin(), it.cend(), joinedSelectors, ser); for (size_t i = 0; i < level; ++i) { @@ -755,19 +811,19 @@ void SelectIteratorContainer::dump(size_t level, const_iterator begin, const_ite }, Restricted>{}( - [&ser](const auto &c) { ser << c.Dump(); }), - [&ser, &joinedSelectors](const JoinSelectIterator &jit) { jit.Dump(ser, joinedSelectors); }, - [&ser](const AlwaysTrue &) { ser << "Always True"; }); + [&ser](const auto& c) { ser << c.Dump(); }), + [&ser, &joinedSelectors](const JoinSelectIterator& jit) { jit.Dump(ser, joinedSelectors); }, + [&ser](const AlwaysTrue&) { ser << "Always True"; }); ser << '\n'; } } -void JoinSelectIterator::Dump(WrSerializer &ser, const std::vector &joinedSelectors) const { - const auto &js = joinedSelectors.at(joinIndex); - const auto &q = js.JoinQuery(); +void JoinSelectIterator::Dump(WrSerializer& ser, const std::vector& joinedSelectors) const { + const auto& js = joinedSelectors.at(joinIndex); + const auto& q = js.JoinQuery(); ser << js.Type() << " (" << q.GetSQL() << ") ON "; ser << '('; - for (const auto &jqe : q.joinEntries_) { + for (const auto& jqe : q.joinEntries_) { if (&jqe != &q.joinEntries_.front()) { ser << ' ' << jqe.Operation() << ' '; } else { diff --git a/cpp_src/core/nsselecter/selectiteratorcontainer.h b/cpp_src/core/nsselecter/selectiteratorcontainer.h index e53eb8501..4f23b5446 100644 --- a/cpp_src/core/nsselecter/selectiteratorcontainer.h +++ b/cpp_src/core/nsselecter/selectiteratorcontainer.h @@ -21,14 +21,14 @@ class QueryPreprocessor; struct JoinSelectIterator { size_t joinIndex; double Cost() const noexcept { return std::numeric_limits::max(); } - void Dump(WrSerializer &, const std::vector &) const; + void Dump(WrSerializer&, const std::vector&) const; }; struct SelectIteratorsBracket : private Bracket { using Bracket::Bracket; using Bracket::Size; using Bracket::Append; - void CopyPayloadFrom(const SelectIteratorsBracket &other) noexcept { haveJoins = other.haveJoins; } + void CopyPayloadFrom(const SelectIteratorsBracket& other) noexcept { haveJoins = other.haveJoins; } bool haveJoins = false; }; @@ -43,7 +43,7 @@ class SelectIteratorContainer ComparatorIndexed, EqualPositionComparator, ComparatorNotIndexed>; public: - SelectIteratorContainer(PayloadType pt = PayloadType(), SelectCtx *ctx = nullptr) + SelectIteratorContainer(PayloadType pt = PayloadType(), SelectCtx* ctx = nullptr) : pt_(std::move(pt)), ctx_(ctx), maxIterations_(std::numeric_limits::max()), wasZeroIterations_(false) {} void SortByCost(int expectedIterations); @@ -52,10 +52,10 @@ class SelectIteratorContainer void CheckFirstQuery(); // Let iterators choose most effecive algorith void SetExpectMaxIterations(int expectedIterations); - void PrepareIteratorsForSelectLoop(QueryPreprocessor &, unsigned sortId, bool isFt, const NamespaceImpl &, SelectFunction::Ptr &, - FtCtx::Ptr &, const RdxContext &); + void PrepareIteratorsForSelectLoop(QueryPreprocessor&, unsigned sortId, bool isFt, const NamespaceImpl&, SelectFunction::Ptr&, + FtCtx::Ptr&, const RdxContext&); template - bool Process(PayloadValue &, bool *finish, IdType *rowId, IdType, bool match); + bool Process(PayloadValue&, bool* finish, IdType* rowId, IdType, bool match); bool IsSelectIterator(size_t i) const noexcept { assertrx_throw(i < Size()); @@ -71,12 +71,12 @@ class SelectIteratorContainer [] RX_PRE_LMBD_ALWAYS_INLINE( OneOf) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator &sit) RX_POST_LMBD_ALWAYS_INLINE noexcept { return sit.distinct; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const SelectIterator& sit) RX_POST_LMBD_ALWAYS_INLINE noexcept { return sit.distinct; }, Restricted>{}( - [] RX_PRE_LMBD_ALWAYS_INLINE(const auto &comp) RX_POST_LMBD_ALWAYS_INLINE noexcept { return comp.IsDistinct(); })); + [] RX_PRE_LMBD_ALWAYS_INLINE(const auto& comp) RX_POST_LMBD_ALWAYS_INLINE noexcept { return comp.IsDistinct(); })); } - void ExplainJSON(int iters, JsonBuilder &builder, const std::vector *js) const { + void ExplainJSON(int iters, JsonBuilder& builder, const std::vector* js) const { explainJSON(cbegin(), cend(), iters, builder, js); } @@ -87,60 +87,66 @@ class SelectIteratorContainer } int GetMaxIterations(bool withZero = false) const noexcept { return (withZero && wasZeroIterations_) ? 0 : maxIterations_; } std::string Dump() const; - static bool IsExpectingOrderedResults(const QueryEntry &qe) noexcept { + static bool IsExpectingOrderedResults(const QueryEntry& qe) noexcept { return IsOrderedCondition(qe.Condition()) || (qe.Condition() != CondAny && qe.Values().size() <= 1); } private: - bool prepareIteratorsForSelectLoop(QueryPreprocessor &, size_t begin, size_t end, unsigned sortId, bool isFt, const NamespaceImpl &, - SelectFunction::Ptr &, FtCtx::Ptr &, const RdxContext &); + bool prepareIteratorsForSelectLoop(QueryPreprocessor&, size_t begin, size_t end, unsigned sortId, bool isFt, const NamespaceImpl&, + SelectFunction::Ptr&, FtCtx::Ptr&, const RdxContext&); void sortByCost(span indexes, span costs, unsigned from, unsigned to, int expectedIterations); double fullCost(span indexes, unsigned i, unsigned from, unsigned to, int expectedIterations) const noexcept; double cost(span indexes, unsigned cur, int expectedIterations) const noexcept; double cost(span indexes, unsigned from, unsigned to, int expectedIterations) const noexcept; void moveJoinsToTheBeginingOfORs(span indexes, unsigned from, unsigned to); // Check idset must be 1st - static void checkFirstQuery(Container &); + static void checkFirstQuery(Container&); template - bool checkIfSatisfyCondition(SelectIterator &, bool *finish, IdType rowId); - bool checkIfSatisfyCondition(JoinSelectIterator &, PayloadValue &, IdType properRowId, bool match); + bool checkIfSatisfyCondition(SelectIterator&, bool* finish, IdType rowId); + bool checkIfSatisfyCondition(JoinSelectIterator&, PayloadValue&, IdType properRowId, bool match); template - bool checkIfSatisfyAllConditions(iterator begin, iterator end, PayloadValue &, bool *finish, IdType rowId, IdType properRowId, + bool checkIfSatisfyAllConditions(iterator begin, iterator end, PayloadValue&, bool* finish, IdType rowId, IdType properRowId, bool match); - static std::string explainJSON(const_iterator it, const_iterator to, int iters, JsonBuilder &builder, - const std::vector *); + static std::string explainJSON(const_iterator it, const_iterator to, int iters, JsonBuilder& builder, + const std::vector*); template static IdType getNextItemId(const_iterator begin, const_iterator end, IdType from); static bool isIdset(const_iterator it, const_iterator end); static bool markBracketsHavingJoins(iterator begin, iterator end) noexcept; bool haveJoins(size_t i) const noexcept; - SelectKeyResults processQueryEntry(const QueryEntry &qe, const NamespaceImpl &ns, StrictMode strictMode); - SelectKeyResults processQueryEntry(const QueryEntry &qe, bool enableSortIndexOptimize, const NamespaceImpl &ns, unsigned sortId, - bool isQueryFt, SelectFunction::Ptr &selectFnc, bool &isIndexFt, bool &isIndexSparse, FtCtx::Ptr &, - QueryPreprocessor &qPreproc, const RdxContext &); + SelectKeyResults processQueryEntry(const QueryEntry& qe, const NamespaceImpl& ns, StrictMode strictMode); + SelectKeyResults processQueryEntry(const QueryEntry& qe, bool enableSortIndexOptimize, const NamespaceImpl& ns, unsigned sortId, + bool isQueryFt, SelectFunction::Ptr& selectFnc, bool& isIndexFt, bool& isIndexSparse, FtCtx::Ptr&, + QueryPreprocessor& qPreproc, const RdxContext&); template - void processField(FieldsComparator &, const QueryField &, const NamespaceImpl &) const; - void processJoinEntry(const JoinQueryEntry &, OpType); - void processQueryEntryResults(SelectKeyResults &&, OpType, const NamespaceImpl &, const QueryEntry &, bool isIndexFt, - bool isIndexSparse, std::optional nextOp); + void processField(FieldsComparator&, const QueryField&, const NamespaceImpl&) const; + void processJoinEntry(const JoinQueryEntry&, OpType); + void processQueryEntryResults(SelectKeyResults&&, OpType, const NamespaceImpl&, const QueryEntry&, bool isIndexFt, bool isIndexSparse, + std::optional nextOp); using EqualPositions = h_vector; - void processEqualPositions(const std::vector &equalPositions, const NamespaceImpl &ns, const QueryEntries &queries); - static std::vector prepareEqualPositions(const QueryEntries &queries, size_t begin, size_t end); + void processEqualPositions(const std::vector& equalPositions, const NamespaceImpl& ns, const QueryEntries& queries); + static std::vector prepareEqualPositions(const QueryEntries& queries, size_t begin, size_t end); /// @return end() if empty or last opened bracket is empty iterator lastAppendedOrClosed() { typename Container::iterator it = this->container_.begin(), end = this->container_.end(); - if (!this->activeBrackets_.empty()) it += (this->activeBrackets_.back() + 1); - if (it == end) return this->end(); + if (!this->activeBrackets_.empty()) { + it += (this->activeBrackets_.back() + 1); + } + if (it == end) { + return this->end(); + } iterator i = it, i2 = it, e = end; - while (++i2 != e) i = i2; + while (++i2 != e) { + i = i2; + } return i; } - static void dump(size_t level, const_iterator begin, const_iterator end, const std::vector &, WrSerializer &); + static void dump(size_t level, const_iterator begin, const_iterator end, const std::vector&, WrSerializer&); PayloadType pt_; - SelectCtx *ctx_; + SelectCtx* ctx_; int maxIterations_; bool wasZeroIterations_; }; diff --git a/cpp_src/core/nsselecter/sortexpression.cc b/cpp_src/core/nsselecter/sortexpression.cc index 6741df102..7acaa9d3e 100644 --- a/cpp_src/core/nsselecter/sortexpression.cc +++ b/cpp_src/core/nsselecter/sortexpression.cc @@ -11,7 +11,7 @@ namespace { -static RX_NO_INLINE void throwParseError(const std::string_view sortExpr, char const* const pos, const std::string_view message) { +static RX_NO_INLINE void throwParseError(const std::string_view sortExpr, const char* const pos, const std::string_view message) { throw reindexer::Error(errParams, "'%s' is not valid sort expression. Parser failed at position %d.%s%s", sortExpr, pos - sortExpr.data(), message.empty() ? "" : " ", message); } @@ -51,8 +51,12 @@ const PayloadValue& SortExpression::getJoinedValue(IdType rowId, const joins::Na const auto& js = joinedSelectors[nsIdx]; const joins::ItemIterator jIt{&joinResults, rowId}; const auto jfIt = jIt.at(nsIdx); - if (jfIt == jIt.end() || jfIt.ItemsCount() == 0) throw Error(errQueryExec, "Not found value joined from ns %s", js.RightNsName()); - if (jfIt.ItemsCount() > 1) throw Error(errQueryExec, "Found more than 1 value joined from ns %s", js.RightNsName()); + if (jfIt == jIt.end() || jfIt.ItemsCount() == 0) { + throw Error(errQueryExec, "Not found value joined from ns %s", js.RightNsName()); + } + if (jfIt.ItemsCount() > 1) { + throw Error(errQueryExec, "Found more than 1 value joined from ns %s", js.RightNsName()); + } return jfIt[0].Value(); } @@ -60,11 +64,11 @@ VariantArray SortExpression::GetJoinedFieldValues(IdType rowId, const joins::Nam const std::vector& joinedSelectors, size_t nsIdx, std::string_view column, int index) { const auto& js = joinedSelectors[nsIdx]; - std::reference_wrapper pt = std::visit( - overloaded{ - [](const JoinPreResult::Values& values) noexcept { return std::cref(values.payloadType); }, - Restricted{}([&js](const auto&) noexcept { return std::cref(js.rightNs_->payloadType_); })}, - js.PreResult().payload); + std::reference_wrapper pt = + std::visit(overloaded{[](const JoinPreResult::Values& values) noexcept { return std::cref(values.payloadType); }, + Restricted{}( + [&js](const auto&) noexcept { return std::cref(js.rightNs_->payloadType_); })}, + js.PreResult().payload); const ConstPayload pv{pt, getJoinedValue(rowId, joinResults, joinedSelectors, nsIdx)}; VariantArray values; if (index == IndexValueType::SetByJsonPath) { @@ -96,7 +100,9 @@ const SortExprFuncs::JoinedIndex& SortExpression::GetJoinedIndex() const noexcep double SortExprFuncs::Index::GetValue(ConstPayload pv, TagsMatcher& tagsMatcher) const { const VariantArray values = getFieldValues(pv, tagsMatcher, index, column); - if (values.empty()) throw Error(errQueryExec, "Empty field in sort expression: %s", column); + if (values.empty()) { + throw Error(errQueryExec, "Empty field in sort expression: %s", column); + } if (values.size() > 1 || values[0].Type().Is() || values[0].Type().Is()) { throw Error(errQueryExec, "Array, composite or tuple field in sort expression"); } @@ -111,7 +117,9 @@ double DistanceFromPoint::GetValue(ConstPayload pv, TagsMatcher& tagsMatcher) co double JoinedIndex::GetValue(IdType rowId, const joins::NamespaceResults& joinResults, const std::vector& joinedSelectors) const { const VariantArray values = SortExpression::GetJoinedFieldValues(rowId, joinResults, joinedSelectors, nsIdx, column, index); - if (values.empty()) throw Error(errQueryExec, "Empty field in sort expression: %s %s", joinedSelectors[nsIdx].RightNsName(), column); + if (values.empty()) { + throw Error(errQueryExec, "Empty field in sort expression: %s %s", joinedSelectors[nsIdx].RightNsName(), column); + } if (values.size() > 1 || values[0].Type().Is() || values[0].Type().Is()) { throw Error(errQueryExec, "Array, composite or tuple field in sort expression"); } @@ -148,11 +156,11 @@ double DistanceBetweenJoinedIndexes::GetValue(IdType rowId, const joins::Namespa double DistanceBetweenJoinedIndexesSameNs::GetValue(IdType rowId, const joins::NamespaceResults& joinResults, const std::vector& joinedSelectors) const { const auto& js = joinedSelectors[nsIdx]; - std::reference_wrapper pt = std::visit( - overloaded{ - [](const JoinPreResult::Values& values) noexcept { return std::cref(values.payloadType); }, - Restricted{}([&js](const auto&) noexcept { return std::cref(js.rightNs_->payloadType_); })}, - js.PreResult().payload); + std::reference_wrapper pt = + std::visit(overloaded{[](const JoinPreResult::Values& values) noexcept { return std::cref(values.payloadType); }, + Restricted{}( + [&js](const auto&) noexcept { return std::cref(js.rightNs_->payloadType_); })}, + js.PreResult().payload); const ConstPayload pv{pt, SortExpression::getJoinedValue(rowId, joinResults, joinedSelectors, nsIdx)}; TagsMatcher tm = std::visit(overloaded{[](const JoinPreResult::Values& values) noexcept { return std::cref(values.tagsMatcher); }, Restricted{}( @@ -204,7 +212,9 @@ static ParseIndexNameResult parseIndexName(std::string_view& expr, const std: const auto end = expr.data() + expr.size(); auto joinedSelectorIt = joinedSelectors.cend(); bool joinedFieldInQuotes = false; - while (pos != end && *pos != '.' && kIndexNameSyms.test(*pos)) ++pos; + while (pos != end && *pos != '.' && kIndexNameSyms.test(*pos)) { + ++pos; + } if (pos != end && *pos == '.') { std::string_view namespaceName = {expr.data(), static_cast(pos - expr.data())}; @@ -228,7 +238,9 @@ static ParseIndexNameResult parseIndexName(std::string_view& expr, const std: joinedFieldInQuotes = false; } } - while (pos != end && kIndexNameSyms.test(*pos)) ++pos; + while (pos != end && kIndexNameSyms.test(*pos)) { + ++pos; + } std::string_view name{expr.data(), static_cast(pos - expr.data())}; if (name.empty()) { throwParseError(fullExpr, pos, "Expected index or function name."); @@ -264,53 +276,72 @@ static Point parsePoint(std::string_view& expr, std::string_view funcName, const } expr.remove_prefix(1); skipSpaces(); - if (expr.empty() || (expr[0] != '\'' && expr[0] != '"')) throwParseError(fullExpr, expr.data(), "Expected \" or '."); + if (expr.empty() || (expr[0] != '\'' && expr[0] != '"')) { + throwParseError(fullExpr, expr.data(), "Expected \" or '."); + } const char openQuote = expr[0]; expr.remove_prefix(1); skipSpaces(); - if (!checkIfStartsWith("point"sv, expr)) throwParseError(fullExpr, expr.data(), "Expected 'point'."); + if (!checkIfStartsWith("point"sv, expr)) { + throwParseError(fullExpr, expr.data(), "Expected 'point'."); + } expr.remove_prefix(5); skipSpaces(); - if (expr.empty() || expr[0] != '(') throwParseError(fullExpr, expr.data(), "Expected '('."); + if (expr.empty() || expr[0] != '(') { + throwParseError(fullExpr, expr.data(), "Expected '('."); + } expr.remove_prefix(1); skipSpaces(); int countOfCharsParsedAsDouble = 0; const double x = converter.StringToDouble(expr.data(), expr.size(), &countOfCharsParsedAsDouble); - if (countOfCharsParsedAsDouble == 0) throwParseError(fullExpr, expr.data(), "Expected number."); + if (countOfCharsParsedAsDouble == 0) { + throwParseError(fullExpr, expr.data(), "Expected number."); + } expr.remove_prefix(countOfCharsParsedAsDouble); skipSpaces(); countOfCharsParsedAsDouble = 0; const double y = converter.StringToDouble(expr.data(), expr.size(), &countOfCharsParsedAsDouble); - if (countOfCharsParsedAsDouble == 0) throwParseError(fullExpr, expr.data(), "Expected number."); + if (countOfCharsParsedAsDouble == 0) { + throwParseError(fullExpr, expr.data(), "Expected number."); + } expr.remove_prefix(countOfCharsParsedAsDouble); skipSpaces(); - if (expr.empty() || expr[0] != ')') throwParseError(fullExpr, expr.data(), "Expected ')'."); + if (expr.empty() || expr[0] != ')') { + throwParseError(fullExpr, expr.data(), "Expected ')'."); + } expr.remove_prefix(1); skipSpaces(); - if (expr.empty() || expr[0] != openQuote) throwParseError(fullExpr, expr.data(), std::string("Expected ") + openQuote + '.'); + if (expr.empty() || expr[0] != openQuote) { + throwParseError(fullExpr, expr.data(), std::string("Expected ") + openQuote + '.'); + } expr.remove_prefix(1); skipSpaces(); - if (expr.empty() || expr[0] != ')') throwParseError(fullExpr, expr.data(), "Expected ')'."); + if (expr.empty() || expr[0] != ')') { + throwParseError(fullExpr, expr.data(), "Expected ')'."); + } expr.remove_prefix(1); return Point{x, y}; } template -void SortExpression::parseDistance(std::string_view& expr, const std::vector& joinedSelectors, std::string_view const fullExpr, +void SortExpression::parseDistance(std::string_view& expr, const std::vector& joinedSelectors, const std::string_view fullExpr, const ArithmeticOpType op, const bool negative, const SkipSW& skipSpaces) { skipSpaces(); const auto parsedIndexName1 = parseIndexName(expr, joinedSelectors, fullExpr); skipSpaces(); if (parsedIndexName1.joinedSelectorIt != joinedSelectors.cend()) { - if (expr.empty() || expr[0] != ',') throwParseError(fullExpr, expr.data(), "Expected ','."); + if (expr.empty() || expr[0] != ',') { + throwParseError(fullExpr, expr.data(), "Expected ','."); + } expr.remove_prefix(1); skipSpaces(); const size_t jNsIdx1 = static_cast(parsedIndexName1.joinedSelectorIt - joinedSelectors.cbegin()); const auto parsedIndexName2 = parseIndexName(expr, joinedSelectors, fullExpr); if (parsedIndexName2.joinedSelectorIt != joinedSelectors.cend()) { if (parsedIndexName1.joinedSelectorIt == parsedIndexName2.joinedSelectorIt) { - if (toLower(parsedIndexName1.name) == toLower(parsedIndexName2.name)) + if (toLower(parsedIndexName1.name) == toLower(parsedIndexName2.name)) { throwParseError(fullExpr, expr.data(), "Distance between two same indexes"); + } Append({op, negative}, DistanceBetweenJoinedIndexesSameNs{jNsIdx1, parsedIndexName1.name, parsedIndexName2.name}); } else { Append({op, negative}, @@ -330,12 +361,16 @@ void SortExpression::parseDistance(std::string_view& expr, const std::vector& } else if (!expr.empty() && expr[0] == '(') { const auto point = parsePoint(expr, toLower(parsedIndexName1.name), fullExpr, skipSpaces); skipSpaces(); - if (expr.empty() || expr[0] != ',') throwParseError(fullExpr, expr.data(), "Expected ','."); + if (expr.empty() || expr[0] != ',') { + throwParseError(fullExpr, expr.data(), "Expected ','."); + } expr.remove_prefix(1); skipSpaces(); const auto parsedIndexName2 = parseIndexName(expr, joinedSelectors, fullExpr); skipSpaces(); - if (!expr.empty() && expr[0] == '(') throwParseError(fullExpr, expr.data(), "Allowed only one function inside ST_Geometry"); + if (!expr.empty() && expr[0] == '(') { + throwParseError(fullExpr, expr.data(), "Allowed only one function inside ST_Geometry"); + } if (parsedIndexName2.joinedSelectorIt != joinedSelectors.cend()) { Append({op, negative}, DistanceJoinedIndexFromPoint{static_cast(parsedIndexName2.joinedSelectorIt - joinedSelectors.cbegin()), @@ -344,7 +379,9 @@ void SortExpression::parseDistance(std::string_view& expr, const std::vector& Append({op, negative}, DistanceFromPoint{parsedIndexName2.name, point}); } } else { - if (expr.empty() || expr[0] != ',') throwParseError(fullExpr, expr.data(), "Expected ','."); + if (expr.empty() || expr[0] != ',') { + throwParseError(fullExpr, expr.data(), "Expected ','."); + } expr.remove_prefix(1); skipSpaces(); const auto parsedIndexName2 = parseIndexName(expr, joinedSelectors, fullExpr); @@ -359,8 +396,9 @@ void SortExpression::parseDistance(std::string_view& expr, const std::vector& const auto point = parsePoint(expr, toLower(parsedIndexName2.name), fullExpr, skipSpaces); Append({op, negative}, DistanceFromPoint{parsedIndexName1.name, point}); } else { - if (toLower(parsedIndexName1.name) == toLower(parsedIndexName2.name)) + if (toLower(parsedIndexName1.name) == toLower(parsedIndexName2.name)) { throwParseError(fullExpr, expr.data(), "Distance between two same indexes"); + } Append({op, negative}, DistanceBetweenIndexes{parsedIndexName1.name, parsedIndexName2.name}); } } @@ -369,7 +407,7 @@ void SortExpression::parseDistance(std::string_view& expr, const std::vector& } template -std::string_view SortExpression::parse(std::string_view expr, bool* containIndexOrFunction, std::string_view const fullExpr, +std::string_view SortExpression::parse(std::string_view expr, bool* containIndexOrFunction, const std::string_view fullExpr, const std::vector& joinedSelectors) { using namespace double_conversion; static const StringToDoubleConverter converter{StringToDoubleConverter::ALLOW_TRAILING_JUNK | @@ -381,7 +419,9 @@ std::string_view SortExpression::parse(std::string_view expr, bool* containIndex bool lastOperationPlusOrMinus = false; ArithmeticOpType op = OpPlus; const auto skipSpaces = [&expr]() { - while (!expr.empty() && isspace(expr[0])) expr.remove_prefix(1); + while (!expr.empty() && isspace(expr[0])) { + expr.remove_prefix(1); + } }; skipSpaces(); while (!expr.empty()) { @@ -397,13 +437,17 @@ std::string_view SortExpression::parse(std::string_view expr, bool* containIndex } expr.remove_prefix(1); skipSpaces(); - if (expr.empty()) throwParseError(fullExpr, expr.data(), "The expression unexpected ends after unary operator."); + if (expr.empty()) { + throwParseError(fullExpr, expr.data(), "The expression unexpected ends after unary operator."); + } } if (expr[0] == '(') { expr.remove_prefix(1); OpenBracket({op, negative}); expr = parse(expr, containIndexOrFunction, fullExpr, joinedSelectors); - if (expr.empty() || expr[0] != ')') throwParseError(fullExpr, expr.data(), "Expected ')'."); + if (expr.empty() || expr[0] != ')') { + throwParseError(fullExpr, expr.data(), "Expected ')'."); + } expr.remove_prefix(1); CloseBracket(); } else if (expr[0] == '"') { @@ -441,7 +485,9 @@ std::string_view SortExpression::parse(std::string_view expr, bool* containIndex } else { throwParseError(fullExpr, expr.data(), "Unsupported function name : '" + funcName + "'."); } - if (expr.empty() || expr[0] != ')') throwParseError(fullExpr, expr.data(), "Expected ')'."); + if (expr.empty() || expr[0] != ')') { + throwParseError(fullExpr, expr.data(), "Expected ')'."); + } expr.remove_prefix(1); } else { Append({op, negative}, SortExprFuncs::Index{parsedIndexName.name}); @@ -457,7 +503,9 @@ std::string_view SortExpression::parse(std::string_view expr, bool* containIndex } else { switch (expr[0]) { case ')': - if (needCloseBracket) CloseBracket(); + if (needCloseBracket) { + CloseBracket(); + } return expr; case '+': case '-': @@ -486,8 +534,12 @@ std::string_view SortExpression::parse(std::string_view expr, bool* containIndex } skipSpaces(); } - if (expectValue) throwParseError(fullExpr, expr.data(), "Expected value."); - if (needCloseBracket) CloseBracket(); + if (expectValue) { + throwParseError(fullExpr, expr.data(), "Expected value."); + } + if (needCloseBracket) { + CloseBracket(); + } return expr; } @@ -496,8 +548,12 @@ SortExpression SortExpression::Parse(const std::string_view expression, const st SortExpression result; bool containIndexOrFunction = false; const auto expr = result.parse(expression, &containIndexOrFunction, expression, joinedSelector); - if (!expr.empty()) throwParseError(expression, expr.data(), ""); - if (!containIndexOrFunction) throwParseError(expression, expr.data(), "Sort expression does not depend from namespace data"); + if (!expr.empty()) { + throwParseError(expression, expr.data(), ""); + } + if (!containIndexOrFunction) { + throwParseError(expression, expr.data(), "Sort expression does not depend from namespace data"); + } return result; } @@ -546,7 +602,9 @@ double SortExpression::calculate(const_iterator it, const_iterator end, IdType r assertrx_throw(joinedResults); return i.GetValue(rowId, *joinedResults, js); }); - if (it->operation.negative) value = -value; + if (it->operation.negative) { + value = -value; + } switch (it->operation.op) { case OpPlus: result += value; @@ -558,7 +616,9 @@ double SortExpression::calculate(const_iterator it, const_iterator end, IdType r result *= value; break; case OpDiv: - if (value == 0.0) throw Error(errQueryExec, "Division by zero in sort expression"); + if (value == 0.0) { + throw Error(errQueryExec, "Division by zero in sort expression"); + } result /= value; break; } @@ -593,7 +653,9 @@ void SortExpression::dump(const_iterator begin, const_iterator end, WrSerializer } ser << ' '; } - if (it->operation.negative) ser << "(-"; + if (it->operation.negative) { + ser << "(-"; + } it->Visit( [&it, &ser](const SortExpressionBracket& b) { ser << (b.IsAbs() ? "ABS(" : "("); @@ -618,7 +680,9 @@ void SortExpression::dump(const_iterator begin, const_iterator end, WrSerializer [&ser](const DistanceBetweenJoinedIndexesSameNs& i) { ser << "ST_Distance(joined " << i.nsIdx << ' ' << i.column1 << ", joined " << i.nsIdx << ' ' << i.column2 << ')'; }); - if (it->operation.negative) ser << ')'; + if (it->operation.negative) { + ser << ')'; + } } } diff --git a/cpp_src/core/nsselecter/sortingcontext.h b/cpp_src/core/nsselecter/sortingcontext.h index 8c8c4272c..0f87dbd1b 100644 --- a/cpp_src/core/nsselecter/sortingcontext.h +++ b/cpp_src/core/nsselecter/sortingcontext.h @@ -13,62 +13,76 @@ struct SortingEntry; struct SortingContext { struct RawDataParams { RawDataParams() = default; - RawDataParams(const void *p, const PayloadType &pt, int field) noexcept + RawDataParams(const void* p, const PayloadType& pt, int field) noexcept : ptr(p), type(ptr ? pt.Field(field).Type() : KeyValueType::Undefined{}) {} - const void *ptr = nullptr; + const void* ptr = nullptr; KeyValueType type = KeyValueType::Undefined{}; }; struct FieldEntry { - const SortingEntry &data; - Index *index = nullptr; + const SortingEntry& data; + Index* index = nullptr; RawDataParams rawData = {}; - const CollateOpts *opts = nullptr; + const CollateOpts* opts = nullptr; }; struct JoinedFieldEntry { - const SortingEntry &data; + const SortingEntry& data; size_t nsIdx; std::string_view field; int index = IndexValueType::NotSet; }; struct ExpressionEntry { - const SortingEntry &data; + const SortingEntry& data; size_t expression; }; using Entry = std::variant; [[nodiscard]] int sortId() const noexcept { - if (!enableSortOrders) return 0; - const Index *sortIdx = sortIndex(); + if (!enableSortOrders) { + return 0; + } + const Index* sortIdx = sortIndex(); return sortIdx ? int(sortIdx->SortId()) : 0; } - [[nodiscard]] Index *sortIndex() const noexcept { - if (entries.empty()) return nullptr; + [[nodiscard]] Index* sortIndex() const noexcept { + if (entries.empty()) { + return nullptr; + } // get_if is truly noexcept, so using it instead of std::visit - if (const auto *fe = std::get_if(&entries[0]); fe) { + if (const auto* fe = std::get_if(&entries[0]); fe) { return fe->index; } return nullptr; } - [[nodiscard]] const Index *sortIndexIfOrdered() const noexcept { - if (entries.empty() || !isIndexOrdered() || !enableSortOrders) return nullptr; + [[nodiscard]] const Index* sortIndexIfOrdered() const noexcept { + if (entries.empty() || !isIndexOrdered() || !enableSortOrders) { + return nullptr; + } // get_if is truly noexcept, so using it instead of std::visit - if (const auto *fe = std::get_if(&entries[0]); fe) { + if (const auto* fe = std::get_if(&entries[0]); fe) { return fe->index; } return nullptr; } + [[nodiscard]] const FieldEntry* sortFieldEntryIfOrdered() const noexcept { + if (entries.empty() || !isIndexOrdered() || !enableSortOrders) { + return nullptr; + } + return std::get_if(&entries[0]); + } [[nodiscard]] bool isOptimizationEnabled() const noexcept { return (uncommitedIndex >= 0) && sortIndex(); } [[nodiscard]] bool isIndexOrdered() const noexcept { - if (entries.empty()) return false; + if (entries.empty()) { + return false; + } // get_if is truly noexcept, so using it instead of std::visit - if (const auto *fe = std::get_if(&entries[0]); fe) { + if (const auto* fe = std::get_if(&entries[0]); fe) { return fe->index && fe->index->IsOrdered(); } return false; } - [[nodiscard]] const Entry &getFirstColumnEntry() const noexcept { + [[nodiscard]] const Entry& getFirstColumnEntry() const noexcept { assertrx_throw(!entries.empty()); return entries[0]; } @@ -76,7 +90,7 @@ struct SortingContext { uncommitedIndex = -1; if (!entries.empty()) { // get_if is truly noexcept, so using it instead of std::visit - if (auto *fe = std::get_if(&entries[0]); fe) { + if (auto* fe = std::get_if(&entries[0]); fe) { fe->index = nullptr; } } @@ -91,7 +105,7 @@ struct SortingContext { }; struct SortingOptions { - SortingOptions(const SortingContext &sortingContext) noexcept + SortingOptions(const SortingContext& sortingContext) noexcept : forcedMode{sortingContext.forcedMode}, multiColumn{sortingContext.entries.size() > 1}, haveExpression{!sortingContext.expressions.empty()} { @@ -100,7 +114,7 @@ struct SortingOptions { byBtreeIndex = false; } else { // get_if is truly noexcept, so using it instead of std::visit - if (auto *sortEntry = std::get_if(&sortingContext.entries[0]); sortEntry) { + if (auto* sortEntry = std::get_if(&sortingContext.entries[0]); sortEntry) { if (sortEntry->index && sortEntry->index->IsOrdered()) { byBtreeIndex = (sortingContext.isOptimizationEnabled() || sortingContext.enableSortOrders); multiColumnByBtreeIndex = (byBtreeIndex && multiColumn); diff --git a/cpp_src/core/nsselecter/substitutionhelpers.h b/cpp_src/core/nsselecter/substitutionhelpers.h index 8ebc54929..3c89f197b 100644 --- a/cpp_src/core/nsselecter/substitutionhelpers.h +++ b/cpp_src/core/nsselecter/substitutionhelpers.h @@ -32,9 +32,9 @@ class CompositeSearcher { h_vector entries; }; - CompositeSearcher(const NamespaceImpl &ns) noexcept : ns_(ns) {} + CompositeSearcher(const NamespaceImpl& ns) noexcept : ns_(ns) {} - void Add(int field, const std::vector &composites, unsigned entry) { + void Add(int field, const std::vector& composites, unsigned entry) { assertrx_throw(entry < std::numeric_limits::max()); for (auto composite : composites) { const auto idxType = ns_.indexes_[composite]->Type(); @@ -42,7 +42,7 @@ class CompositeSearcher { continue; } bool found = false; - for (auto &d : d_) { + for (auto& d : d_) { if (d.idx == composite) { d.fields.push_back(field); d.entries.push_back(entry); @@ -59,8 +59,8 @@ class CompositeSearcher { int res = -1; unsigned maxSize = 0; for (int i = 0; i < int(d_.size()); ++i) { - auto &data = d_[i]; - const auto &idxFields = ns_.indexes_[data.idx]->Fields(); + auto& data = d_[i]; + const auto& idxFields = ns_.indexes_[data.idx]->Fields(); // If all of the composite fields were found in query const auto dfCnt = data.fields.count(); if (dfCnt == idxFields.size() && idxFields.contains(data.fields)) { @@ -88,9 +88,9 @@ class CompositeSearcher { if (unsigned(curId) + 1 != d_.size()) { std::swap(d_[curId], d_.back()); } - const auto &cur = d_.back(); + const auto& cur = d_.back(); for (unsigned i = 0, sz = d_.size(); i < sz - deleted; ++i) { - auto &data = d_[i]; + auto& data = d_[i]; if (haveIntersection(data.entries, cur.entries)) { std::swap(data, d_[sz - ++deleted]); --i; @@ -107,7 +107,7 @@ class CompositeSearcher { } return res; } - const IndexData &operator[](uint16_t i) const noexcept { return d_[i]; } + const IndexData& operator[](uint16_t i) const noexcept { return d_[i]; } private: void remove(uint16_t i) noexcept { @@ -116,7 +116,7 @@ class CompositeSearcher { } d_.pop_back(); } - static bool haveIntersection(const h_vector &lEntries, const h_vector &rEntries) noexcept { + static bool haveIntersection(const h_vector& lEntries, const h_vector& rEntries) noexcept { for (auto lit = lEntries.begin(), rit = rEntries.begin(); lit != lEntries.end() && rit != rEntries.end();) { if (*lit < *rit) { ++lit; @@ -130,7 +130,7 @@ class CompositeSearcher { } h_vector d_; - const NamespaceImpl &ns_; + const NamespaceImpl& ns_; }; // EntriesRange - query entries range. [from; to) @@ -150,7 +150,7 @@ class EntriesRange { } --from_; } - bool Append(const EntriesRange &r) noexcept { + bool Append(const EntriesRange& r) noexcept { if (to_ == r.from_) { to_ = r.to_; return true; diff --git a/cpp_src/core/payload/fieldsset.cc b/cpp_src/core/payload/fieldsset.cc index 80a6b85c6..6f929ab16 100644 --- a/cpp_src/core/payload/fieldsset.cc +++ b/cpp_src/core/payload/fieldsset.cc @@ -7,8 +7,8 @@ namespace reindexer { throw Error(errLogic, "Can not push_back(%d) to IndexesFieldsSet. Value must be in scope [-1,%d]", f, kMaxIndexes - 1); } -FieldsSet::FieldsSet(const TagsMatcher &tagsMatcher, const h_vector &fields) : mask_(0) { - for (const std::string &str : fields) { +FieldsSet::FieldsSet(const TagsMatcher& tagsMatcher, const h_vector& fields) : mask_(0) { + for (const std::string& str : fields) { tagsPaths_.emplace_back(tagsMatcher.path2tag(str)); } } diff --git a/cpp_src/core/payload/fieldsset.h b/cpp_src/core/payload/fieldsset.h index 98c0062ae..849738f5b 100644 --- a/cpp_src/core/payload/fieldsset.h +++ b/cpp_src/core/payload/fieldsset.h @@ -28,14 +28,16 @@ class IndexesFieldsSet { IndexesFieldsSet(int f) { push_back(f); } bool contains(int f) const noexcept { return f >= 0 && f < kMaxIndexes && mask_.test(unsigned(f)); } void push_back(int f) { - if (f < 0) return; + if (f < 0) { + return; + } if (f >= kMaxIndexes) { throwMaxValueError(f); } mask_.set(unsigned(f)); } - const std::bitset &mask() const &noexcept { return mask_; } - const std::bitset &mask() const && = delete; + const std::bitset& mask() const& noexcept { return mask_; } + const std::bitset& mask() const&& = delete; unsigned count() const noexcept { return mask_.count(); } private: @@ -51,46 +53,54 @@ class FieldsSet : protected base_fields_set { using base_fields_set::size; using base_fields_set::empty; using base_fields_set::operator[]; - FieldsSet(const TagsMatcher &, const h_vector &fields); + FieldsSet(const TagsMatcher&, const h_vector& fields); FieldsSet(int f) { push_back(f); } FieldsSet(std::initializer_list l) { - for (auto f : l) push_back(f); + for (auto f : l) { + push_back(f); + } } FieldsSet(std::initializer_list l) { - for (const TagsPath &tagsPath : l) push_back(tagsPath); + for (const TagsPath& tagsPath : l) { + push_back(tagsPath); + } } FieldsSet(std::initializer_list l) { - for (const IndexedTagsPath &tagsPath : l) push_back(tagsPath); + for (const IndexedTagsPath& tagsPath : l) { + push_back(tagsPath); + } } FieldsSet() = default; - void push_back(const std::string &jsonPath) { + void push_back(const std::string& jsonPath) { if (!contains(jsonPath)) { jsonPaths_.push_back(jsonPath); } } - void push_back(std::string &&jsonPath) { + void push_back(std::string&& jsonPath) { if (!contains(jsonPath)) { jsonPaths_.emplace_back(std::move(jsonPath)); } } - void push_back(const TagsPath &tagsPath) { pushBack(tagsPath); } - void push_back(TagsPath &&tagsPath) { pushBack(std::move(tagsPath)); } - void push_front(TagsPath &&tagsPath) { + void push_back(const TagsPath& tagsPath) { pushBack(tagsPath); } + void push_back(TagsPath&& tagsPath) { pushBack(std::move(tagsPath)); } + void push_front(TagsPath&& tagsPath) { if (!contains(tagsPath)) { base_fields_set::insert(begin(), IndexValueType::SetByJsonPath); tagsPaths_.insert(tagsPaths_.begin(), std::move(tagsPath)); } } - void push_back(const IndexedTagsPath &tagsPath) { pushBack(tagsPath); } - void push_back(IndexedTagsPath &&tagsPath) { pushBack(std::move(tagsPath)); } - void push_back(const FieldsPath &fieldPath) { pushBack(fieldPath); } - void push_back(FieldsPath &&fieldPath) { pushBack(std::move(fieldPath)); } + void push_back(const IndexedTagsPath& tagsPath) { pushBack(tagsPath); } + void push_back(IndexedTagsPath&& tagsPath) { pushBack(std::move(tagsPath)); } + void push_back(const FieldsPath& fieldPath) { pushBack(fieldPath); } + void push_back(FieldsPath&& fieldPath) { pushBack(std::move(fieldPath)); } void push_back(int f) { - if (f < 0) return; + if (f < 0) { + return; + } if (f >= kMaxIndexes) { throwMaxValueError(f); } @@ -100,7 +110,9 @@ class FieldsSet : protected base_fields_set { } } void push_front(int f) { - if (f < 0) return; + if (f < 0) { + return; + } if (f >= kMaxIndexes) { throwMaxValueError(f); } @@ -116,44 +128,48 @@ class FieldsSet : protected base_fields_set { auto it = std::find(begin(), end(), f); assertrx(it != end()); base_fields_set::erase(it); - if (!byJsonPath) mask_.reset(unsigned(f)); + if (!byJsonPath) { + mask_.reset(unsigned(f)); + } } } bool contains(int f) const noexcept { return f >= 0 && f < kMaxIndexes && mask_.test(unsigned(f)); } - bool contains(const FieldsSet &f) const noexcept { return (mask_ & f.mask_) == f.mask_; } + bool contains(const FieldsSet& f) const noexcept { return (mask_ & f.mask_) == f.mask_; } bool contains(std::string_view jsonPath) const noexcept { return std::find(jsonPaths_.begin(), jsonPaths_.end(), jsonPath) != jsonPaths_.end(); } - bool contains(const IndexesFieldsSet &f) const noexcept { return (mask_ & f.mask()) == f.mask(); } - bool contains(const TagsPath &tagsPath) const noexcept { - for (const FieldsPath &path : tagsPaths_) { - if (std::visit(overloaded{[&tagsPath](const TagsPath &path) { return path == tagsPath; }, - [&tagsPath](const IndexedTagsPath &path) { return path.Compare(tagsPath); }}, + bool contains(const IndexesFieldsSet& f) const noexcept { return (mask_ & f.mask()) == f.mask(); } + bool contains(const TagsPath& tagsPath) const noexcept { + for (const FieldsPath& path : tagsPaths_) { + if (std::visit(overloaded{[&tagsPath](const TagsPath& path) { return path == tagsPath; }, + [&tagsPath](const IndexedTagsPath& path) { return path.Compare(tagsPath); }}, path)) { return true; } } return false; } - bool contains(const IndexedTagsPath &tagsPath) const noexcept { - for (const FieldsPath &path : tagsPaths_) { - if (std::visit(overloaded{[&tagsPath](const TagsPath &path) { return tagsPath.Compare(path); }, - [&tagsPath](const IndexedTagsPath &path) { return path == tagsPath; }}, + bool contains(const IndexedTagsPath& tagsPath) const noexcept { + for (const FieldsPath& path : tagsPaths_) { + if (std::visit(overloaded{[&tagsPath](const TagsPath& path) { return tagsPath.Compare(path); }, + [&tagsPath](const IndexedTagsPath& path) { return path == tagsPath; }}, path)) { return true; } } return false; } - bool contains(const FieldsPath &fieldsPath) const noexcept { - return std::visit([&](const auto &fp) { return contains(fp); }, fieldsPath); + bool contains(const FieldsPath& fieldsPath) const noexcept { + return std::visit([&](const auto& fp) { return contains(fp); }, fieldsPath); } - bool match(const TagsPath &tagsPath) const noexcept { - if (tagsPaths_.empty()) return true; - for (auto &path : tagsPaths_) { - if (std::visit(overloaded{[&tagsPath, this](const TagsPath &path) { return comparePaths(tagsPath, path); }, - [&tagsPath, this](const IndexedTagsPath &path) { return comparePaths(path, tagsPath); }}, + bool match(const TagsPath& tagsPath) const noexcept { + if (tagsPaths_.empty()) { + return true; + } + for (auto& path : tagsPaths_) { + if (std::visit(overloaded{[&tagsPath, this](const TagsPath& path) { return comparePaths(tagsPath, path); }, + [&tagsPath, this](const IndexedTagsPath& path) { return comparePaths(path, tagsPath); }}, path)) { return true; } @@ -161,11 +177,13 @@ class FieldsSet : protected base_fields_set { return false; } template - bool match(const IndexedTagsPathImpl &tagsPath) const noexcept { - if (tagsPaths_.empty()) return true; - for (auto &path : tagsPaths_) { - if (std::visit(overloaded{[&tagsPath, this](const TagsPath &path) { return comparePaths(tagsPath, path); }, - [&tagsPath, this](const IndexedTagsPath &path) { return comparePaths(tagsPath, path); }}, + bool match(const IndexedTagsPathImpl& tagsPath) const noexcept { + if (tagsPaths_.empty()) { + return true; + } + for (auto& path : tagsPaths_) { + if (std::visit(overloaded{[&tagsPath, this](const TagsPath& path) { return comparePaths(tagsPath, path); }, + [&tagsPath, this](const IndexedTagsPath& path) { return comparePaths(tagsPath, path); }}, path)) { return true; } @@ -181,43 +199,48 @@ class FieldsSet : protected base_fields_set { size_t getTagsPathsLength() const noexcept { return tagsPaths_.size(); } size_t getJsonPathsLength() const noexcept { return jsonPaths_.size(); } - const h_vector &getJsonPaths() const noexcept { return jsonPaths_; } + const h_vector& getJsonPaths() const noexcept { return jsonPaths_; } bool isTagsPathIndexed(size_t idx) const noexcept { assertrx(idx < tagsPaths_.size()); - return std::visit(overloaded{[](const TagsPath &) { return false; }, [](const IndexedTagsPath &) { return true; }}, - tagsPaths_[idx]); + return std::visit(overloaded{[](const TagsPath&) { return false; }, [](const IndexedTagsPath&) { return true; }}, tagsPaths_[idx]); } - const TagsPath &getTagsPath(size_t idx) const & { return std::get(tagsPaths_[idx]); } - const TagsPath &getTagsPath(size_t idx) const && = delete; - const IndexedTagsPath &getIndexedTagsPath(size_t idx) const & { return std::get(tagsPaths_[idx]); } - const IndexedTagsPath &getIndexedTagsPath(size_t idx) const && = delete; - const FieldsPath &getFieldsPath(size_t idx) const & { return tagsPaths_[idx]; } - const FieldsPath &getFieldsPath(size_t idx) const && = delete; - const std::string &getJsonPath(size_t idx) const &noexcept { return jsonPaths_[idx]; } - const std::string &getJsonPath(size_t idx) const && = delete; + const TagsPath& getTagsPath(size_t idx) const& { return std::get(tagsPaths_[idx]); } + const TagsPath& getTagsPath(size_t idx) const&& = delete; + const IndexedTagsPath& getIndexedTagsPath(size_t idx) const& { return std::get(tagsPaths_[idx]); } + const IndexedTagsPath& getIndexedTagsPath(size_t idx) const&& = delete; + const FieldsPath& getFieldsPath(size_t idx) const& { return tagsPaths_[idx]; } + const FieldsPath& getFieldsPath(size_t idx) const&& = delete; + const std::string& getJsonPath(size_t idx) const& noexcept { return jsonPaths_[idx]; } + const std::string& getJsonPath(size_t idx) const&& = delete; - bool operator==(const FieldsSet &f) const noexcept { + bool operator==(const FieldsSet& f) const noexcept { return (mask_ == f.mask_) && (tagsPaths_ == f.tagsPaths_) && (jsonPaths_ == jsonPaths_); } - bool operator!=(const FieldsSet &f) const noexcept { return !(*this == f); } + bool operator!=(const FieldsSet& f) const noexcept { return !(*this == f); } template - void Dump(T &os) const { - DumpFieldsPath const fieldsPathDumper{os}; + void Dump(T& os) const { + const DumpFieldsPath fieldsPathDumper{os}; os << "{["; for (auto b = begin(), it = b, e = end(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << *it; } os << "], mask: " << mask_ << ", tagsPaths: ["; for (auto b = tagsPaths_.cbegin(), it = b, e = tagsPaths_.cend(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } std::visit(fieldsPathDumper, *it); } os << "]}"; os << "], jsonPaths: ["; for (auto b = jsonPaths_.cbegin(), it = b, e = jsonPaths_.cend(); it != e; ++it) { - if (it != b) os << ", "; + if (it != b) { + os << ", "; + } os << *it; } os << "]}"; @@ -225,14 +248,14 @@ class FieldsSet : protected base_fields_set { private: template - void pushBack(F &&fieldPath) { + void pushBack(F&& fieldPath) { if (!contains(fieldPath)) { base_fields_set::push_back(IndexValueType::SetByJsonPath); tagsPaths_.emplace_back(std::forward(fieldPath)); } } template - bool comparePaths(const TPath1 &lhs, const TPath2 &rhs) const noexcept { + bool comparePaths(const TPath1& lhs, const TPath2& rhs) const noexcept { unsigned i = 0, count = std::min(lhs.size(), rhs.size()); for (; i < count && lhs[i] == rhs[i]; ++i) { } @@ -251,26 +274,30 @@ class FieldsSet : protected base_fields_set { template class DumpFieldsPath { public: - DumpFieldsPath(T &os) noexcept : os_{os} {} - void operator()(const TagsPath &tp) const { + DumpFieldsPath(T& os) noexcept : os_{os} {} + void operator()(const TagsPath& tp) const { os_ << '['; for (auto b = tp.cbegin(), it = b, e = tp.cend(); it != e; ++it) { - if (it != b) os_ << ", "; + if (it != b) { + os_ << ", "; + } os_ << *it; } os_ << ']'; } - void operator()(const IndexedTagsPath &tp) const { + void operator()(const IndexedTagsPath& tp) const { os_ << '['; for (auto b = tp.cbegin(), it = b, e = tp.cend(); it != e; ++it) { - if (it != b) os_ << ", "; + if (it != b) { + os_ << ", "; + } os_ << '?'; } os_ << ']'; } private: - T &os_; + T& os_; }; }; diff --git a/cpp_src/core/payload/payloadfieldtype.cc b/cpp_src/core/payload/payloadfieldtype.cc index 25622abe8..36d83f02f 100644 --- a/cpp_src/core/payload/payloadfieldtype.cc +++ b/cpp_src/core/payload/payloadfieldtype.cc @@ -7,7 +7,9 @@ namespace reindexer { size_t PayloadFieldType::Sizeof() const noexcept { - if (IsArray()) return sizeof(PayloadFieldValue::Array); + if (IsArray()) { + return sizeof(PayloadFieldValue::Array); + } return ElemSizeof(); } @@ -24,7 +26,9 @@ size_t PayloadFieldType::ElemSizeof() const noexcept { } size_t PayloadFieldType::Alignof() const noexcept { - if (IsArray()) return alignof(PayloadFieldValue::Array); + if (IsArray()) { + return alignof(PayloadFieldValue::Array); + } return Type().EvaluateOneOf( [](KeyValueType::Bool) noexcept { return alignof(bool); }, [](KeyValueType::Int) noexcept { return alignof(int); }, [](KeyValueType::Int64) noexcept { return alignof(int64_t); }, [](KeyValueType::Uuid) noexcept { return alignof(Uuid); }, diff --git a/cpp_src/core/payload/payloadfieldtype.h b/cpp_src/core/payload/payloadfieldtype.h index ba762c934..b4cb5588c 100644 --- a/cpp_src/core/payload/payloadfieldtype.h +++ b/cpp_src/core/payload/payloadfieldtype.h @@ -19,11 +19,11 @@ class PayloadFieldType { void SetOffset(size_t o) noexcept { offset_ = o; } size_t Offset() const noexcept { return offset_; } KeyValueType Type() const noexcept { return type_; } - const std::string &Name() const &noexcept { return name_; } - const std::string &Name() && = delete; - const std::vector &JsonPaths() const &noexcept { return jsonPaths_; } - const std::vector &JsonPaths() && = delete; - void AddJsonPath(const std::string &jsonPath) { jsonPaths_.push_back(jsonPath); } + const std::string& Name() const& noexcept { return name_; } + const std::string& Name() && = delete; + const std::vector& JsonPaths() const& noexcept { return jsonPaths_; } + const std::vector& JsonPaths() && = delete; + void AddJsonPath(const std::string& jsonPath) { jsonPaths_.push_back(jsonPath); } private: KeyValueType type_; diff --git a/cpp_src/core/payload/payloadfieldvalue.h b/cpp_src/core/payload/payloadfieldvalue.h index 21c549aac..af9fe371e 100644 --- a/cpp_src/core/payload/payloadfieldvalue.h +++ b/cpp_src/core/payload/payloadfieldvalue.h @@ -17,17 +17,23 @@ class PayloadFieldValue { int len; }; // Construct object - PayloadFieldValue(const PayloadFieldType &t, uint8_t *v) noexcept : t_(t), p_(v) {} + PayloadFieldValue(const PayloadFieldType& t, uint8_t* v) noexcept : t_(t), p_(v) {} // Single value operations void Set(Variant kv) { t_.Type().EvaluateOneOf(overloaded{[&kv](KeyValueType::Int64) { - if (kv.Type().Is()) kv.convert(KeyValueType::Int64{}); + if (kv.Type().Is()) { + kv.convert(KeyValueType::Int64{}); + } }, [&kv](KeyValueType::Int) { - if (kv.Type().Is()) kv.convert(KeyValueType::Int{}); + if (kv.Type().Is()) { + kv.convert(KeyValueType::Int{}); + } }, [&kv](KeyValueType::Uuid) { - if (kv.Type().Is()) kv.convert(KeyValueType::Uuid{}); + if (kv.Type().Is()) { + kv.convert(KeyValueType::Uuid{}); + } }, [](OneOf) noexcept {}}); @@ -36,12 +42,12 @@ class PayloadFieldValue { } t_.Type().EvaluateOneOf( - [&](KeyValueType::Int) noexcept { *reinterpret_cast(p_) = int(kv); }, - [&](KeyValueType::Bool) noexcept { *reinterpret_cast(p_) = bool(kv); }, - [&](KeyValueType::Int64) noexcept { *reinterpret_cast(p_) = int64_t(kv); }, - [&](KeyValueType::Double) noexcept { *reinterpret_cast(p_) = double(kv); }, - [&](KeyValueType::String) noexcept { *reinterpret_cast(p_) = p_string(kv); }, - [&](KeyValueType::Uuid) noexcept { *reinterpret_cast(p_) = Uuid{kv}; }, + [&](KeyValueType::Int) noexcept { *reinterpret_cast(p_) = int(kv); }, + [&](KeyValueType::Bool) noexcept { *reinterpret_cast(p_) = bool(kv); }, + [&](KeyValueType::Int64) noexcept { *reinterpret_cast(p_) = int64_t(kv); }, + [&](KeyValueType::Double) noexcept { *reinterpret_cast(p_) = double(kv); }, + [&](KeyValueType::String) noexcept { *reinterpret_cast(p_) = p_string(kv); }, + [&](KeyValueType::Uuid) noexcept { *reinterpret_cast(p_) = Uuid{kv}; }, [](OneOf) noexcept { assertrx(0); abort(); @@ -51,14 +57,14 @@ class PayloadFieldValue { template Variant Get(HoldT h) const noexcept(noexcept(Variant(std::declval(), h))) { return t_.Type().EvaluateOneOf( - [&](KeyValueType::Bool) noexcept { return Variant(*reinterpret_cast(p_)); }, - [&](KeyValueType::Int) noexcept { return Variant(*reinterpret_cast(p_)); }, - [&](KeyValueType::Int64) noexcept { return Variant(*reinterpret_cast(p_)); }, - [&](KeyValueType::Double) noexcept { return Variant(*reinterpret_cast(p_)); }, + [&](KeyValueType::Bool) noexcept { return Variant(*reinterpret_cast(p_)); }, + [&](KeyValueType::Int) noexcept { return Variant(*reinterpret_cast(p_)); }, + [&](KeyValueType::Int64) noexcept { return Variant(*reinterpret_cast(p_)); }, + [&](KeyValueType::Double) noexcept { return Variant(*reinterpret_cast(p_)); }, [&](KeyValueType::String) noexcept(noexcept(Variant(std::declval(), h))) { - return Variant(*reinterpret_cast(p_), h); + return Variant(*reinterpret_cast(p_), h); }, - [&](KeyValueType::Uuid) noexcept { return Variant(*reinterpret_cast(p_)); }, + [&](KeyValueType::Uuid) noexcept { return Variant(*reinterpret_cast(p_)); }, [](OneOf) noexcept -> Variant { assertrx(0); abort(); @@ -79,31 +85,31 @@ class PayloadFieldValue { // } size_t Hash() const noexcept { return t_.Type().EvaluateOneOf( - [&](KeyValueType::Bool) noexcept { return std::hash()(*reinterpret_cast(p_)); }, - [&](KeyValueType::Int) noexcept { return std::hash()(*reinterpret_cast(p_)); }, - [&](KeyValueType::Int64) noexcept { return std::hash()(*reinterpret_cast(p_)); }, - [&](KeyValueType::Double) noexcept { return std::hash()(*reinterpret_cast(p_)); }, - [&](KeyValueType::String) noexcept { return std::hash()(*reinterpret_cast(p_)); }, - [&](KeyValueType::Uuid) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::Bool) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::Int) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::Int64) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::Double) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::String) noexcept { return std::hash()(*reinterpret_cast(p_)); }, + [&](KeyValueType::Uuid) noexcept { return std::hash()(*reinterpret_cast(p_)); }, [](OneOf) noexcept -> size_t { assertrx(0); abort(); }); } - bool IsEQ(const PayloadFieldValue &o) const { - if (!t_.Type().IsSame(o.t_.Type())) return false; + bool IsEQ(const PayloadFieldValue& o) const { + if (!t_.Type().IsSame(o.t_.Type())) { + return false; + } return t_.Type().EvaluateOneOf( - [&](KeyValueType::Bool) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, - [&](KeyValueType::Int) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, - [&](KeyValueType::Int64) noexcept { - return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); - }, - [&](KeyValueType::Double) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, + [&](KeyValueType::Bool) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, + [&](KeyValueType::Int) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, + [&](KeyValueType::Int64) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, + [&](KeyValueType::Double) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, [&](KeyValueType::String) { - return collateCompare(*reinterpret_cast(p_), *reinterpret_cast(o.p_), + return collateCompare(*reinterpret_cast(p_), *reinterpret_cast(o.p_), SortingPrioritiesTable()) == ComparationResult::Eq; }, - [&](KeyValueType::Uuid) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, + [&](KeyValueType::Uuid) noexcept { return *reinterpret_cast(p_) == *reinterpret_cast(o.p_); }, [](OneOf) noexcept -> bool { assertrx(0); abort(); @@ -111,12 +117,12 @@ class PayloadFieldValue { } // Type of value, not owning - const PayloadFieldType &t_; + const PayloadFieldType& t_; // Value data, not owning - uint8_t *p_; + uint8_t* p_; private: - [[noreturn]] void throwSetTypeMissmatch(const Variant &kv); + [[noreturn]] void throwSetTypeMissmatch(const Variant& kv); }; } // namespace reindexer diff --git a/cpp_src/core/payload/payloadiface.cc b/cpp_src/core/payload/payloadiface.cc index b2a5877a0..207a4d07d 100644 --- a/cpp_src/core/payload/payloadiface.cc +++ b/cpp_src/core/payload/payloadiface.cc @@ -12,11 +12,11 @@ namespace reindexer { // Get element(s) by field index template -void PayloadIface::Get(int field, VariantArray &keys, Variant::hold_t h) const { +void PayloadIface::Get(int field, VariantArray& keys, Variant::hold_t h) const { get(field, keys, h); } template -void PayloadIface::Get(int field, VariantArray &keys) const { +void PayloadIface::Get(int field, VariantArray& keys) const { get(field, keys, Variant::no_hold_t{}); } @@ -32,21 +32,21 @@ Variant PayloadIface::Get(int field, int idx) const { // Get element(s) by field name template -void PayloadIface::Get(std::string_view field, VariantArray &kvs, Variant::hold_t h) const { +void PayloadIface::Get(std::string_view field, VariantArray& kvs, Variant::hold_t h) const { get(t_.FieldByName(field), kvs, h); } template -void PayloadIface::Get(std::string_view field, VariantArray &kvs) const { +void PayloadIface::Get(std::string_view field, VariantArray& kvs) const { get(t_.FieldByName(field), kvs, Variant::no_hold_t{}); } template template -void PayloadIface::get(int field, VariantArray &keys, HoldT h) const { +void PayloadIface::get(int field, VariantArray& keys, HoldT h) const { assertrx(field < NumFields()); keys.clear(); if (t_.Field(field).IsArray()) { - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); keys.reserve(arr->len); for (int i = 0; i < arr->len; i++) { @@ -64,7 +64,7 @@ Variant PayloadIface::get(int field, int idx, HoldT h) const { assertrx(field < NumFields()); if (t_.Field(field).IsArray()) { - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); assertf(idx < arr->len, "Field '%s.%s' bound exceed idx %d > len %d", Type().Name(), Type().Field(field).Name(), idx, arr->len); PayloadFieldValue pv(t_.Field(field), v_->Ptr() + arr->offset + idx * t_.Field(field).ElemSizeof()); @@ -76,7 +76,7 @@ Variant PayloadIface::get(int field, int idx, HoldT h) const { } template -void PayloadIface::GetByJsonPath(std::string_view jsonPath, TagsMatcher &tagsMatcher, VariantArray &kvs, +void PayloadIface::GetByJsonPath(std::string_view jsonPath, TagsMatcher& tagsMatcher, VariantArray& kvs, KeyValueType expectedType) const { VariantArray krefs; Get(0, krefs); @@ -102,7 +102,7 @@ void PayloadIface::GetByJsonPath(std::string_view jsonPath, TagsMatcher &tags template template -void PayloadIface::getByJsonPath(const P &path, VariantArray &krefs, KeyValueType expectedType) const { +void PayloadIface::getByJsonPath(const P& path, VariantArray& krefs, KeyValueType expectedType) const { krefs.clear(); if (path.empty()) { return; @@ -115,18 +115,18 @@ void PayloadIface::getByJsonPath(const P &path, VariantArray &krefs, KeyValue } template -void PayloadIface::GetByJsonPath(const TagsPath &tagsPath, VariantArray &krefs, KeyValueType expectedType) const { +void PayloadIface::GetByJsonPath(const TagsPath& tagsPath, VariantArray& krefs, KeyValueType expectedType) const { getByJsonPath(tagsPath, krefs, expectedType); } template -void PayloadIface::GetByJsonPath(const IndexedTagsPath &tagsPath, VariantArray &krefs, KeyValueType expectedType) const { +void PayloadIface::GetByJsonPath(const IndexedTagsPath& tagsPath, VariantArray& krefs, KeyValueType expectedType) const { getByJsonPath(tagsPath, krefs, expectedType); } template -void PayloadIface::GetByFieldsSet(const FieldsSet &fields, VariantArray &kvs, KeyValueType expectedType, - const h_vector &expectedCompositeTypes) const { +void PayloadIface::GetByFieldsSet(const FieldsSet& fields, VariantArray& kvs, KeyValueType expectedType, + const h_vector& expectedCompositeTypes) const { if (expectedType.Is()) { kvs.Clear(); kvs.emplace_back(GetComposite(fields, expectedCompositeTypes)); @@ -146,7 +146,7 @@ void PayloadIface::GetByFieldsSet(const FieldsSet &fields, VariantArray &kvs, } template -Variant PayloadIface::GetComposite(const FieldsSet &fields, const h_vector &expectedTypes) const { +Variant PayloadIface::GetComposite(const FieldsSet& fields, const h_vector& expectedTypes) const { thread_local VariantArray buffer; buffer.clear(); assertrx_throw(fields.size() == expectedTypes.size()); @@ -173,7 +173,7 @@ Variant PayloadIface::GetComposite(const FieldsSet &fields, const h_vector -VariantArray PayloadIface::GetIndexedArrayData(const IndexedTagsPath &tagsPath, int field, int &offset, int &size) const { +VariantArray PayloadIface::GetIndexedArrayData(const IndexedTagsPath& tagsPath, int field, int& offset, int& size) const { if (tagsPath.empty()) { throw Error(errParams, "GetIndexedArrayData(): tagsPath shouldn't be empty!"); } @@ -194,8 +194,8 @@ VariantArray PayloadIface::GetIndexedArrayData(const IndexedTagsPath &tagsPat } template -template ::value>::type *> -void PayloadIface::SetSingleElement(int field, const Variant &key) { +template ::value>::type*> +void PayloadIface::SetSingleElement(int field, const Variant& key) { if (t_.Field(field).IsArray()) { throw Error(errLogic, "Unable to set array field via single field setter"); } @@ -204,11 +204,11 @@ void PayloadIface::SetSingleElement(int field, const Variant &key) { // Set element or array by field index and element index template -template ::value>::type *> -void PayloadIface::Set(int field, int idx, const Variant &v) { +template ::value>::type*> +void PayloadIface::Set(int field, int idx, const Variant& v) { assertrx(idx >= 0); assertrx(t_.Field(field).IsArray()); - auto const *const arr = reinterpret_cast(Field(field).p_); + const auto* const arr = reinterpret_cast(Field(field).p_); const auto elemSize = t_.Field(field).ElemSizeof(); assertrx(idx < arr->len); PayloadFieldValue pv(t_.Field(field), v_->Ptr() + arr->offset + idx * elemSize); @@ -220,7 +220,7 @@ int PayloadIface::ResizeArray(int field, int count, bool append) { assertrx(t_.Field(field).IsArray()); size_t realSize = RealSize(); - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); auto elemSize = t_.Field(field).ElemSizeof(); size_t grow = elemSize * count; @@ -236,16 +236,21 @@ int PayloadIface::ResizeArray(int field, int count, bool append) { v_->Resize(realSize, realSize + grow - strip); memmove(v_->Ptr() + insert + grow - strip, v_->Ptr() + insert, realSize - insert); - arr = reinterpret_cast(Field(field).p_); - if (!arr->offset) arr->offset = insert; + arr = reinterpret_cast(Field(field).p_); + if (!arr->offset) { + arr->offset = insert; + } arr->len += count; // Move another arrays, after our - for (int f = 0; f < NumFields(); f++) + for (int f = 0; f < NumFields(); f++) { if (f != field && t_.Field(f).IsArray()) { - auto *arr = reinterpret_cast(Field(f).p_); - if (arr->offset >= insert) arr->offset += grow - strip; + auto* arr = reinterpret_cast(Field(f).p_); + if (arr->offset >= insert) { + arr->offset += grow - strip; + } } + } return arr->len - count; } @@ -253,28 +258,31 @@ int PayloadIface::ResizeArray(int field, int count, bool append) { template size_t PayloadIface::RealSize() const { size_t sz = t_.TotalSize(); - for (int field = 0; field < NumFields(); field++) + for (int field = 0; field < NumFields(); field++) { if (t_.Field(field).IsArray()) { - auto *arr = reinterpret_cast(Field(field).p_); - if (arr->offset >= sz) sz = arr->offset + arr->len * t_.Field(field).ElemSizeof(); + auto* arr = reinterpret_cast(Field(field).p_); + if (arr->offset >= sz) { + sz = arr->offset + arr->len * t_.Field(field).ElemSizeof(); + } } + } return sz; } // Serialize field values template -void PayloadIface::SerializeFields(WrSerializer &ser, const FieldsSet &fields) const { +void PayloadIface::SerializeFields(WrSerializer& ser, const FieldsSet& fields) const { size_t tagPathIdx = 0; VariantArray varr; for (int field : fields) { if (field == IndexValueType::SetByJsonPath) { assertrx(tagPathIdx < fields.getTagsPathsLength()); if (fields.isTagsPathIndexed(tagPathIdx)) { - const IndexedTagsPath &tagsPath = fields.getIndexedTagsPath(tagPathIdx); + const IndexedTagsPath& tagsPath = fields.getIndexedTagsPath(tagPathIdx); GetByJsonPath(tagsPath, varr, KeyValueType::Undefined{}); } else { - const TagsPath &tagsPath = fields.getTagsPath(tagPathIdx); + const TagsPath& tagsPath = fields.getTagsPath(tagPathIdx); GetByJsonPath(tagsPath, varr, KeyValueType::Undefined{}); } if (varr.empty()) { @@ -302,35 +310,43 @@ std::string PayloadIface::Dump() const { printString += Type().Field(i).Name(); printString += ": "; - if (Type().Field(i).IsArray()) printString += "["; + if (Type().Field(i).IsArray()) { + printString += "["; + } for (size_t j = 0; j < fieldValues.size(); ++j) { - auto &fieldValue = fieldValues[j]; + auto& fieldValue = fieldValues[j]; auto str = fieldValue.As(); - if (i != 0) + if (i != 0) { printString += str; - else { - for (size_t z = 0; z < str.length(); z++) printString += std::to_string(uint8_t(str[z])) + " "; + } else { + for (size_t z = 0; z < str.length(); z++) { + printString += std::to_string(uint8_t(str[z])) + " "; + } } if (j != fieldValues.size() - 1) { printString += ", "; } } - if (Type().Field(i).IsArray()) printString += "]"; - if (i != NumFields() - 1) printString += ", "; + if (Type().Field(i).IsArray()) { + printString += "]"; + } + if (i != NumFields() - 1) { + printString += ", "; + } } return printString; } template <> -void PayloadIface::GetJSON(const TagsMatcher &tm, WrSerializer &ser) { +void PayloadIface::GetJSON(const TagsMatcher& tm, WrSerializer& ser) { JsonBuilder b(ser); JsonEncoder e(&tm); e.Encode(*this, b); } template <> -std::string PayloadIface::GetJSON(const TagsMatcher &tm) { +std::string PayloadIface::GetJSON(const TagsMatcher& tm) { WrSerializer ser; GetJSON(tm, ser); return std::string(ser.Slice()); @@ -338,30 +354,31 @@ std::string PayloadIface::GetJSON(const TagsMatcher &tm) { // Get fields hash template -size_t PayloadIface::GetHash(const FieldsSet &fields) const { +size_t PayloadIface::GetHash(const FieldsSet& fields) const { size_t ret = 0; VariantArray keys1; size_t tagPathIdx = 0; for (auto field : fields) { ret *= 127; if (field != IndexValueType::SetByJsonPath) { - auto &f = t_.Field(field); + auto& f = t_.Field(field); if (f.IsArray()) { - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); ret ^= arr->len; - uint8_t *p = v_->Ptr() + arr->offset; + uint8_t* p = v_->Ptr() + arr->offset; for (int i = 0; i < arr->len; i++, p += f.ElemSizeof()) { ret ^= PayloadFieldValue(f, p).Hash(); } - } else + } else { ret ^= Field(field).Hash(); + } } else { assertrx(tagPathIdx < fields.getTagsPathsLength()); if (fields.isTagsPathIndexed(tagPathIdx)) { - const IndexedTagsPath &tagsPath = fields.getIndexedTagsPath(tagPathIdx++); + const IndexedTagsPath& tagsPath = fields.getIndexedTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, keys1, KeyValueType::Undefined{}); } else { - const TagsPath &tagsPath = fields.getTagsPath(tagPathIdx++); + const TagsPath& tagsPath = fields.getTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, keys1, KeyValueType::Undefined{}); } ret ^= keys1.Hash(); @@ -377,49 +394,56 @@ uint64_t PayloadIface::GetHash() const noexcept { for (int field = 0; field < t_.NumFields(); field++) { ret <<= 1; - auto &f = t_.Field(field); + auto& f = t_.Field(field); if (f.IsArray()) { - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); ret ^= arr->len; - uint8_t *p = v_->Ptr() + arr->offset; + uint8_t* p = v_->Ptr() + arr->offset; for (int i = 0; i < arr->len; i++, p += f.ElemSizeof()) { ret ^= PayloadFieldValue(f, p).Hash(); } - } else + } else { ret ^= Field(field).Hash(); + } } return ret; } template -bool PayloadIface::IsEQ(const T &other, const FieldsSet &fields) const { +bool PayloadIface::IsEQ(const T& other, const FieldsSet& fields) const { size_t tagPathIdx = 0; PayloadIface o(t_, other); VariantArray keys1, keys2; for (auto field : fields) { if (field != IndexValueType::SetByJsonPath) { - auto &f = t_.Field(field); + auto& f = t_.Field(field); if (f.IsArray()) { - auto *arr1 = reinterpret_cast(Field(field).p_); - auto *arr2 = reinterpret_cast(o.Field(field).p_); - if (arr1->len != arr2->len) return false; + auto* arr1 = reinterpret_cast(Field(field).p_); + auto* arr2 = reinterpret_cast(o.Field(field).p_); + if (arr1->len != arr2->len) { + return false; + } - uint8_t *p1 = v_->Ptr() + arr1->offset; - uint8_t *p2 = o.v_->Ptr() + arr2->offset; + uint8_t* p1 = v_->Ptr() + arr1->offset; + uint8_t* p2 = o.v_->Ptr() + arr2->offset; for (int i = 0; i < arr1->len; i++, p1 += f.ElemSizeof(), p2 += f.ElemSizeof()) { - if (!PayloadFieldValue(f, p1).IsEQ(PayloadFieldValue(f, p2))) return false; + if (!PayloadFieldValue(f, p1).IsEQ(PayloadFieldValue(f, p2))) { + return false; + } } } else { - if (!Field(field).IsEQ(o.Field(field))) return false; + if (!Field(field).IsEQ(o.Field(field))) { + return false; + } } } else { if (fields.isTagsPathIndexed(tagPathIdx)) { - const IndexedTagsPath &tagsPath = fields.getIndexedTagsPath(tagPathIdx++); + const IndexedTagsPath& tagsPath = fields.getIndexedTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, keys1, KeyValueType::Undefined{}); o.GetByJsonPath(tagsPath, keys2, KeyValueType::Undefined{}); } else { - const TagsPath &tagsPath = fields.getTagsPath(tagPathIdx++); + const TagsPath& tagsPath = fields.getTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, keys1, KeyValueType::Undefined{}); o.GetByJsonPath(tagsPath, keys2, KeyValueType::Undefined{}); } @@ -433,8 +457,8 @@ bool PayloadIface::IsEQ(const T &other, const FieldsSet &fields) const { template template -ComparationResult PayloadIface::CompareField(const T &other, int field, const FieldsSet &fields, size_t &tagPathIdx, - const CollateOpts &collateOpts) const { +ComparationResult PayloadIface::CompareField(const T& other, int field, const FieldsSet& fields, size_t& tagPathIdx, + const CollateOpts& collateOpts) const { VariantArray krefs1, krefs2; PayloadIface o(t_, other); @@ -446,11 +470,11 @@ ComparationResult PayloadIface::CompareField(const T &other, int field, const } else { assertrx(tagPathIdx < fields.getTagsPathsLength()); if (fields.isTagsPathIndexed(tagPathIdx)) { - const IndexedTagsPath &tagsPath = fields.getIndexedTagsPath(tagPathIdx++); + const IndexedTagsPath& tagsPath = fields.getIndexedTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, krefs1, KeyValueType::Undefined{}); o.GetByJsonPath(tagsPath, krefs2, KeyValueType::Undefined{}); } else { - const TagsPath &tagsPath = fields.getTagsPath(tagPathIdx++); + const TagsPath& tagsPath = fields.getTagsPath(tagPathIdx++); GetByJsonPath(tagsPath, krefs1, KeyValueType::Undefined{}); o.GetByJsonPath(tagsPath, krefs2, KeyValueType::Undefined{}); } @@ -475,13 +499,13 @@ ComparationResult PayloadIface::CompareField(const T &other, int field, const template template -ComparationResult PayloadIface::Compare(const T &other, const FieldsSet &fields, size_t &firstDifferentFieldIdx, - const h_vector &collateOpts) const { +ComparationResult PayloadIface::Compare(const T& other, const FieldsSet& fields, size_t& firstDifferentFieldIdx, + const h_vector& collateOpts) const { size_t tagPathIdx = 0; const bool commonOpts = (collateOpts.size() == 1); for (size_t i = 0; i < fields.size(); ++i) { - const CollateOpts *opts(commonOpts ? collateOpts[0] : collateOpts[i]); + const CollateOpts* opts(commonOpts ? collateOpts[0] : collateOpts[i]); const auto cmpRes = CompareField(other, fields[i], fields, tagPathIdx, opts ? *opts : CollateOpts()); if (cmpRes != ComparationResult::Eq) { firstDifferentFieldIdx = i; @@ -493,96 +517,98 @@ ComparationResult PayloadIface::Compare(const T &other, const FieldsSet &fiel template template -ComparationResult PayloadIface::Compare(const T &other, const FieldsSet &fields, const CollateOpts &collateOpts) const { +ComparationResult PayloadIface::Compare(const T& other, const FieldsSet& fields, const CollateOpts& collateOpts) const { size_t firstDifferentFieldIdx = 0; return Compare(other, fields, firstDifferentFieldIdx, {&collateOpts}); } template void PayloadIface::AddRefStrings(int field) noexcept { - auto &f = t_.Field(field); + auto& f = t_.Field(field); assertrx(f.Type().template Is()); // direct payloadvalue manipulation for speed optimize if (!f.IsArray()) { - auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); - key_string_add_ref(const_cast(str.getCxxstr())); + auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); + key_string_add_ref(const_cast(str.getCxxstr())); } else { - auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); + auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); for (int i = 0; i < arr->len; i++) { - auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); - key_string_add_ref(const_cast(str.getCxxstr())); + auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); + key_string_add_ref(const_cast(str.getCxxstr())); } } } template void PayloadIface::AddRefStrings() noexcept { - for (auto field : t_.StrFields()) AddRefStrings(field); + for (auto field : t_.StrFields()) { + AddRefStrings(field); + } } template void PayloadIface::ReleaseStrings(int field) noexcept { - auto &f = t_.Field(field); + auto& f = t_.Field(field); assertrx(f.Type().template Is()); // direct payloadvalue manipulation for speed optimize if (!f.IsArray()) { - auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); - key_string_release(const_cast(str.getCxxstr())); + auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); + key_string_release(const_cast(str.getCxxstr())); } else { - auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); + auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); for (int i = 0; i < arr->len; i++) { - auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); - key_string_release(const_cast(str.getCxxstr())); + auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); + key_string_release(const_cast(str.getCxxstr())); } } } template template -void PayloadIface::copyOrMoveStrings(int field, StrHolder &dest, bool copy) { - auto &f = t_.Field(field); +void PayloadIface::copyOrMoveStrings(int field, StrHolder& dest, bool copy) { + auto& f = t_.Field(field); assertrx(f.Type().template Is()); // direct payloadvalue manipulation for speed optimize if (!f.IsArray()) { - auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); - dest.emplace_back(reinterpret_cast(const_cast(str.getCxxstr())), copy); + auto str = *reinterpret_cast((v_->Ptr() + f.Offset())); + dest.emplace_back(reinterpret_cast(const_cast(str.getCxxstr())), copy); } else { - auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); + auto arr = reinterpret_cast(v_->Ptr() + f.Offset()); for (int i = 0; i < arr->len; i++) { - auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); - dest.emplace_back(reinterpret_cast(const_cast(str.getCxxstr())), copy); + auto str = *reinterpret_cast(v_->Ptr() + arr->offset + i * t_.Field(field).ElemSizeof()); + dest.emplace_back(reinterpret_cast(const_cast(str.getCxxstr())), copy); } } } template -template ::value>::type *> -void PayloadIface::setArray(int field, const VariantArray &keys, bool append) { +template ::value>::type*> +void PayloadIface::setArray(int field, const VariantArray& keys, bool append) { if (keys.IsNullValue()) { ResizeArray(field, 0, append); return; } int pos = ResizeArray(field, keys.size(), append); - auto const *const arr = reinterpret_cast(Field(field).p_); + const auto* const arr = reinterpret_cast(Field(field).p_); const auto elemSize = t_.Field(field).ElemSizeof(); - for (const Variant &kv : keys) { + for (const Variant& kv : keys) { PayloadFieldValue pv(t_.Field(field), v_->Ptr() + arr->offset + (pos++) * elemSize); pv.Set(kv); } } template -void PayloadIface::MoveStrings(int field, StringsHolder &dest) { +void PayloadIface::MoveStrings(int field, StringsHolder& dest) { copyOrMoveStrings(field, dest, false); } template -void PayloadIface::CopyStrings(std::vector &dest) { +void PayloadIface::CopyStrings(std::vector& dest) { for (auto field : t_.StrFields()) { copyOrMoveStrings(field, dest, true); } @@ -590,11 +616,13 @@ void PayloadIface::CopyStrings(std::vector &dest) { template void PayloadIface::ReleaseStrings() noexcept { - for (auto field : t_.StrFields()) ReleaseStrings(field); + for (auto field : t_.StrFields()) { + ReleaseStrings(field); + } } template -template ::value>::type *> +template ::value>::type*> T PayloadIface::CopyTo(PayloadType modifiedType, bool newOrUpdatedFields) { if (newOrUpdatedFields) { return CopyWithNewOrUpdatedFields(modifiedType); @@ -604,12 +632,12 @@ T PayloadIface::CopyTo(PayloadType modifiedType, bool newOrUpdatedFields) { } template -template ::value>::type *> +template ::value>::type*> T PayloadIface::CopyWithNewOrUpdatedFields(PayloadType modifiedType) { size_t totalGrow = 0; for (int idx = 1; idx < modifiedType.NumFields(); ++idx) { if (!t_.Contains(modifiedType.Field(idx).Name())) { - const PayloadFieldType &fieldType = modifiedType.Field(idx); + const PayloadFieldType& fieldType = modifiedType.Field(idx); totalGrow += fieldType.IsArray() ? sizeof(PayloadFieldValue::Array) : fieldType.Sizeof(); } else { if (modifiedType.Field(idx).IsArray() && !t_.Field(idx).IsArray()) { @@ -630,16 +658,16 @@ T PayloadIface::CopyWithNewOrUpdatedFields(PayloadType modifiedType) { } template -template ::value>::type *> +template ::value>::type*> T PayloadIface::CopyWithRemovedFields(PayloadType modifiedType) { size_t totalReduce = 0; std::vector fieldsLeft; for (int idx = 0; idx < t_.NumFields(); ++idx) { - const std::string &fieldname(t_.Field(idx).Name()); + const std::string& fieldname(t_.Field(idx).Name()); if (modifiedType.Contains(fieldname)) { fieldsLeft.emplace_back(fieldname); } else { - const PayloadFieldType &fieldType = t_.Field(idx); + const PayloadFieldType& fieldType = t_.Field(idx); totalReduce += fieldType.IsArray() ? sizeof(PayloadFieldValue::Array) : fieldType.Sizeof(); } } @@ -647,7 +675,7 @@ T PayloadIface::CopyWithRemovedFields(PayloadType modifiedType) { VariantArray kr; T pv(RealSize() - totalReduce); PayloadIface copyValueInterface(modifiedType, pv); - for (const auto &fieldname : fieldsLeft) { + for (const auto& fieldname : fieldsLeft) { Get(fieldname, kr); copyValueInterface.Set(fieldname, kr, false); } @@ -659,68 +687,64 @@ T PayloadIface::CopyWithRemovedFields(PayloadType modifiedType) { #pragma warning(disable : 5037) #endif -template void PayloadIface::Set(0)>(std::string_view, VariantArray const &, bool); -template void PayloadIface::Set(0)>(int, VariantArray const &, bool); -template void PayloadIface::Set(0)>(int, int, const Variant &); -template void PayloadIface::SetSingleElement(0)>(int, const Variant &); - -template PayloadValue PayloadIface::CopyTo(0)>(PayloadType t, bool newFields); -template PayloadValue PayloadIface::CopyWithNewOrUpdatedFields(0)>(PayloadType t); -template PayloadValue PayloadIface::CopyWithRemovedFields(0)>(PayloadType t); - -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; +template void PayloadIface::Set(0)>(std::string_view, const VariantArray&, bool); +template void PayloadIface::Set(0)>(int, const VariantArray&, bool); +template void PayloadIface::Set(0)>(int, int, const Variant&); +template void PayloadIface::SetSingleElement(0)>(int, const Variant&); + +template PayloadValue PayloadIface::CopyTo(0)>(PayloadType t, bool newFields); +template PayloadValue PayloadIface::CopyWithNewOrUpdatedFields(0)>(PayloadType t); +template PayloadValue PayloadIface::CopyWithRemovedFields(0)>(PayloadType t); + +template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, size_t &, const h_vector &) const; - -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, - size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField( - const PayloadValue &, int, const FieldsSet &, size_t &, const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, - size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, size_t &, - const CollateOpts &) const; -template ComparationResult PayloadIface::CompareField(const PayloadValue &, int, - const FieldsSet &, size_t &, - const CollateOpts &) const; + const PayloadValue&, const FieldsSet&, size_t&, const h_vector&) const; + +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; +template ComparationResult PayloadIface::CompareField(const PayloadValue&, int, + const FieldsSet&, size_t&, + const CollateOpts&) const; template class PayloadIface; template class PayloadIface; diff --git a/cpp_src/core/payload/payloadiface.h b/cpp_src/core/payload/payloadiface.h index c9fad0e4c..672f3be04 100644 --- a/cpp_src/core/payload/payloadiface.h +++ b/cpp_src/core/payload/payloadiface.h @@ -22,30 +22,30 @@ class PayloadIface { friend class PayloadIface; public: - PayloadIface(const PayloadType &t, T &v) noexcept : t_(*t.get()), v_(&v) {} - PayloadIface(const PayloadTypeImpl &t, T &v) noexcept : t_(t), v_(&v) {} + PayloadIface(const PayloadType& t, T& v) noexcept : t_(*t.get()), v_(&v) {} + PayloadIface(const PayloadTypeImpl& t, T& v) noexcept : t_(t), v_(&v) {} void Reset() noexcept { memset(v_->Ptr(), 0, t_.TotalSize()); } // Get element(s) by field index - void Get(int field, VariantArray &, Variant::hold_t) const; - void Get(int field, VariantArray &) const; + void Get(int field, VariantArray&, Variant::hold_t) const; + void Get(int field, VariantArray&) const; // Get element by field and array index [[nodiscard]] Variant Get(int field, int idx, Variant::hold_t) const; [[nodiscard]] Variant Get(int field, int idx) const; // Get array as span of typed elements template - span GetArray(int field) const & { + span GetArray(int field) const& { assertrx(field < Type().NumFields()); assertrx(Type().Field(field).IsArray()); - auto *arr = reinterpret_cast(Field(field).p_); - return span(reinterpret_cast(v_->Ptr() + arr->offset), arr->len); + auto* arr = reinterpret_cast(Field(field).p_); + return span(reinterpret_cast(v_->Ptr() + arr->offset), arr->len); } // Get array len int GetArrayLen(int field) const { assertrx(field < Type().NumFields()); assertrx(Type().Field(field).IsArray()); - auto *arr = reinterpret_cast(Field(field).p_); + auto* arr = reinterpret_cast(Field(field).p_); return arr->len; } @@ -55,24 +55,24 @@ class PayloadIface { int ResizeArray(int field, int grow, bool append); // Set element or array by field index - template ::value>::type * = nullptr> - void Set(int field, const VariantArray &keys, bool append = false) { + template ::value>::type* = nullptr> + void Set(int field, const VariantArray& keys, bool append = false) { if (!t_.Field(field).IsArray() && keys.size() >= 1) { Field(field).Set(keys[0]); } else { setArray(field, keys, append); } } - template ::value>::type * = nullptr> - void Set(int field, const Variant &key, bool append = false) { + template ::value>::type* = nullptr> + void Set(int field, const Variant& key, bool append = false) { if (t_.Field(field).IsArray()) { Set(field, VariantArray{key}, append); return; } Field(field).Set(key); } - template ::value>::type * = nullptr> - void Set(int field, Variant &&key, bool append = false) { + template ::value>::type* = nullptr> + void Set(int field, Variant&& key, bool append = false) { if (t_.Field(field).IsArray()) { Set(field, VariantArray{std::move(key)}, append); return; @@ -81,44 +81,44 @@ class PayloadIface { } // Set non-array element by field index - template ::value>::type * = nullptr> - void SetSingleElement(int field, const Variant &key); + template ::value>::type* = nullptr> + void SetSingleElement(int field, const Variant& key); // Set element or array by field index - template ::value>::type * = nullptr> - void Set(std::string_view field, const VariantArray &keys, bool append = false) { + template ::value>::type* = nullptr> + void Set(std::string_view field, const VariantArray& keys, bool append = false) { return Set(t_.FieldByName(field), keys, append); } - template ::value>::type * = nullptr> - void Set(std::string_view field, const Variant &key, bool append = false) { + template ::value>::type* = nullptr> + void Set(std::string_view field, const Variant& key, bool append = false) { return Set(t_.FieldByName(field), key, append); } - template ::value>::type * = nullptr> - void Set(std::string_view field, Variant &&key, bool append = false) { + template ::value>::type* = nullptr> + void Set(std::string_view field, Variant&& key, bool append = false) { return Set(t_.FieldByName(field), std::move(key), append); } // Set element or array by field index and element index - template ::value>::type * = nullptr> - void Set(int field, int idx, const Variant &v); + template ::value>::type* = nullptr> + void Set(int field, int idx, const Variant& v); // Copies current payload value to a new one // according to PayloadType format - template ::value>::type * = nullptr> + template ::value>::type* = nullptr> T CopyTo(PayloadType t, bool newFields = true); // Get element(s) by field name - void Get(std::string_view field, VariantArray &, Variant::hold_t) const; - void Get(std::string_view field, VariantArray &) const; + void Get(std::string_view field, VariantArray&, Variant::hold_t) const; + void Get(std::string_view field, VariantArray&) const; // Get element(s) by json path - void GetByJsonPath(std::string_view jsonPath, TagsMatcher &tagsMatcher, VariantArray &, KeyValueType expectedType) const; - void GetByJsonPath(const TagsPath &jsonPath, VariantArray &, KeyValueType expectedType) const; - void GetByJsonPath(const IndexedTagsPath &jsonPath, VariantArray &, KeyValueType expectedType) const; - void GetByFieldsSet(const FieldsSet &, VariantArray &, KeyValueType expectedType, - const h_vector &expectedCompositeTypes) const; - [[nodiscard]] Variant GetComposite(const FieldsSet &, const h_vector &expectedTypes) const; - VariantArray GetIndexedArrayData(const IndexedTagsPath &jsonPath, int field, int &offset, int &size) const; + void GetByJsonPath(std::string_view jsonPath, TagsMatcher& tagsMatcher, VariantArray&, KeyValueType expectedType) const; + void GetByJsonPath(const TagsPath& jsonPath, VariantArray&, KeyValueType expectedType) const; + void GetByJsonPath(const IndexedTagsPath& jsonPath, VariantArray&, KeyValueType expectedType) const; + void GetByFieldsSet(const FieldsSet&, VariantArray&, KeyValueType expectedType, + const h_vector& expectedCompositeTypes) const; + [[nodiscard]] Variant GetComposite(const FieldsSet&, const h_vector& expectedTypes) const; + VariantArray GetIndexedArrayData(const IndexedTagsPath& jsonPath, int field, int& offset, int& size) const; // Get fields count int NumFields() const noexcept { return t_.NumFields(); } @@ -126,30 +126,30 @@ class PayloadIface { // Real size of payload with arrays size_t RealSize() const; - inline const uint8_t *Ptr() const noexcept { return v_->Ptr(); } - const PayloadTypeImpl &Type() const noexcept { return t_; } - const T *Value() const noexcept { return v_; } + inline const uint8_t* Ptr() const noexcept { return v_->Ptr(); } + const PayloadTypeImpl& Type() const noexcept { return t_; } + const T* Value() const noexcept { return v_; } // Serialize field values - void SerializeFields(WrSerializer &ser, const FieldsSet &fields) const; + void SerializeFields(WrSerializer& ser, const FieldsSet& fields) const; // Get hash by fields mask - size_t GetHash(const FieldsSet &fields) const; + size_t GetHash(const FieldsSet& fields) const; // Compare is EQ by field mask - bool IsEQ(const T &other, const FieldsSet &fields) const; + bool IsEQ(const T& other, const FieldsSet& fields) const; // Get hash of all document uint64_t GetHash() const noexcept; // Compare single field (indexed or non-indexed) template - ComparationResult CompareField(const T &other, int field, const FieldsSet &fields, size_t &tagPathIdx, - const CollateOpts &collateOpts) const; + ComparationResult CompareField(const T& other, int field, const FieldsSet& fields, size_t& tagPathIdx, + const CollateOpts& collateOpts) const; // Compare 2 objects by field mask template - ComparationResult Compare(const T &other, const FieldsSet &fields, const CollateOpts &collateOpts = CollateOpts()) const; + ComparationResult Compare(const T& other, const FieldsSet& fields, const CollateOpts& collateOpts = CollateOpts()) const; template - ComparationResult Compare(const T &other, const FieldsSet &fields, size_t &firstDifferentFieldIdx, - const h_vector &collateOpts) const; + ComparationResult Compare(const T& other, const FieldsSet& fields, size_t& firstDifferentFieldIdx, + const h_vector& collateOpts) const; // Get PayloadFieldValue by field index PayloadFieldValue Field(int field) const noexcept { return PayloadFieldValue(t_.Field(field), v_->Ptr() + t_.Field(field).Offset()); } @@ -160,39 +160,39 @@ class PayloadIface { // Release strings void ReleaseStrings() noexcept; void ReleaseStrings(int field) noexcept; - void MoveStrings(int field, StringsHolder &dest); - void CopyStrings(std::vector &dest); + void MoveStrings(int field, StringsHolder& dest); + void CopyStrings(std::vector& dest); // Item values' string for printing std::string Dump() const; // Item as JSON - std::string GetJSON(const TagsMatcher &tm); - void GetJSON(const TagsMatcher &tm, WrSerializer &ser); + std::string GetJSON(const TagsMatcher& tm); + void GetJSON(const TagsMatcher& tm, WrSerializer& ser); private: enum class HoldPolicy : bool { Hold, NoHold }; - template ::value>::type * = nullptr> + template ::value>::type* = nullptr> T CopyWithNewOrUpdatedFields(PayloadType t); - template ::value>::type * = nullptr> + template ::value>::type* = nullptr> T CopyWithRemovedFields(PayloadType t); template - void copyOrMoveStrings(int field, StrHolder &dest, bool copy); + void copyOrMoveStrings(int field, StrHolder& dest, bool copy); template - void getByJsonPath(const P &path, VariantArray &, KeyValueType expectedType) const; - template ::value>::type * = nullptr> - void setArray(int field, const VariantArray &keys, bool append); + void getByJsonPath(const P& path, VariantArray&, KeyValueType expectedType) const; + template ::value>::type* = nullptr> + void setArray(int field, const VariantArray& keys, bool append); template - void get(int field, VariantArray &, HoldT h) const; + void get(int field, VariantArray&, HoldT h) const; template [[nodiscard]] Variant get(int field, int idx, HoldT h) const; template - void get(std::string_view field, VariantArray &, HoldT h) const; + void get(std::string_view field, VariantArray&, HoldT h) const; // Array of elements types , not owning - const PayloadTypeImpl &t_; + const PayloadTypeImpl& t_; // Data of elements, not owning - T *v_; + T* v_; }; template <> @@ -201,49 +201,50 @@ template <> int PayloadIface::ResizeArray(int, int, bool) = delete; template <> -void PayloadIface::GetJSON(const TagsMatcher &, WrSerializer &); +void PayloadIface::GetJSON(const TagsMatcher&, WrSerializer&); template <> -std::string PayloadIface::GetJSON(const TagsMatcher &); +std::string PayloadIface::GetJSON(const TagsMatcher&); template <> -void PayloadIface::GetJSON(const TagsMatcher &, WrSerializer &) = delete; +void PayloadIface::GetJSON(const TagsMatcher&, WrSerializer&) = delete; template <> -std::string PayloadIface::GetJSON(const TagsMatcher &) = delete; - -extern template void PayloadIface::Set(0)>(std::string_view, VariantArray const &, bool); -extern template void PayloadIface::Set(0)>(int, VariantArray const &, bool); -extern template void PayloadIface::Set(0)>(int, int, const Variant &); -extern template void PayloadIface::SetSingleElement(0)>(int, const Variant &); - -extern template PayloadValue PayloadIface::CopyTo(0)>(PayloadType t, bool newFields); -extern template PayloadValue PayloadIface::CopyWithNewOrUpdatedFields(0)>(PayloadType t); -extern template PayloadValue PayloadIface::CopyWithRemovedFields(0)>(PayloadType t); - -extern template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -extern template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; +std::string PayloadIface::GetJSON(const TagsMatcher&) = delete; + +extern template void PayloadIface::Set(0)>(std::string_view, const VariantArray&, bool); +extern template void PayloadIface::Set(0)>(int, const VariantArray&, bool); +extern template void PayloadIface::Set(0)>(int, int, const Variant&); +extern template void PayloadIface::SetSingleElement(0)>(int, const Variant&); + +extern template PayloadValue PayloadIface::CopyTo(0)>(PayloadType t, bool newFields); +extern template PayloadValue PayloadIface::CopyWithNewOrUpdatedFields(0)>(PayloadType t); +extern template PayloadValue PayloadIface::CopyWithRemovedFields(0)>(PayloadType t); + +extern template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +extern template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; extern template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, const CollateOpts &) const; + const PayloadValue&, const FieldsSet&, const CollateOpts&) const; extern template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, const CollateOpts &) const; -extern template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; -extern template ComparationResult PayloadIface::Compare(const PayloadValue &, - const FieldsSet &, - const CollateOpts &) const; + const PayloadValue&, const FieldsSet&, const CollateOpts&) const; +extern template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; +extern template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; extern template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, const CollateOpts &) const; -extern template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, const CollateOpts &) const; + const PayloadValue&, const FieldsSet&, const CollateOpts&) const; +extern template ComparationResult PayloadIface::Compare(const PayloadValue&, + const FieldsSet&, + const CollateOpts&) const; extern template ComparationResult PayloadIface::Compare( - const PayloadValue &, const FieldsSet &, size_t &, const h_vector &) const; + const PayloadValue&, const FieldsSet&, size_t&, const h_vector&) const; extern template ComparationResult PayloadIface::CompareField( - const PayloadValue &, int, const FieldsSet &, size_t &, const CollateOpts &) const; + const PayloadValue&, int, const FieldsSet&, size_t&, const CollateOpts&) const; extern template class PayloadIface; extern template class PayloadIface; diff --git a/cpp_src/core/payload/payloadtype.cc b/cpp_src/core/payload/payloadtype.cc index 4aa4350f2..0f9bfd33d 100644 --- a/cpp_src/core/payload/payloadtype.cc +++ b/cpp_src/core/payload/payloadtype.cc @@ -15,24 +15,28 @@ size_t PayloadTypeImpl::TotalSize() const noexcept { std::string PayloadTypeImpl::ToString() const { std::stringstream ret; - for (auto &f : fields_) { + for (auto& f : fields_) { ret << f.Type().Name() << (f.IsArray() ? "[]" : "") << " '" << f.Name() << '\'' << " json:\""; - for (auto &jp : f.JsonPaths()) ret << jp << ";"; + for (auto& jp : f.JsonPaths()) { + ret << jp << ";"; + } ret << "\"\n"; } return ret.str(); } -void PayloadTypeImpl::Dump(std::ostream &os, std::string_view step, std::string_view offset) const { +void PayloadTypeImpl::Dump(std::ostream& os, std::string_view step, std::string_view offset) const { std::string newOffset{offset}; newOffset += step; os << '{'; - for (auto &f : fields_) { + for (auto& f : fields_) { os << '\n' << newOffset << f.Type().Name() << (f.IsArray() ? "[]" : "") << " '" << f.Name() << "'" << " json:\""; for (size_t i = 0, s = f.JsonPaths().size(); i < s; ++i) { - if (i != 0) os << ';'; + if (i != 0) { + os << ';'; + } os << f.JsonPaths()[i]; } os << '"'; @@ -47,14 +51,16 @@ void PayloadTypeImpl::Add(PayloadFieldType f) { auto it = fieldsByName_.find(f.Name()); if (it != fieldsByName_.end()) { // Non unique name -> check type, and upgrade to array if types are the same - auto &oldf = fields_[it->second]; + auto& oldf = fields_[it->second]; throw Error(errLogic, "Cannot add field with name '%s' and type '%s' to namespace '%s'. It already exists with type '%s'", f.Name(), f.Type().Name(), Name(), oldf.Type().Name()); } else { // Unique name -> just add field f.SetOffset(TotalSize()); - for (auto &jp : f.JsonPaths()) { - if (!jp.length()) continue; + for (auto& jp : f.JsonPaths()) { + if (!jp.length()) { + continue; + } auto res = fieldsByJsonPath_.emplace(jp, int(fields_.size())); if (!res.second && res.first->second != int(fields_.size())) { throw Error(errLogic, "Cannot add field with name '%s' to namespace '%s'. Json path '%s' already used in field '%s'", @@ -73,14 +79,20 @@ void PayloadTypeImpl::Add(PayloadFieldType f) { bool PayloadTypeImpl::Drop(std::string_view field) { auto itField = fieldsByName_.find(field); - if (itField == fieldsByName_.end()) return false; + if (itField == fieldsByName_.end()) { + return false; + } const auto fieldIdx = itField->second; - for (auto &f : fieldsByName_) { - if (f.second > fieldIdx) --f.second; + for (auto& f : fieldsByName_) { + if (f.second > fieldIdx) { + --f.second; + } } - for (auto &f : fieldsByJsonPath_) { - if (f.second > fieldIdx) --f.second; + for (auto& f : fieldsByJsonPath_) { + if (f.second > fieldIdx) { + --f.second; + } } const auto fieldType = fields_[fieldIdx].Type(); @@ -94,7 +106,7 @@ bool PayloadTypeImpl::Drop(std::string_view field) { ++it; } - for (auto &jp : fields_[fieldIdx].JsonPaths()) { + for (auto& jp : fields_[fieldIdx].JsonPaths()) { fieldsByJsonPath_.erase(jp); } @@ -103,7 +115,7 @@ bool PayloadTypeImpl::Drop(std::string_view field) { if (idx == 0) { fields_[idx].SetOffset(0); } else { - const PayloadFieldType &plTypePrev(fields_[idx - 1]); + const PayloadFieldType& plTypePrev(fields_[idx - 1]); fields_[idx].SetOffset(plTypePrev.Offset() + plTypePrev.Sizeof()); } } @@ -115,24 +127,30 @@ bool PayloadTypeImpl::Drop(std::string_view field) { int PayloadTypeImpl::FieldByName(std::string_view field) const { auto it = fieldsByName_.find(field); - if (it == fieldsByName_.end()) throw Error(errLogic, "Field '%s' not found in namespace '%s'", field, Name()); + if (it == fieldsByName_.end()) { + throw Error(errLogic, "Field '%s' not found in namespace '%s'", field, Name()); + } return it->second; } -bool PayloadTypeImpl::FieldByName(std::string_view name, int &field) const noexcept { +bool PayloadTypeImpl::FieldByName(std::string_view name, int& field) const noexcept { auto it = fieldsByName_.find(name); - if (it == fieldsByName_.end()) return false; + if (it == fieldsByName_.end()) { + return false; + } field = it->second; return true; } int PayloadTypeImpl::FieldByJsonPath(std::string_view jsonPath) const noexcept { auto it = fieldsByJsonPath_.find(jsonPath); - if (it == fieldsByJsonPath_.end()) return -1; + if (it == fieldsByJsonPath_.end()) { + return -1; + } return it->second; } -void PayloadTypeImpl::serialize(WrSerializer &ser) const { +void PayloadTypeImpl::serialize(WrSerializer& ser) const { ser.PutVarUint(base_key_string::export_hdr_offset()); ser.PutVarUint(NumFields()); for (int i = 0; i < NumFields(); i++) { @@ -142,11 +160,13 @@ void PayloadTypeImpl::serialize(WrSerializer &ser) const { ser.PutVarUint(Field(i).ElemSizeof()); ser.PutVarUint(Field(i).IsArray()); ser.PutVarUint(Field(i).JsonPaths().size()); - for (auto &jp : Field(i).JsonPaths()) ser.PutVString(jp); + for (auto& jp : Field(i).JsonPaths()) { + ser.PutVString(jp); + } } } -void PayloadTypeImpl::deserialize(Serializer &ser) { +void PayloadTypeImpl::deserialize(Serializer& ser) { fields_.clear(); fieldsByName_.clear(); fieldsByJsonPath_.clear(); @@ -165,40 +185,46 @@ void PayloadTypeImpl::deserialize(Serializer &ser) { bool isArray = ser.GetVarUint(); uint64_t jsonPathsCount = ser.GetVarUint(); - while (jsonPathsCount--) jsonPaths.push_back(std::string(ser.GetVString())); + while (jsonPathsCount--) { + jsonPaths.push_back(std::string(ser.GetVString())); + } (void)elemSizeof; PayloadFieldType ft(t, name, jsonPaths, isArray); - if (isArray) ft.SetArray(); + if (isArray) { + ft.SetArray(); + } ft.SetOffset(offset); fieldsByName_.emplace(name, fields_.size()); - if (t.Is()) strFields_.push_back(fields_.size()); + if (t.Is()) { + strFields_.push_back(fields_.size()); + } fields_.push_back(ft); } } -PayloadType::PayloadType(const std::string &name, std::initializer_list fields) +PayloadType::PayloadType(const std::string& name, std::initializer_list fields) : shared_cow_ptr(make_intrusive>(name, fields)) {} -PayloadType::PayloadType(const PayloadTypeImpl &impl) +PayloadType::PayloadType(const PayloadTypeImpl& impl) : shared_cow_ptr(make_intrusive>(impl)) {} PayloadType::~PayloadType() = default; -const PayloadFieldType &PayloadType::Field(int field) const { return get()->Field(field); } -const std::string &PayloadType::Name() const { return get()->Name(); } -void PayloadType::SetName(const std::string &name) { clone()->SetName(name); } +const PayloadFieldType& PayloadType::Field(int field) const { return get()->Field(field); } +const std::string& PayloadType::Name() const { return get()->Name(); } +void PayloadType::SetName(const std::string& name) { clone()->SetName(name); } int PayloadType::NumFields() const { return get()->NumFields(); } void PayloadType::Add(PayloadFieldType f) { clone()->Add(std::move(f)); } bool PayloadType::Drop(std::string_view field) { return clone()->Drop(field); } int PayloadType::FieldByName(std::string_view field) const { return get()->FieldByName(field); } -bool PayloadType::FieldByName(std::string_view name, int &field) const { return get()->FieldByName(name, field); } +bool PayloadType::FieldByName(std::string_view name, int& field) const { return get()->FieldByName(name, field); } bool PayloadType::Contains(std::string_view field) const { return get()->Contains(field); } int PayloadType::FieldByJsonPath(std::string_view jsonPath) const { return get()->FieldByJsonPath(jsonPath); } -const std::vector &PayloadType::StrFields() const { return get()->StrFields(); } +const std::vector& PayloadType::StrFields() const { return get()->StrFields(); } size_t PayloadType::TotalSize() const { return get()->TotalSize(); } std::string PayloadType::ToString() const { return get()->ToString(); } -void PayloadType::Dump(std::ostream &os, std::string_view step, std::string_view offset) const { +void PayloadType::Dump(std::ostream& os, std::string_view step, std::string_view offset) const { std::string newOffset{offset}; newOffset += step; os << "{\n" << newOffset << "name: " << Name() << ",\n" << newOffset; @@ -206,11 +232,11 @@ void PayloadType::Dump(std::ostream &os, std::string_view step, std::string_view os << '\n' << offset << '}'; } -void PayloadTypeImpl::checkNewJsonPathBeforeAdd(const PayloadFieldType &f, const std::string &jsonPath) const { +void PayloadTypeImpl::checkNewJsonPathBeforeAdd(const PayloadFieldType& f, const std::string& jsonPath) const { const auto pos = jsonPath.find('.'); if (pos < jsonPath.length() - 1) { - for (auto &fld : fields_) { - for (auto &jpfld : fld.JsonPaths()) { + for (auto& fld : fields_) { + for (auto& jpfld : fld.JsonPaths()) { // new field total overwrites existing one if ((jsonPath.rfind(jpfld, 0) == 0) && (jsonPath[jpfld.length()] == '.')) { throw Error(errLogic, diff --git a/cpp_src/core/payload/payloadtype.h b/cpp_src/core/payload/payloadtype.h index 07e512eb3..dd8292d6e 100644 --- a/cpp_src/core/payload/payloadtype.h +++ b/cpp_src/core/payload/payloadtype.h @@ -13,28 +13,28 @@ class PayloadTypeImpl; class PayloadType : public shared_cow_ptr { public: PayloadType() noexcept = default; - PayloadType(PayloadType &&) noexcept = default; - PayloadType(const PayloadType &) = default; - PayloadType &operator=(PayloadType &&) noexcept = default; - PayloadType &operator=(const PayloadType &) = default; - explicit PayloadType(const std::string &name, std::initializer_list fields = {}); - explicit PayloadType(const PayloadTypeImpl &impl); + PayloadType(PayloadType&&) noexcept = default; + PayloadType(const PayloadType&) = default; + PayloadType& operator=(PayloadType&&) noexcept = default; + PayloadType& operator=(const PayloadType&) = default; + explicit PayloadType(const std::string& name, std::initializer_list fields = {}); + explicit PayloadType(const PayloadTypeImpl& impl); ~PayloadType(); - const PayloadFieldType &Field(int field) const; + const PayloadFieldType& Field(int field) const; - const std::string &Name() const; - void SetName(const std::string &name); + const std::string& Name() const; + void SetName(const std::string& name); int NumFields() const; void Add(PayloadFieldType); bool Drop(std::string_view field); int FieldByName(std::string_view field) const; - bool FieldByName(std::string_view name, int &field) const; + bool FieldByName(std::string_view name, int& field) const; bool Contains(std::string_view field) const; int FieldByJsonPath(std::string_view jsonPath) const; - const std::vector &StrFields() const; + const std::vector& StrFields() const; size_t TotalSize() const; std::string ToString() const; - void Dump(std::ostream &, std::string_view step = " ", std::string_view offset = "") const; + void Dump(std::ostream&, std::string_view step = " ", std::string_view offset = "") const; }; } // namespace reindexer diff --git a/cpp_src/core/payload/payloadtypeimpl.h b/cpp_src/core/payload/payloadtypeimpl.h index 64db9568c..6347a3a49 100644 --- a/cpp_src/core/payload/payloadtypeimpl.h +++ b/cpp_src/core/payload/payloadtypeimpl.h @@ -20,34 +20,34 @@ class PayloadTypeImpl { public: PayloadTypeImpl(std::string name, std::initializer_list fields = {}) : fields_(fields), name_(std::move(name)) {} - const PayloadFieldType &Field(int field) const &noexcept { + const PayloadFieldType& Field(int field) const& noexcept { assertf(field < NumFields(), "%s: %d, %d", name_, field, NumFields()); return fields_[field]; } - const PayloadFieldType &Field(int) const && = delete; + const PayloadFieldType& Field(int) const&& = delete; - const std::string &Name() const &noexcept { return name_; } - const std::string &Name() const && = delete; + const std::string& Name() const& noexcept { return name_; } + const std::string& Name() const&& = delete; void SetName(std::string name) noexcept { name_ = std::move(name); } int NumFields() const noexcept { return fields_.size(); } void Add(PayloadFieldType f); bool Drop(std::string_view field); int FieldByName(std::string_view field) const; - bool FieldByName(std::string_view name, int &field) const noexcept; + bool FieldByName(std::string_view name, int& field) const noexcept; bool Contains(std::string_view field) const noexcept { return fieldsByName_.find(field) != fieldsByName_.end(); } int FieldByJsonPath(std::string_view jsonPath) const noexcept; - const std::vector &StrFields() const &noexcept { return strFields_; } - const std::vector &StrFields() const && = delete; + const std::vector& StrFields() const& noexcept { return strFields_; } + const std::vector& StrFields() const&& = delete; - void serialize(WrSerializer &ser) const; - void deserialize(Serializer &ser); + void serialize(WrSerializer& ser) const; + void deserialize(Serializer& ser); size_t TotalSize() const noexcept; std::string ToString() const; - void Dump(std::ostream &, std::string_view step, std::string_view offset) const; + void Dump(std::ostream&, std::string_view step, std::string_view offset) const; private: - void checkNewJsonPathBeforeAdd(const PayloadFieldType &f, const std::string &jsonPath) const; + void checkNewJsonPathBeforeAdd(const PayloadFieldType& f, const std::string& jsonPath) const; std::vector fields_; FieldMap fieldsByName_; diff --git a/cpp_src/core/payload/payloadvalue.cc b/cpp_src/core/payload/payloadvalue.cc index d1b07a365..692f2fa64 100644 --- a/cpp_src/core/payload/payloadvalue.cc +++ b/cpp_src/core/payload/payloadvalue.cc @@ -4,7 +4,7 @@ namespace reindexer { -PayloadValue::PayloadValue(size_t size, const uint8_t *ptr, size_t cap) : p_(nullptr) { +PayloadValue::PayloadValue(size_t size, const uint8_t* ptr, size_t cap) : p_(nullptr) { p_ = alloc((cap != 0) ? cap : size); if (ptr) { @@ -14,15 +14,16 @@ PayloadValue::PayloadValue(size_t size, const uint8_t *ptr, size_t cap) : p_(nul } } -uint8_t *PayloadValue::alloc(size_t cap) { - auto pn = reinterpret_cast(operator new(cap + sizeof(dataHeader))); - dataHeader *nheader = reinterpret_cast(pn); +uint8_t* PayloadValue::alloc(size_t cap) { + auto pn = reinterpret_cast(operator new(cap + sizeof(dataHeader))); + dataHeader* nheader = reinterpret_cast(pn); new (nheader) dataHeader(); nheader->cap = cap; if (p_) { nheader->lsn = header()->lsn; - } else + } else { nheader->lsn = -1; + } return pn; } @@ -58,7 +59,9 @@ void PayloadValue::Resize(size_t oldSize, size_t newSize) { assertrx(p_); assertrx(header()->refcount.load(std::memory_order_acquire) == 1); - if (newSize <= header()->cap) return; + if (newSize <= header()->cap) { + return; + } auto pn = alloc(newSize); memcpy(pn + sizeof(dataHeader), Ptr(), oldSize); @@ -69,21 +72,23 @@ void PayloadValue::Resize(size_t oldSize, size_t newSize) { p_ = pn; } -std::ostream &operator<<(std::ostream &os, const PayloadValue &pv) { - os << "{p_: " << std::hex << static_cast(pv.p_) << std::dec; +std::ostream& operator<<(std::ostream& os, const PayloadValue& pv) { + os << "{p_: " << std::hex << static_cast(pv.p_) << std::dec; if (pv.p_) { - const auto *header = pv.header(); + const auto* header = pv.header(); os << ", refcount: " << header->refcount.load(std::memory_order_relaxed) << ", cap: " << header->cap << ", lsn: " << header->lsn << ", [" << std::hex; - const uint8_t *ptr = pv.Ptr(); + const uint8_t* ptr = pv.Ptr(); const size_t cap = header->cap; for (size_t i = 0; i < cap; ++i) { - if (i != 0) os << ' '; + if (i != 0) { + os << ' '; + } os << static_cast(ptr[i]); } os << std::dec << "], tuple: "; assertrx(cap >= sizeof(p_string)); - const p_string &str = *reinterpret_cast(ptr); + const p_string& str = *reinterpret_cast(ptr); str.Dump(os); } return os << '}'; diff --git a/cpp_src/core/payload/payloadvalue.h b/cpp_src/core/payload/payloadvalue.h index 87772037b..33a0a59d0 100644 --- a/cpp_src/core/payload/payloadvalue.h +++ b/cpp_src/core/payload/payloadvalue.h @@ -21,24 +21,26 @@ class PayloadValue { }; PayloadValue() noexcept : p_(nullptr) {} - PayloadValue(const PayloadValue &other) noexcept : p_(other.p_) { + PayloadValue(const PayloadValue& other) noexcept : p_(other.p_) { if (p_) { header()->refcount.fetch_add(1, std::memory_order_relaxed); } } // Alloc payload store with size, and copy data from another array - PayloadValue(size_t size, const uint8_t *ptr = nullptr, size_t cap = 0); + PayloadValue(size_t size, const uint8_t* ptr = nullptr, size_t cap = 0); ~PayloadValue() { release(); } - PayloadValue &operator=(const PayloadValue &other) noexcept { + PayloadValue& operator=(const PayloadValue& other) noexcept { if (&other != this) { release(); p_ = other.p_; - if (p_) header()->refcount.fetch_add(1, std::memory_order_relaxed); + if (p_) { + header()->refcount.fetch_add(1, std::memory_order_relaxed); + } } return *this; } - PayloadValue(PayloadValue &&other) noexcept : p_(other.p_) { other.p_ = nullptr; } - PayloadValue &operator=(PayloadValue &&other) noexcept { + PayloadValue(PayloadValue&& other) noexcept : p_(other.p_) { other.p_ = nullptr; } + PayloadValue& operator=(PayloadValue&& other) noexcept { if (&other != this) { release(); p_ = other.p_; @@ -53,23 +55,23 @@ class PayloadValue { // Resize void Resize(size_t oldSize, size_t newSize); // Get data pointer - uint8_t *Ptr() const noexcept { return p_ + sizeof(dataHeader); } + uint8_t* Ptr() const noexcept { return p_ + sizeof(dataHeader); } void SetLSN(int64_t lsn) noexcept { header()->lsn = lsn; } int64_t GetLSN() const noexcept { return p_ ? header()->lsn : 0; } bool IsFree() const noexcept { return bool(p_ == nullptr); } void Free() noexcept { release(); } size_t GetCapacity() const noexcept { return header()->cap; } - const uint8_t *get() const noexcept { return p_; } + const uint8_t* get() const noexcept { return p_; } protected: - uint8_t *alloc(size_t cap); + uint8_t* alloc(size_t cap); void release() noexcept; - dataHeader *header() noexcept { return reinterpret_cast(p_); } - const dataHeader *header() const noexcept { return reinterpret_cast(p_); } - friend std::ostream &operator<<(std::ostream &os, const PayloadValue &); + dataHeader* header() noexcept { return reinterpret_cast(p_); } + const dataHeader* header() const noexcept { return reinterpret_cast(p_); } + friend std::ostream& operator<<(std::ostream& os, const PayloadValue&); // Data of elements, shared - uint8_t *p_; + uint8_t* p_; }; } // namespace reindexer diff --git a/cpp_src/core/perfstatcounter.cc b/cpp_src/core/perfstatcounter.cc index 41b58afc9..56547fea5 100644 --- a/cpp_src/core/perfstatcounter.cc +++ b/cpp_src/core/perfstatcounter.cc @@ -80,7 +80,9 @@ template void PerfStatCounter::lap() { auto now = system_clock_w::now(); std::chrono::microseconds elapsed = std::chrono::duration_cast(now - calcStartTime); - if (elapsed < std::chrono::microseconds(1000000)) return; + if (elapsed < std::chrono::microseconds(1000000)) { + return; + } avgHitCount = calcHitCount; avgTime = calcTime; calcTime = std::chrono::microseconds(0); diff --git a/cpp_src/core/perfstatcounter.h b/cpp_src/core/perfstatcounter.h index b26de1b47..d8fbfce37 100644 --- a/cpp_src/core/perfstatcounter.h +++ b/cpp_src/core/perfstatcounter.h @@ -64,15 +64,21 @@ using PerfStatCounterST = PerfStatCounter; template class PerfStatCalculator { public: - PerfStatCalculator(PerfStatCounter &counter, bool enable) noexcept : counter_(&counter), enable_(enable) { - if (enable_) tmStart = system_clock_w::now(); + PerfStatCalculator(PerfStatCounter& counter, bool enable) noexcept : counter_(&counter), enable_(enable) { + if (enable_) { + tmStart = system_clock_w::now(); + } } ~PerfStatCalculator() { - if (enable_) counter_->Hit(std::chrono::duration_cast(system_clock_w::now() - tmStart)); + if (enable_) { + counter_->Hit(std::chrono::duration_cast(system_clock_w::now() - tmStart)); + } } - void SetCounter(PerfStatCounter &counter) { counter_ = &counter; } + void SetCounter(PerfStatCounter& counter) { counter_ = &counter; } void LockHit() { - if (enable_) counter_->LockHit(std::chrono::duration_cast(system_clock_w::now() - tmStart)); + if (enable_) { + counter_->LockHit(std::chrono::duration_cast(system_clock_w::now() - tmStart)); + } } void HitManualy() { if (enable_) { @@ -82,7 +88,7 @@ class PerfStatCalculator { } system_clock_w::time_point tmStart; - PerfStatCounter *counter_; + PerfStatCounter* counter_; bool enable_; }; using PerfStatCalculatorMT = PerfStatCalculator; diff --git a/cpp_src/core/query/dsl/dslencoder.cc b/cpp_src/core/query/dsl/dslencoder.cc index 65662a9d4..82290d4ee 100644 --- a/cpp_src/core/query/dsl/dslencoder.cc +++ b/cpp_src/core/query/dsl/dslencoder.cc @@ -37,9 +37,11 @@ constexpr static auto kReqTotalValues = frozen::make_unordered_map -std::string_view get(frozen::unordered_map const& m, const T& key) { +std::string_view get(const frozen::unordered_map& m, const T& key) { auto it = m.find(key); - if (it != m.end()) return it->second; + if (it != m.end()) { + return it->second; + } assertrx(it != m.end()); return std::string_view(); } @@ -64,13 +66,17 @@ static void encodeJoins(const Query& query, JsonBuilder& builder) { } static void encodeEqualPositions(const EqualPositions_t& equalPositions, JsonBuilder& builder) { - if (equalPositions.empty()) return; + if (equalPositions.empty()) { + return; + } auto node = builder.Object(); auto epNodePositions = node.Array("equal_positions"); for (const auto& eqPos : equalPositions) { auto epNodePosition = epNodePositions.Object(std::string_view()); auto epNodePositionArr = epNodePosition.Array("positions"); - for (const auto& field : eqPos) epNodePositionArr.Put(nullptr, field); + for (const auto& field : eqPos) { + epNodePositionArr.Put(nullptr, field); + } } } @@ -94,12 +100,16 @@ static void encodeMergedQueries(const Query& query, JsonBuilder& builder) { static void encodeSelectFilter(const Query& query, JsonBuilder& builder) { auto arrNode = builder.Array("select_filter"); - for (auto& str : query.SelectFilters()) arrNode.Put(nullptr, str); + for (auto& str : query.SelectFilters()) { + arrNode.Put(nullptr, str); + } } static void encodeSelectFunctions(const Query& query, JsonBuilder& builder) { auto arrNode = builder.Array("select_functions"); - for (auto& str : query.selectFunctions_) arrNode.Put(nullptr, str); + for (auto& str : query.selectFunctions_) { + arrNode.Put(nullptr, str); + } } static void encodeAggregationFunctions(const Query& query, JsonBuilder& builder) { @@ -123,8 +133,12 @@ static void encodeAggregationFunctions(const Query& query, JsonBuilder& builder) break; } - if (entry.Limit() != QueryEntry::kDefaultLimit) aggNode.Put("limit", entry.Limit()); - if (entry.Offset() != QueryEntry::kDefaultOffset) aggNode.Put("offset", entry.Offset()); + if (entry.Limit() != QueryEntry::kDefaultLimit) { + aggNode.Put("limit", entry.Limit()); + } + if (entry.Offset() != QueryEntry::kDefaultOffset) { + aggNode.Put("offset", entry.Offset()); + } auto fldNode = aggNode.Array("fields"); for (const auto& field : entry.Fields()) { fldNode.Put(nullptr, field); @@ -179,7 +193,9 @@ static void putValues(JsonBuilder& builder, const VariantArray& values) { } static void encodeFilter(const QueryEntry& qentry, JsonBuilder& builder) { - if (qentry.Distinct()) return; + if (qentry.Distinct()) { + return; + } builder.Put("cond", get(kCondMap, CondType(qentry.Condition()))); builder.Put("field", qentry.FieldName()); putValues(builder, qentry.Values()); @@ -258,10 +274,14 @@ void toDsl(const Query& query, QueryScope scope, JsonBuilder& builder) { bool withDropEntries = false, withUpdateEntries = false; for (const UpdateEntry& updateEntry : query.UpdateFields()) { if (updateEntry.Mode() == FieldModeDrop) { - if (!withDropEntries) withDropEntries = true; + if (!withDropEntries) { + withDropEntries = true; + } } if (updateEntry.Mode() == FieldModeSet || updateEntry.Mode() == FieldModeSetJson) { - if (!withUpdateEntries) withUpdateEntries = true; + if (!withUpdateEntries) { + withUpdateEntries = true; + } } } if (withDropEntries) { @@ -333,7 +353,9 @@ void QueryEntries::toDsl(const_iterator it, const_iterator to, const Query& pare dsl::encodeEqualPositions(bracket.equalPositions, arrNode); }, [&node](const QueryEntry& qe) { - if (qe.Distinct()) return; + if (qe.Distinct()) { + return; + } dsl::encodeFilter(qe, node); }, [&node, &parentQuery](const JoinQueryEntry& jqe) { diff --git a/cpp_src/core/query/dsl/dslparser.cc b/cpp_src/core/query/dsl/dslparser.cc index 18aa54a39..05a0b7ce4 100644 --- a/cpp_src/core/query/dsl/dslparser.cc +++ b/cpp_src/core/query/dsl/dslparser.cc @@ -45,7 +45,7 @@ enum class UpdateField { Name, Type, Values, IsArray }; enum class UpdateFieldType { Object, Expression, Value }; template -constexpr auto MakeFastStrMap(std::pair const (&items)[N]) { +constexpr auto MakeFastStrMap(const std::pair (&items)[N]) { return frozen::make_unordered_map(items, frozen::nocase_hash_str{}, frozen::nocase_equal_str{}); } @@ -177,11 +177,13 @@ bool checkTag(const JsonValue& val, JsonTag tag, Tags... tags) noexcept { template void checkJsonValueType(const JsonValue& val, std::string_view name, JsonTags... possibleTags) { - if (!checkTag(val, possibleTags...)) throw Error(errParseJson, "Wrong type of field '%s'", name); + if (!checkTag(val, possibleTags...)) { + throw Error(errParseJson, "Wrong type of field '%s'", name); + } } template -T get(frozen::unordered_map const& m, std::string_view name, +T get(const frozen::unordered_map& m, std::string_view name, std::string_view mapName) { auto it = m.find(name); if (it == m.end()) { @@ -235,7 +237,9 @@ static void parseSortEntry(const JsonValue& entry, SortingEntries& sortingEntrie std::string_view name = subelement.key; switch (get(kSortMap, name, "sort"sv)) { case Sort::Desc: - if ((v.getTag() != JSON_TRUE) && (v.getTag() != JSON_FALSE)) throw Error(errParseJson, "Wrong type of field '%s'", name); + if ((v.getTag() != JSON_TRUE) && (v.getTag() != JSON_FALSE)) { + throw Error(errParseJson, "Wrong type of field '%s'", name); + } sortingEntry.desc = (v.getTag() == JSON_TRUE); break; @@ -259,7 +263,9 @@ static void parseSortEntry(const JsonValue& entry, SortingEntries& sortingEntrie static void parseSort(const JsonValue& v, SortingEntries& sortingEntries, std::vector& forcedSortOrder) { if (v.getTag() == JSON_ARRAY) { - for (auto entry : v) parseSort(entry.value, sortingEntries, forcedSortOrder); + for (auto entry : v) { + parseSort(entry.value, sortingEntries, forcedSortOrder); + } } else if (v.getTag() == JSON_OBJECT) { parseSortEntry(v, sortingEntries, forcedSortOrder); } else { @@ -326,7 +332,9 @@ static void parseFilter(const JsonValue& filter, Query& q, std::vector())) + if (isExpression && (values.size() != 1 || !values.front().Type().template Is())) { throw Error(errParseDSL, R"(The array "values" must contain only a string type value for the type "expression")"); + } if (isObject) { query.SetObject(fieldName, std::move(values)); @@ -645,7 +660,9 @@ void parse(const JsonValue& root, Query& q) { case Root::Filters: checkJsonValueType(v, name, JSON_ARRAY); - for (const auto& filter : v) parseFilter(filter.value, q, equalPositions, 0); + for (const auto& filter : v) { + parseFilter(filter.value, q, equalPositions, 0); + } break; case Root::Sort: @@ -675,7 +692,9 @@ void parse(const JsonValue& root, Query& q) { break; case Root::Aggregations: checkJsonValueType(v, name, JSON_ARRAY); - for (const auto& aggregation : v) parseAggregation(aggregation.value, q); + for (const auto& aggregation : v) { + parseAggregation(aggregation.value, q); + } break; case Root::Explain: checkJsonValueType(v, name, JSON_FALSE, JSON_TRUE); @@ -683,7 +702,9 @@ void parse(const JsonValue& root, Query& q) { break; case Root::WithRank: checkJsonValueType(v, name, JSON_FALSE, JSON_TRUE); - if (v.getTag() == JSON_TRUE) q.WithRank(); + if (v.getTag() == JSON_TRUE) { + q.WithRank(); + } break; case Root::StrictMode: checkJsonValueType(v, name, JSON_STRING); @@ -729,7 +750,9 @@ Error Parse(std::string_view str, Query& q) { gason::JsonParser parser; auto root = parser.Parse(str); Error err = schemaChecker.Check(root); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } dsl::parse(root.value, q); } catch (const gason::Exception& ex) { return Error(errParseJson, "Query: %s", ex.what()); diff --git a/cpp_src/core/query/expressionevaluator.cc b/cpp_src/core/query/expressionevaluator.cc index a4b8d3a77..9dff39ede 100644 --- a/cpp_src/core/query/expressionevaluator.cc +++ b/cpp_src/core/query/expressionevaluator.cc @@ -29,7 +29,7 @@ void ExpressionEvaluator::captureArrayContent(tokenizer& parser) { if rx_unlikely (tok.text() == "]"sv) { throw Error(errParseSQL, "Expected field value, but found ']' in query, %s", parser.where()); } - arrayValues_.emplace_back(token2kv(tok, parser, false)); + arrayValues_.emplace_back(token2kv(tok, parser, CompositeAllowed::No, FieldAllowed::No)); tok = parser.next_token(tokenizer::flags::no_flags); if (tok.text() == "]"sv) { break; @@ -48,7 +48,7 @@ void ExpressionEvaluator::throwUnexpectedTokenError(tokenizer& parser, const tok } ExpressionEvaluator::PrimaryToken ExpressionEvaluator::getPrimaryToken(tokenizer& parser, const PayloadValue& v, StringAllowed strAllowed, - token& outTok) { + NonIntegralAllowed nonIntAllowed, token& outTok) { outTok = parser.next_token(); if (outTok.text() == "("sv) { const double val = performSumAndSubtracting(parser, v); @@ -73,11 +73,11 @@ ExpressionEvaluator::PrimaryToken ExpressionEvaluator::getPrimaryToken(tokenizer } } case TokenName: - return handleTokenName(parser, v, outTok); + return handleTokenName(parser, v, nonIntAllowed, outTok); case TokenString: if (strAllowed == StringAllowed::Yes) { arrayValues_.MarkArray(); - arrayValues_.emplace_back(token2kv(outTok, parser, false)); + arrayValues_.emplace_back(token2kv(outTok, parser, CompositeAllowed::No, FieldAllowed::No)); return {.value = std::nullopt, .type = PrimaryToken::Type::Array}; } else { throwUnexpectedTokenError(parser, outTok); @@ -91,7 +91,8 @@ ExpressionEvaluator::PrimaryToken ExpressionEvaluator::getPrimaryToken(tokenizer throw Error(errParams, "Unexpected token in expression: '%s'", outTok.text()); } -ExpressionEvaluator::PrimaryToken ExpressionEvaluator::handleTokenName(tokenizer& parser, const PayloadValue& v, token& outTok) { +ExpressionEvaluator::PrimaryToken ExpressionEvaluator::handleTokenName(tokenizer& parser, const PayloadValue& v, + NonIntegralAllowed nonIntAllowed, token& outTok) { int field = 0; VariantArray fieldValues; ConstPayload pv(type_, v); @@ -109,7 +110,7 @@ ExpressionEvaluator::PrimaryToken ExpressionEvaluator::handleTokenName(tokenizer return {.value = arrayValues_.back().As(), .type = PrimaryToken::Type::Array}; }, [&, this](OneOf) -> PrimaryToken { - if rx_unlikely (state_ != StateArrayConcat && + if rx_unlikely (nonIntAllowed == NonIntegralAllowed::No && state_ != StateArrayConcat && parser.peek_token(tokenizer::flags::treat_sign_as_token).text() != "|"sv) { throw Error(errParams, kWrongFieldTypeError, outTok.text()); } @@ -140,7 +141,11 @@ ExpressionEvaluator::PrimaryToken ExpressionEvaluator::handleTokenName(tokenizer return {.value = double((outTok.text() == "array_remove"sv) ? Command::ArrayRemove : Command::ArrayRemoveOnce), .type = PrimaryToken::Type::Command}; } else if rx_unlikely (outTok.text() == "true"sv || outTok.text() == "false"sv) { - throwUnexpectedTokenError(parser, outTok); + if rx_unlikely (nonIntAllowed == NonIntegralAllowed::No) { + throwUnexpectedTokenError(parser, outTok); + } + arrayValues_.emplace_back(outTok.text() == "true"sv); + return {.value = std::nullopt, .type = PrimaryToken::Type::Null}; } pv.GetByJsonPath(outTok.text(), tagsMatcher_, fieldValues, KeyValueType::Undefined{}); @@ -200,7 +205,7 @@ void ExpressionEvaluator::handleCommand(tokenizer& parser, const PayloadValue& v VariantArray resultArr; token valueToken; - auto trr = getPrimaryToken(parser, v, StringAllowed::No, valueToken); + auto trr = getPrimaryToken(parser, v, StringAllowed::No, NonIntegralAllowed::Yes, valueToken); if rx_unlikely (trr.type != PrimaryToken::Type::Null) { if rx_unlikely (trr.type != PrimaryToken::Type::Array) { throw Error(errParams, "Only an array field is expected as first parameter of command 'array_remove_once/array_remove'"); @@ -217,7 +222,7 @@ void ExpressionEvaluator::handleCommand(tokenizer& parser, const PayloadValue& v } // parse list of delete items - auto val = getPrimaryToken(parser, v, StringAllowed::Yes, valueToken); + auto val = getPrimaryToken(parser, v, StringAllowed::Yes, NonIntegralAllowed::Yes, valueToken); if rx_unlikely (val.type != PrimaryToken::Type::Null) { if ((val.type != PrimaryToken::Type::Array) && (val.type != PrimaryToken::Type::Scalar)) { throw Error(errParams, "Expecting array or scalar as command parameter: '%s'", valueToken.text()); @@ -257,7 +262,7 @@ void ExpressionEvaluator::handleCommand(tokenizer& parser, const PayloadValue& v double ExpressionEvaluator::performArrayConcatenation(tokenizer& parser, const PayloadValue& v, token& tok) { token valueToken; - auto left = getPrimaryToken(parser, v, StringAllowed::No, valueToken); + auto left = getPrimaryToken(parser, v, StringAllowed::No, NonIntegralAllowed::No, valueToken); tok = parser.peek_token(); switch (left.type) { case PrimaryToken::Type::Scalar: @@ -291,7 +296,7 @@ double ExpressionEvaluator::performArrayConcatenation(tokenizer& parser, const P throw Error(errParams, "Unable to mix arrays concatenation and arithmetic operations. Got token: '%s'", tok.text()); } state_ = StateArrayConcat; - auto right = getPrimaryToken(parser, v, StringAllowed::No, valueToken); + auto right = getPrimaryToken(parser, v, StringAllowed::No, NonIntegralAllowed::No, valueToken); if rx_unlikely (right.type == PrimaryToken::Type::Scalar) { throw Error(errParams, kScalarsInConcatenationError, valueToken.text()); } @@ -320,7 +325,9 @@ double ExpressionEvaluator::performMultiplicationAndDivision(tokenizer& parser, // tok.text() == "/"sv parser.next_token(tokenizer::flags::treat_sign_as_token); const double val = performMultiplicationAndDivision(parser, v, tok); - if (val == 0) throw Error(errLogic, "Division by zero!"); + if (val == 0) { + throw Error(errLogic, "Division by zero!"); + } left /= val; } } diff --git a/cpp_src/core/query/expressionevaluator.h b/cpp_src/core/query/expressionevaluator.h index 72fafe67d..4d60c0bf0 100644 --- a/cpp_src/core/query/expressionevaluator.h +++ b/cpp_src/core/query/expressionevaluator.h @@ -26,8 +26,10 @@ class ExpressionEvaluator { }; enum class StringAllowed : bool { No = false, Yes = true }; - [[nodiscard]] PrimaryToken getPrimaryToken(tokenizer& parser, const PayloadValue& v, StringAllowed strAllowed, token& outTok); - [[nodiscard]] PrimaryToken handleTokenName(tokenizer& parser, const PayloadValue& v, token& outTok); + enum class NonIntegralAllowed : bool { No = false, Yes = true }; + [[nodiscard]] PrimaryToken getPrimaryToken(tokenizer& parser, const PayloadValue& v, StringAllowed strAllowed, + NonIntegralAllowed nonIntAllowed, token& outTok); + [[nodiscard]] PrimaryToken handleTokenName(tokenizer& parser, const PayloadValue& v, NonIntegralAllowed nonIntAllowed, token& outTok); [[nodiscard]] double performSumAndSubtracting(tokenizer& parser, const PayloadValue& v); [[nodiscard]] double performMultiplicationAndDivision(tokenizer& parser, const PayloadValue& v, token& lastTok); [[nodiscard]] double performArrayConcatenation(tokenizer& parser, const PayloadValue& v, token& lastTok); diff --git a/cpp_src/core/query/query.cc b/cpp_src/core/query/query.cc index 00a0297fd..90f61590a 100644 --- a/cpp_src/core/query/query.cc +++ b/cpp_src/core/query/query.cc @@ -93,7 +93,7 @@ void Query::VerifyForUpdate() const { } } -bool Query::operator==(const Query &obj) const { +bool Query::operator==(const Query& obj) const { if (entries_ != obj.entries_ || aggregations_ != obj.aggregations_ || NsName() != obj.NsName() || sortingEntries_ != obj.sortingEntries_ || CalcTotal() != obj.CalcTotal() || Offset() != obj.Offset() || @@ -110,9 +110,13 @@ bool Query::operator==(const Query &obj) const { return true; } -bool JoinedQuery::operator==(const JoinedQuery &obj) const { - if (joinEntries_ != obj.joinEntries_) return false; - if (joinType != obj.joinType) return false; +bool JoinedQuery::operator==(const JoinedQuery& obj) const { + if (joinEntries_ != obj.joinEntries_) { + return false; + } + if (joinType != obj.joinType) { + return false; + } return Query::operator==(obj); } Query Query::FromSQL(std::string_view q) { return SQLParser::Parse(q); } @@ -121,8 +125,8 @@ Error Query::FromJSON(std::string_view dsl) { return dsl::Parse(dsl, *this); } std::string Query::GetJSON() const { return dsl::toDsl(*this); } -WrSerializer &Query::GetSQL(WrSerializer &ser, bool stripArgs) const { return SQLEncoder(*this).GetSQL(ser, stripArgs); } -WrSerializer &Query::GetSQL(WrSerializer &ser, QueryType realType, bool stripArgs) const { +WrSerializer& Query::GetSQL(WrSerializer& ser, bool stripArgs) const { return SQLEncoder(*this).GetSQL(ser, stripArgs); } +WrSerializer& Query::GetSQL(WrSerializer& ser, QueryType realType, bool stripArgs) const { return SQLEncoder(*this, realType).GetSQL(ser, stripArgs); } @@ -136,7 +140,7 @@ std::string Query::GetSQL(QueryType realType) const { return std::string(SQLEncoder(*this, realType).GetSQL(ser, false).Slice()); } -void Query::Join(JoinedQuery &&jq) & { +void Query::Join(JoinedQuery&& jq) & { switch (jq.joinType) { case JoinType::Merge: if (nextOp_ != OpAnd) { @@ -164,7 +168,7 @@ void Query::Join(JoinedQuery &&jq) & { adoptNested(joinQueries_.back()); } -VariantArray Query::deserializeValues(Serializer &ser, CondType cond) { +VariantArray Query::deserializeValues(Serializer& ser, CondType cond) { VariantArray values; auto cnt = ser.GetVarUint(); if (cond == CondDWithin) { @@ -180,12 +184,14 @@ VariantArray Query::deserializeValues(Serializer &ser, CondType cond) { values.emplace_back(ser.GetVariant().EnsureHold()); } else { values.reserve(cnt); - while (cnt--) values.emplace_back(ser.GetVariant().EnsureHold()); + while (cnt--) { + values.emplace_back(ser.GetVariant().EnsureHold()); + } } return values; } -void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { +void Query::deserialize(Serializer& ser, bool& hasJoinConditions) { bool end = false; std::vector> equalPositions; while (!end && !ser.Eof()) { @@ -231,11 +237,13 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { size_t fieldsCount = ser.GetVarUint(); h_vector fields; fields.reserve(fieldsCount); - while (fieldsCount--) fields.emplace_back(std::string(ser.GetVString())); + while (fieldsCount--) { + fields.emplace_back(std::string(ser.GetVString())); + } auto pos = ser.Pos(); bool aggEnd = false; aggregations_.emplace_back(type, std::move(fields)); - auto &ae = aggregations_.back(); + auto& ae = aggregations_.back(); while (!ser.Eof() && !aggEnd) { int atype = ser.GetVarUint(); switch (atype) { @@ -277,7 +285,9 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { throw Error(errParams, "Forced sort order is allowed for the first sorting entry only"); } forcedSortOrder_.reserve(cnt); - while (cnt--) forcedSortOrder_.push_back(ser.GetVariant().EnsureHold()); + while (cnt--) { + forcedSortOrder_.push_back(ser.GetVariant().EnsureHold()); + } break; } case QueryJoinOn: { @@ -285,8 +295,8 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { const CondType condition = static_cast(ser.GetVarUint()); std::string leftFieldName{ser.GetVString()}; std::string rightFieldName{ser.GetVString()}; - reinterpret_cast(this)->joinEntries_.emplace_back(op, condition, std::move(leftFieldName), - std::move(rightFieldName)); + reinterpret_cast(this)->joinEntries_.emplace_back(op, condition, std::move(leftFieldName), + std::move(rightFieldName)); break; } case QueryDebugLevel: @@ -311,7 +321,9 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { const unsigned bracketPosition = ser.GetVarUint(); const unsigned fieldsCount = ser.GetVarUint(); equalPositions.emplace_back(bracketPosition, fieldsCount); - for (auto &field : equalPositions.back().second) field = ser.GetVString(); + for (auto& field : equalPositions.back().second) { + field = ser.GetVString(); + } break; } case QueryExplain: @@ -402,7 +414,7 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { throw Error(errParseBin, "Unknown type %d while parsing binary buffer", qtype); } } - for (auto &&eqPos : equalPositions) { + for (auto&& eqPos : equalPositions) { if (eqPos.first == 0) { entries_.equalPositions.emplace_back(std::move(eqPos.second)); } else { @@ -412,19 +424,19 @@ void Query::deserialize(Serializer &ser, bool &hasJoinConditions) { return; } -void Query::Serialize(WrSerializer &ser, uint8_t mode) const { +void Query::Serialize(WrSerializer& ser, uint8_t mode) const { ser.PutVString(NsName()); entries_.Serialize(ser, subQueries_); if (!(mode & SkipAggregations)) { - for (const auto &agg : aggregations_) { + for (const auto& agg : aggregations_) { ser.PutVarUint(QueryAggregation); ser.PutVarUint(agg.Type()); ser.PutVarUint(agg.Fields().size()); - for (const auto &field : agg.Fields()) { + for (const auto& field : agg.Fields()) { ser.PutVString(field); } - for (const auto &se : agg.Sorting()) { + for (const auto& se : agg.Sorting()) { ser.PutVarUint(QueryAggregationSort); ser.PutVString(se.expression); ser.PutVarUint(se.desc); @@ -441,18 +453,20 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { } if (!(mode & SkipSortEntries)) { - for (const auto &sortingEntry : sortingEntries_) { + for (const auto& sortingEntry : sortingEntries_) { ser.PutVarUint(QuerySortIndex); ser.PutVString(sortingEntry.expression); ser.PutVarUint(sortingEntry.desc); int cnt = forcedSortOrder_.size(); ser.PutVarUint(cnt); - for (auto &kv : forcedSortOrder_) ser.PutVariant(kv); + for (auto& kv : forcedSortOrder_) { + ser.PutVariant(kv); + } } } if (mode & WithJoinEntries) { - for (const auto &qje : reinterpret_cast(this)->joinEntries_) { + for (const auto& qje : reinterpret_cast(this)->joinEntries_) { ser.PutVarUint(QueryJoinOn); ser.PutVarUint(qje.Operation()); ser.PutVarUint(qje.Condition()); @@ -461,20 +475,24 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { } } - for (const auto &equalPoses : entries_.equalPositions) { + for (const auto& equalPoses : entries_.equalPositions) { ser.PutVarUint(QueryEqualPosition); ser.PutVarUint(0); ser.PutVarUint(equalPoses.size()); - for (const auto &ep : equalPoses) ser.PutVString(ep); + for (const auto& ep : equalPoses) { + ser.PutVString(ep); + } } for (size_t i = 0; i < entries_.Size(); ++i) { if (entries_.IsSubTree(i)) { - const auto &bracket = entries_.Get(i); - for (const auto &equalPoses : bracket.equalPositions) { + const auto& bracket = entries_.Get(i); + for (const auto& equalPoses : bracket.equalPositions) { ser.PutVarUint(QueryEqualPosition); ser.PutVarUint(i + 1); ser.PutVarUint(equalPoses.size()); - for (const auto &ep : equalPoses) ser.PutVString(ep); + for (const auto& ep : equalPoses) { + ser.PutVString(ep); + } } } } @@ -506,7 +524,7 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { ser.PutVarUint(CalcTotal()); } - for (const auto &sf : selectFilter_) { + for (const auto& sf : selectFilter_) { ser.PutVarUint(QuerySelectFilter); ser.PutVString(sf); } @@ -520,13 +538,13 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { } } - for (const auto &field : updateFields_) { + for (const auto& field : updateFields_) { if (field.Mode() == FieldModeSet) { ser.PutVarUint(QueryUpdateFieldV2); ser.PutVString(field.Column()); ser.PutVarUint(field.Values().IsArrayValue()); ser.PutVarUint(field.Values().size()); - for (const Variant &val : field.Values()) { + for (const Variant& val : field.Values()) { ser.PutVarUint(field.IsExpression()); ser.PutVariant(val); } @@ -541,7 +559,7 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { ser.PutVarUint(QueryEnd); // finita la commedia... of root query if (!(mode & SkipJoinQueries)) { - for (const auto &jq : joinQueries_) { + for (const auto& jq : joinQueries_) { if (!(mode & SkipLeftJoinQueries) || jq.joinType != JoinType::LeftJoin) { ser.PutVarUint(static_cast(jq.joinType)); jq.Serialize(ser, WithJoinEntries); @@ -550,14 +568,14 @@ void Query::Serialize(WrSerializer &ser, uint8_t mode) const { } if (!(mode & SkipMergeQueries)) { - for (const auto &mq : mergeQueries_) { + for (const auto& mq : mergeQueries_) { ser.PutVarUint(static_cast(mq.joinType)); mq.Serialize(ser, (mode | WithJoinEntries) & (~SkipSortEntries)); } } } -Query Query::Deserialize(Serializer &ser) { +Query Query::Deserialize(Serializer& ser) { Query res(ser.GetVString()); bool hasJoinConditions = false; res.deserialize(ser, hasJoinConditions); @@ -573,7 +591,7 @@ Query Query::Deserialize(Serializer &ser) { res.mergeQueries_.emplace_back(std::move(q1)); nested = true; } else { - Query &q = nested ? res.mergeQueries_.back() : res; + Query& q = nested ? res.mergeQueries_.back() : res; if (joinType != JoinType::LeftJoin && !hasJoinConditions) { const size_t joinIdx = res.joinQueries_.size(); res.entries_.Append((joinType == JoinType::OrInnerJoin) ? OpOr : OpAnd, joinIdx); @@ -585,38 +603,38 @@ Query Query::Deserialize(Serializer &ser) { return res; } -Query &Query::Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, Query &&qr) & { +Query& Query::Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, Query&& qr) & { auto jq = JoinedQuery{joinType, std::move(qr)}; jq.joinEntries_.emplace_back(op, cond, std::move(leftField), std::move(rightField)); Join(std::move(jq)); return *this; } -Query &Query::Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, const Query &qr) & { +Query& Query::Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, const Query& qr) & { auto jq = JoinedQuery{joinType, qr}; jq.joinEntries_.emplace_back(op, cond, std::move(leftField), std::move(rightField)); Join(std::move(jq)); return *this; } -Query &Query::Merge(const Query &q) & { +Query& Query::Merge(const Query& q) & { mergeQueries_.emplace_back(JoinType::Merge, q); adoptNested(mergeQueries_.back()); return *this; } -Query &Query::Merge(Query &&q) & { +Query& Query::Merge(Query&& q) & { mergeQueries_.emplace_back(JoinType::Merge, std::move(q)); adoptNested(mergeQueries_.back()); return *this; } -void Query::AddJoinQuery(JoinedQuery &&jq) { +void Query::AddJoinQuery(JoinedQuery&& jq) { adoptNested(jq); joinQueries_.emplace_back(std::move(jq)); } -Query &Query::SortStDistance(std::string_view field, Point p, bool desc) & { +Query& Query::SortStDistance(std::string_view field, Point p, bool desc) & { if (field.empty()) { throw Error(errParams, "Field name for ST_Distance can not be empty"); } @@ -624,7 +642,7 @@ Query &Query::SortStDistance(std::string_view field, Point p, bool desc) & { return *this; } -Query &Query::SortStDistance(std::string_view field1, std::string_view field2, bool desc) & { +Query& Query::SortStDistance(std::string_view field1, std::string_view field2, bool desc) & { if (field1.empty() || field2.empty()) { throw Error(errParams, "Fields names for ST_Distance can not be empty"); } @@ -633,48 +651,64 @@ Query &Query::SortStDistance(std::string_view field1, std::string_view field2, b } void Query::walkNested(bool withSelf, bool withMerged, bool withSubQueries, - const std::function &visitor) noexcept(noexcept(visitor(std::declval()))) { - if (withSelf) visitor(*this); + const std::function& visitor) noexcept(noexcept(visitor(std::declval()))) { + if (withSelf) { + visitor(*this); + } if (withMerged) { - for (auto &mq : mergeQueries_) visitor(mq); + for (auto& mq : mergeQueries_) { + visitor(mq); + } if (withSubQueries) { - for (auto &mq : mergeQueries_) { - for (auto &nq : mq.subQueries_) { + for (auto& mq : mergeQueries_) { + for (auto& nq : mq.subQueries_) { nq.walkNested(true, true, true, visitor); } } } } - for (auto &jq : joinQueries_) visitor(jq); - for (auto &mq : mergeQueries_) { - for (auto &jq : mq.joinQueries_) visitor(jq); + for (auto& jq : joinQueries_) { + visitor(jq); + } + for (auto& mq : mergeQueries_) { + for (auto& jq : mq.joinQueries_) { + visitor(jq); + } } if (withSubQueries) { - for (auto &nq : subQueries_) { + for (auto& nq : subQueries_) { nq.walkNested(true, withMerged, true, visitor); } } } -void Query::WalkNested(bool withSelf, bool withMerged, bool withSubQueries, const std::function &visitor) const +void Query::WalkNested(bool withSelf, bool withMerged, bool withSubQueries, const std::function& visitor) const noexcept(noexcept(visitor(std::declval()))) { - if (withSelf) visitor(*this); + if (withSelf) { + visitor(*this); + } if (withMerged) { - for (auto &mq : mergeQueries_) visitor(mq); + for (auto& mq : mergeQueries_) { + visitor(mq); + } if (withSubQueries) { - for (auto &mq : mergeQueries_) { - for (auto &nq : mq.subQueries_) { + for (auto& mq : mergeQueries_) { + for (auto& nq : mq.subQueries_) { nq.WalkNested(true, true, true, visitor); } } } } - for (auto &jq : joinQueries_) visitor(jq); - for (auto &mq : mergeQueries_) { - for (auto &jq : mq.joinQueries_) visitor(jq); + for (auto& jq : joinQueries_) { + visitor(jq); + } + for (auto& mq : mergeQueries_) { + for (auto& jq : mq.joinQueries_) { + visitor(jq); + } } if (withSubQueries) { - for (auto &nq : subQueries_) { + for (auto& nq : subQueries_) { nq.WalkNested(true, withMerged, true, visitor); } } @@ -684,8 +718,8 @@ bool Query::IsWALQuery() const noexcept { if (entries_.Size() == 1 && entries_.Is(0) && kLsnIndexName == entries_.Get(0).FieldName()) { return true; } else if (entries_.Size() == 2 && entries_.Is(0) && entries_.Is(1)) { - const auto &index0 = entries_.Get(0).FieldName(); - const auto &index1 = entries_.Get(1).FieldName(); + const auto& index0 = entries_.Get(0).FieldName(); + const auto& index1 = entries_.Get(1).FieldName(); return (kLsnIndexName == index0 && kSlaveVersionIndexName == index1) || (kLsnIndexName == index1 && kSlaveVersionIndexName == index0); } diff --git a/cpp_src/core/query/query.h b/cpp_src/core/query/query.h index c44c4f1af..12b6ed234 100644 --- a/cpp_src/core/query/query.h +++ b/cpp_src/core/query/query.h @@ -28,15 +28,15 @@ class Query { /// @param start - number of the first row to get from selected set. Analog to sql OFFSET Offset. /// @param count - number of rows to get from result set. Analog to sql LIMIT RowsCount. /// @param calcTotal - calculation mode. - template > * = nullptr> - explicit Query(Str &&nsName, unsigned start = QueryEntry::kDefaultOffset, unsigned count = QueryEntry::kDefaultLimit, + template >* = nullptr> + explicit Query(Str&& nsName, unsigned start = QueryEntry::kDefaultOffset, unsigned count = QueryEntry::kDefaultLimit, CalcTotalMode calcTotal = ModeNoTotal) : namespace_(std::forward(nsName)), start_(start), count_(count), calcTotal_(calcTotal) {} Query() = default; /// Allows to compare 2 Query objects. - [[nodiscard]] bool operator==(const Query &) const; + [[nodiscard]] bool operator==(const Query&) const; /// Parses pure sql select query and initializes Query object data members as a result. /// @param q - sql query. @@ -45,13 +45,13 @@ class Query { /// Logs query in 'Select field1, ... field N from namespace ...' format. /// @param ser - serializer to store SQL string /// @param stripArgs - replace condition values with '?' - WrSerializer &GetSQL(WrSerializer &ser, bool stripArgs = false) const; + WrSerializer& GetSQL(WrSerializer& ser, bool stripArgs = false) const; /// Logs query in 'Select field1, ... field N from namespace ...' format. /// @param ser - serializer to store SQL string /// @param realType - replaces original query's type /// @param stripArgs - replace condition values with '?' - WrSerializer &GetSQL(WrSerializer &ser, QueryType realType, bool stripArgs = false) const; + WrSerializer& GetSQL(WrSerializer& ser, QueryType realType, bool stripArgs = false) const; /// Logs query in 'Select field1, ... field N from namespace ...' format. /// @param stripArgs - replace condition values with '?' @@ -74,11 +74,11 @@ class Query { /// Enable explain query /// @param on - signaling on/off /// @return Query object ready to be executed - Query &Explain(bool on = true) & noexcept { - walkNested(true, true, true, [on](Query &q) noexcept { q.explain_ = on; }); + Query& Explain(bool on = true) & noexcept { + walkNested(true, true, true, [on](Query& q) noexcept { q.explain_ = on; }); return *this; } - [[nodiscard]] Query &&Explain(bool on = true) && noexcept { return std::move(Explain(on)); } + [[nodiscard]] Query&& Explain(bool on = true) && noexcept { return std::move(Explain(on)); } [[nodiscard]] bool NeedExplain() const noexcept { return explain_; } /// Adds a condition with a single value. Analog to sql Where clause. @@ -86,14 +86,14 @@ class Query { /// @param cond - type of condition. /// @param val - value of index to be compared with. /// @return Query object ready to be executed. - template > * = nullptr, - std::enable_if_t> * = nullptr> - Query &Where(Str &&field, CondType cond, Input &&val) & { + template >* = nullptr, + std::enable_if_t>* = nullptr> + Query& Where(Str&& field, CondType cond, Input&& val) & { return Where(std::forward(field), cond, VariantArray{Variant{std::forward(val)}}); } - template > * = nullptr, - std::enable_if_t> * = nullptr> - [[nodiscard]] Query &&Where(Str &&field, CondType cond, Input &&val) && { + template >* = nullptr, + std::enable_if_t>* = nullptr> + [[nodiscard]] Query&& Where(Str&& field, CondType cond, Input&& val) && { return std::move(Where(std::forward(field), cond, VariantArray{Variant{std::forward(val)}})); } @@ -102,17 +102,19 @@ class Query { /// @param cond - type of condition. /// @param l - list of index values to be compared with. /// @return Query object ready to be executed. - template > * = nullptr> - Query &Where(Str &&field, CondType cond, std::initializer_list l) & { + template >* = nullptr> + Query& Where(Str&& field, CondType cond, std::initializer_list l) & { VariantArray values; values.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) values.emplace_back(*it); + for (auto it = l.begin(); it != l.end(); it++) { + values.emplace_back(*it); + } entries_.Append(nextOp_, std::forward(field), cond, std::move(values)); nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Where(Str &&field, CondType cond, std::initializer_list l) && { + template >* = nullptr> + [[nodiscard]] Query&& Where(Str&& field, CondType cond, std::initializer_list l) && { return std::move(Where(std::forward(field), cond, std::move(l))); } @@ -121,17 +123,19 @@ class Query { /// @param cond - type of condition. /// @param l - vector of index values to be compared with. /// @return Query object ready to be executed. - template > * = nullptr> - Query &Where(Str &&field, CondType cond, const std::vector &l) & { + template >* = nullptr> + Query& Where(Str&& field, CondType cond, const std::vector& l) & { VariantArray values; values.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) values.emplace_back(*it); + for (auto it = l.begin(); it != l.end(); it++) { + values.emplace_back(*it); + } entries_.Append(nextOp_, std::forward(field), cond, std::move(values)); nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Where(Str &&field, CondType cond, const std::vector &l) && { + template >* = nullptr> + [[nodiscard]] Query&& Where(Str&& field, CondType cond, const std::vector& l) && { return std::move(Where(std::forward(field), cond, l)); } @@ -140,14 +144,14 @@ class Query { /// @param cond - type of condition. /// @param l - vector of index values to be compared with. /// @return Query object ready to be executed. - template > * = nullptr> - Query &Where(Str &&field, CondType cond, VariantArray l) & { + template >* = nullptr> + Query& Where(Str&& field, CondType cond, VariantArray l) & { entries_.Append(nextOp_, std::forward(field), cond, std::move(l)); nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Where(Str &&field, CondType cond, VariantArray l) && { + template >* = nullptr> + [[nodiscard]] Query&& Where(Str&& field, CondType cond, VariantArray l) && { return std::move(Where(std::forward(field), cond, std::move(l))); } @@ -162,8 +166,8 @@ class Query { /// in case of CondRange) belongs to "bookid" and l[0][1] (and l[1][1] in case of CondRange) /// belongs to "price" indexes. /// @return Query object ready to be executed. - template > * = nullptr> - Query &WhereComposite(Str &&idx, CondType cond, std::initializer_list l) & { + template >* = nullptr> + Query& WhereComposite(Str&& idx, CondType cond, std::initializer_list l) & { VariantArray values; values.reserve(l.size()); for (auto it = l.begin(); it != l.end(); it++) { @@ -173,12 +177,12 @@ class Query { nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&WhereComposite(Str &&idx, CondType cond, std::initializer_list l) && { + template >* = nullptr> + [[nodiscard]] Query&& WhereComposite(Str&& idx, CondType cond, std::initializer_list l) && { return std::move(WhereComposite(std::forward(idx), cond, std::move(l))); } - template > * = nullptr> - Query &WhereComposite(Str &&idx, CondType cond, const std::vector &v) & { + template >* = nullptr> + Query& WhereComposite(Str&& idx, CondType cond, const std::vector& v) & { VariantArray values; values.reserve(v.size()); for (auto it = v.begin(); it != v.end(); it++) { @@ -188,34 +192,34 @@ class Query { nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&WhereComposite(Str &&idx, CondType cond, const std::vector &v) && { + template >* = nullptr> + [[nodiscard]] Query&& WhereComposite(Str&& idx, CondType cond, const std::vector& v) && { return std::move(WhereComposite(std::forward(idx), cond, v)); } template - Query &WhereBetweenFields(Str1 &&firstIdx, CondType cond, Str2 &&secondIdx) & { + Query& WhereBetweenFields(Str1&& firstIdx, CondType cond, Str2&& secondIdx) & { entries_.Append(nextOp_, std::forward(firstIdx), cond, std::forward(secondIdx)); nextOp_ = OpAnd; return *this; } template - [[nodiscard]] Query &&WhereBetweenFields(Str1 &&firstIdx, CondType cond, Str2 &&secondIdx) && { + [[nodiscard]] Query&& WhereBetweenFields(Str1&& firstIdx, CondType cond, Str2&& secondIdx) && { return std::move(WhereBetweenFields(std::forward(firstIdx), cond, std::forward(secondIdx))); } - template > * = nullptr> - Query &DWithin(Str &&field, Point p, double distance) & { + template >* = nullptr> + Query& DWithin(Str&& field, Point p, double distance) & { entries_.Append(nextOp_, std::forward(field), CondDWithin, VariantArray::Create(p, distance)); nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&DWithin(Str &&field, Point p, double distance) && { + template >* = nullptr> + [[nodiscard]] Query&& DWithin(Str&& field, Point p, double distance) && { return std::move(DWithin(std::forward(field), p, distance)); } - Query &DWithin(Query &&q, Point p, double distance) & { return Where(std::move(q), CondDWithin, VariantArray::Create(p, distance)); } - [[nodiscard]] Query &&DWithin(Query &&q, Point p, double distance) && { return std::move(DWithin(std::move(q), p, distance)); } - Query &Where(Query &&q, CondType cond, VariantArray &&values) & { + Query& DWithin(Query&& q, Point p, double distance) & { return Where(std::move(q), CondDWithin, VariantArray::Create(p, distance)); } + [[nodiscard]] Query&& DWithin(Query&& q, Point p, double distance) && { return std::move(DWithin(std::move(q), p, distance)); } + Query& Where(Query&& q, CondType cond, VariantArray&& values) & { if (cond == CondEmpty || cond == CondAny) { q.checkSubQueryNoData(); q.Limit(0); @@ -241,28 +245,28 @@ class Query { nextOp_ = OpAnd; return *this; } - [[nodiscard]] Query &&Where(Query &&q, CondType cond, VariantArray &&values) && { + [[nodiscard]] Query&& Where(Query&& q, CondType cond, VariantArray&& values) && { return std::move(Where(std::move(q), cond, std::move(values))); } template - Query &Where(Query &&q, CondType cond, std::initializer_list values) & { + Query& Where(Query&& q, CondType cond, std::initializer_list values) & { return Where(std::move(q), cond, VariantArray::Create(values)); } template - [[nodiscard]] Query &&Where(Query &&q, CondType cond, std::initializer_list values) && { + [[nodiscard]] Query&& Where(Query&& q, CondType cond, std::initializer_list values) && { return std::move(Where(std::move(q), cond, VariantArray::Create(values))); } - template > * = nullptr> - [[nodiscard]] Query &Where(Query &&q, CondType cond, Input &&val) & { + template >* = nullptr> + [[nodiscard]] Query& Where(Query&& q, CondType cond, Input&& val) & { return Where(std::move(q), cond, VariantArray{Variant{std::forward(val)}}); } - template > * = nullptr> - [[nodiscard]] Query &&Where(Query &&q, CondType cond, Input &&val) && { + template >* = nullptr> + [[nodiscard]] Query&& Where(Query&& q, CondType cond, Input&& val) && { return std::move(Where(std::move(q), cond, VariantArray{Variant{std::forward(val)}})); } - template > * = nullptr> - Query &Where(Str &&field, CondType cond, Query &&q) & { + template >* = nullptr> + Query& Where(Str&& field, CondType cond, Query&& q) & { if (cond == CondDWithin) { throw Error(errQueryExec, "DWithin between field and subquery"); } @@ -280,8 +284,8 @@ class Query { nextOp_ = OpAnd; return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Where(Str &&field, CondType cond, Query &&q) && { + template >* = nullptr> + [[nodiscard]] Query&& Where(Str&& field, CondType cond, Query&& q) && { return std::move(Where(std::forward(field), cond, std::move(q))); } @@ -289,106 +293,114 @@ class Query { /// @param field - field name. /// @param value - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &Set(Str &&field, ValueType value, bool hasExpressions = false) & { + template >* = nullptr> + Query& Set(Str&& field, ValueType value, bool hasExpressions = false) & { return Set(std::forward(field), {value}, hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&Set(Str &&field, ValueType value, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& Set(Str&& field, ValueType value, bool hasExpressions = false) && { return std::move(Set(std::forward(field), std::move(value), hasExpressions)); } /// Sets a new value for a field. /// @param field - field name. /// @param l - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &Set(Str &&field, std::initializer_list l, bool hasExpressions = false) & { + template >* = nullptr> + Query& Set(Str&& field, std::initializer_list l, bool hasExpressions = false) & { VariantArray value; value.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) value.emplace_back(*it); + for (auto it = l.begin(); it != l.end(); it++) { + value.emplace_back(*it); + } return Set(std::forward(field), std::move(value), hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&Set(Str &&field, std::initializer_list l, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& Set(Str&& field, std::initializer_list l, bool hasExpressions = false) && { return std::move(Set(std::forward(field), std::move(l), hasExpressions)); } /// Sets a new value for a field. /// @param field - field name. /// @param l - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &Set(Str &&field, const std::vector &l, bool hasExpressions = false) & { + template >* = nullptr> + Query& Set(Str&& field, const std::vector& l, bool hasExpressions = false) & { VariantArray value; value.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) value.emplace_back(*it); + for (auto it = l.begin(); it != l.end(); it++) { + value.emplace_back(*it); + } return Set(std::forward(field), std::move(value.MarkArray()), hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&Set(Str &&field, const std::vector &l, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& Set(Str&& field, const std::vector& l, bool hasExpressions = false) && { return std::move(Set(std::forward(field), l, hasExpressions)); } /// Sets a new value for a field. /// @param field - field name. /// @param value - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &Set(Str &&field, VariantArray value, bool hasExpressions = false) & { + template >* = nullptr> + Query& Set(Str&& field, VariantArray value, bool hasExpressions = false) & { updateFields_.emplace_back(std::forward(field), std::move(value), FieldModeSet, hasExpressions); return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Set(Str &&field, VariantArray value, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& Set(Str&& field, VariantArray value, bool hasExpressions = false) && { return std::move(Set(std::forward(field), std::move(value), hasExpressions)); } /// Sets a value for a field as an object. /// @param field - field name. /// @param value - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &SetObject(Str &&field, ValueType value, bool hasExpressions = false) & { + template >* = nullptr> + Query& SetObject(Str&& field, ValueType value, bool hasExpressions = false) & { return SetObject(std::forward(field), {value}, hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&SetObject(Str &&field, ValueType value, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& SetObject(Str&& field, ValueType value, bool hasExpressions = false) && { return std::move(SetObject(std::forward(field), std::move(value), hasExpressions)); } /// Sets a new value for a field as an object. /// @param field - field name. /// @param l - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &SetObject(Str &&field, std::initializer_list l, bool hasExpressions = false) & { + template >* = nullptr> + Query& SetObject(Str&& field, std::initializer_list l, bool hasExpressions = false) & { VariantArray value; value.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) value.emplace_back(*it); + for (auto it = l.begin(); it != l.end(); it++) { + value.emplace_back(*it); + } return SetObject(std::forward(field), std::move(value), hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&SetObject(Str &&field, std::initializer_list l, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& SetObject(Str&& field, std::initializer_list l, bool hasExpressions = false) && { return std::move(SetObject(std::forward(field), std::move(l), hasExpressions)); } /// Sets a new value for a field as an object. /// @param field - field name. /// @param l - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &SetObject(Str &&field, const std::vector &l, bool hasExpressions = false) & { + template >* = nullptr> + Query& SetObject(Str&& field, const std::vector& l, bool hasExpressions = false) & { VariantArray value; value.reserve(l.size()); - for (auto it = l.begin(); it != l.end(); it++) value.emplace_back(Variant(*it)); + for (auto it = l.begin(); it != l.end(); it++) { + value.emplace_back(Variant(*it)); + } return SetObject(std::forward(field), std::move(value.MarkArray()), hasExpressions); } - template > * = nullptr> - [[nodiscard]] Query &&SetObject(Str &&field, const std::vector &l, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& SetObject(Str&& field, const std::vector& l, bool hasExpressions = false) && { return std::move(SetObject(std::forward(field), l, hasExpressions)); } /// Sets a value for a field as an object. /// @param field - field name. /// @param value - new value. /// @param hasExpressions - true: value has expressions in it - template > * = nullptr> - Query &SetObject(Str &&field, VariantArray value, bool hasExpressions = false) & { - for (auto &it : value) { + template >* = nullptr> + Query& SetObject(Str&& field, VariantArray value, bool hasExpressions = false) & { + for (auto& it : value) { if (!it.Type().Is()) { throw Error(errLogic, "Unexpected variant type in SetObject: %s. Expecting KeyValueType::String with JSON-content", it.Type().Name()); @@ -397,56 +409,56 @@ class Query { updateFields_.emplace_back(std::forward(field), std::move(value), FieldModeSetJson, hasExpressions); return *this; } - template > * = nullptr> - [[nodiscard]] Query &&SetObject(Str &&field, VariantArray value, bool hasExpressions = false) && { + template >* = nullptr> + [[nodiscard]] Query&& SetObject(Str&& field, VariantArray value, bool hasExpressions = false) && { return std::move(SetObject(std::forward(field), std::move(value), hasExpressions)); } /// Drops a value for a field. /// @param field - field name. - template > * = nullptr> - Query &Drop(Str &&field) & { + template >* = nullptr> + Query& Drop(Str&& field) & { updateFields_.emplace_back(std::forward(field), VariantArray(), FieldModeDrop); return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Drop(Str &&field) && { + template >* = nullptr> + [[nodiscard]] Query&& Drop(Str&& field) && { return std::move(Drop(std::forward(field))); } /// Add sql-function to query. /// @param function - function declaration. - template > * = nullptr> - void AddFunction(Str &&function) { + template >* = nullptr> + void AddFunction(Str&& function) { selectFunctions_.emplace_back(std::forward(function)); } /// Adds equal position fields to arrays queries. /// @param equalPosition - list of fields with equal array index position. - Query &AddEqualPosition(h_vector equalPosition) & { - auto *const bracket = entries_.LastOpenBracket(); - auto &eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); + Query& AddEqualPosition(h_vector equalPosition) & { + auto* const bracket = entries_.LastOpenBracket(); + auto& eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); eqPos.emplace_back(std::make_move_iterator(equalPosition.begin()), std::make_move_iterator(equalPosition.end())); return *this; } - Query &AddEqualPosition(std::vector equalPosition) & { - auto *const bracket = entries_.LastOpenBracket(); - auto &eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); + Query& AddEqualPosition(std::vector equalPosition) & { + auto* const bracket = entries_.LastOpenBracket(); + auto& eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); eqPos.emplace_back(std::make_move_iterator(equalPosition.begin()), std::make_move_iterator(equalPosition.end())); return *this; } - Query &AddEqualPosition(std::initializer_list l) & { - auto *const bracket = entries_.LastOpenBracket(); - auto &eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); + Query& AddEqualPosition(std::initializer_list l) & { + auto* const bracket = entries_.LastOpenBracket(); + auto& eqPos = (bracket ? bracket->equalPositions : entries_.equalPositions); eqPos.emplace_back(l); return *this; } - [[nodiscard]] Query &&AddEqualPosition(h_vector equalPosition) && { + [[nodiscard]] Query&& AddEqualPosition(h_vector equalPosition) && { return std::move(AddEqualPosition(std::move(equalPosition))); } - [[nodiscard]] Query &&AddEqualPosition(std::vector equalPosition) && { + [[nodiscard]] Query&& AddEqualPosition(std::vector equalPosition) && { return std::move(AddEqualPosition(std::move(equalPosition))); } - [[nodiscard]] Query &&AddEqualPosition(std::initializer_list l) && { return std::move(AddEqualPosition(l)); } + [[nodiscard]] Query&& AddEqualPosition(std::initializer_list l) && { return std::move(AddEqualPosition(l)); } /// Joins namespace with another namespace. Analog to sql JOIN. /// @param joinType - type of Join (Inner, Left or OrInner). @@ -456,21 +468,21 @@ class Query { /// @param op - operation type (and, or, not). /// @param qr - query of the namespace that is going to be joined with this one. /// @return Query object ready to be executed. - Query &Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, Query &&qr) &; + Query& Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, Query&& qr) &; template - [[nodiscard]] Query &&Join(JoinType joinType, StrL &&leftField, StrR &&rightField, CondType cond, OpType op, Query &&qr) && { + [[nodiscard]] Query&& Join(JoinType joinType, StrL&& leftField, StrR&& rightField, CondType cond, OpType op, Query&& qr) && { return std::move(Join(joinType, std::forward(leftField), std::forward(rightField), cond, op, std::move(qr))); } - Query &Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, const Query &qr) &; + Query& Join(JoinType joinType, std::string leftField, std::string rightField, CondType cond, OpType op, const Query& qr) &; template - [[nodiscard]] Query &&Join(JoinType joinType, StrL &&leftField, StrR &&rightField, CondType cond, OpType op, const Query &qr) && { + [[nodiscard]] Query&& Join(JoinType joinType, StrL&& leftField, StrR&& rightField, CondType cond, OpType op, const Query& qr) && { return std::move(Join(joinType, std::forward(leftField), std::forward(rightField), cond, op, qr)); } - [[nodiscard]] auto Join(JoinType joinType, Query &&q) &; - [[nodiscard]] auto Join(JoinType joinType, const Query &q) &; - [[nodiscard]] auto Join(JoinType joinType, Query &&q) &&; - [[nodiscard]] auto Join(JoinType joinType, const Query &q) &&; + [[nodiscard]] auto Join(JoinType joinType, Query&& q) &; + [[nodiscard]] auto Join(JoinType joinType, const Query& q) &; + [[nodiscard]] auto Join(JoinType joinType, Query&& q) &&; + [[nodiscard]] auto Join(JoinType joinType, const Query& q) &&; /// @public /// Inner Join of this namespace with another one. @@ -480,19 +492,19 @@ class Query { /// @param qr - query of the namespace that is going to be joined with this one. /// @return Query object ready to be executed. template - Query &InnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) & { // -V1071 + Query& InnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) & { // -V1071 return Join(JoinType::InnerJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, std::move(qr)); } template - [[nodiscard]] Query &&InnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) && { + [[nodiscard]] Query&& InnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) && { return std::move(InnerJoin(std::forward(leftField), std::forward(rightField), cond, std::move(qr))); } template - Query &InnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) & { + Query& InnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) & { return Join(JoinType::InnerJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, qr); } template - [[nodiscard]] Query &&InnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) && { + [[nodiscard]] Query&& InnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) && { return std::move(InnerJoin(std::forward(leftField), std::forward(rightField), cond, qr)); } @@ -503,19 +515,19 @@ class Query { /// @param qr - query of the namespace that is going to be joined with this one. /// @return Query object ready to be executed. template - Query &LeftJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) & { + Query& LeftJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) & { return Join(JoinType::LeftJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, std::move(qr)); } template - [[nodiscard]] Query &&LeftJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) && { + [[nodiscard]] Query&& LeftJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) && { return std::move(LeftJoin(std::forward(leftField), std::forward(rightField), cond, std::move(qr))); } template - Query &LeftJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) & { + Query& LeftJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) & { return Join(JoinType::LeftJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, qr); } template - [[nodiscard]] Query &&LeftJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) && { + [[nodiscard]] Query&& LeftJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) && { return std::move(LeftJoin(std::forward(leftField), std::forward(rightField), cond, qr)); } @@ -526,57 +538,59 @@ class Query { /// @param qr - query of the namespace that is going to be joined with this one. /// @return a reference to a query object ready to be executed. template - Query &OrInnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) & { + Query& OrInnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) & { return Join(JoinType::OrInnerJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, std::move(qr)); } template - [[nodiscard]] Query &&OrInnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, Query &&qr) && { + [[nodiscard]] Query&& OrInnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, Query&& qr) && { return std::move(OrInnerJoin(std::forward(leftField), std::forward(rightField), cond, std::move(qr))); } template - Query &OrInnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) & { + Query& OrInnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) & { return Join(JoinType::OrInnerJoin, std::forward(leftField), std::forward(rightField), cond, OpAnd, qr); } template - [[nodiscard]] Query &&OrInnerJoin(StrL &&leftField, StrR &&rightField, CondType cond, const Query &qr) && { + [[nodiscard]] Query&& OrInnerJoin(StrL&& leftField, StrR&& rightField, CondType cond, const Query& qr) && { return std::move(OrInnerJoin(std::forward(leftField), std::forward(rightField), cond, qr)); } - Query &Merge(const Query &q) &; - [[nodiscard]] Query &&Merge(const Query &q) && { return std::move(Merge(q)); } - Query &Merge(Query &&q) &; - [[nodiscard]] Query &&Merge(Query &&q) && { return std::move(Merge(std::move(q))); } + Query& Merge(const Query& q) &; + [[nodiscard]] Query&& Merge(const Query& q) && { return std::move(Merge(q)); } + Query& Merge(Query&& q) &; + [[nodiscard]] Query&& Merge(Query&& q) && { return std::move(Merge(std::move(q))); } /// Changes debug level. /// @param level - debug level. /// @return Query object. - Query &Debug(int level) & noexcept { - walkNested(true, true, true, [level](Query &q) noexcept { q.debugLevel_ = level; }); + Query& Debug(int level) & noexcept { + walkNested(true, true, true, [level](Query& q) noexcept { q.debugLevel_ = level; }); return *this; } - [[nodiscard]] Query &&Debug(int level) && noexcept { return std::move(Debug(level)); } + [[nodiscard]] Query&& Debug(int level) && noexcept { return std::move(Debug(level)); } [[nodiscard]] int GetDebugLevel() const noexcept { return debugLevel_; } /// Changes strict mode. /// @param mode - strict mode. /// @return Query object. - Query &Strict(StrictMode mode) & noexcept { - walkNested(true, true, true, [mode](Query &q) noexcept { q.strictMode_ = mode; }); + Query& Strict(StrictMode mode) & noexcept { + walkNested(true, true, true, [mode](Query& q) noexcept { q.strictMode_ = mode; }); return *this; } - [[nodiscard]] Query &&Strict(StrictMode mode) && noexcept { return std::move(Strict(mode)); } + [[nodiscard]] Query&& Strict(StrictMode mode) && noexcept { return std::move(Strict(mode)); } [[nodiscard]] StrictMode GetStrictMode() const noexcept { return strictMode_; } /// Performs sorting by certain column. Same as sql 'ORDER BY'. /// @param sort - sorting column name. /// @param desc - is sorting direction descending or ascending. /// @return Query object. - template > * = nullptr> - Query &Sort(Str &&sort, bool desc) & { // -V1071 - if (!strEmpty(sort)) sortingEntries_.emplace_back(std::forward(sort), desc); + template >* = nullptr> + Query& Sort(Str&& sort, bool desc) & { // -V1071 + if (!strEmpty(sort)) { + sortingEntries_.emplace_back(std::forward(sort), desc); + } return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Sort(Str &&sort, bool desc) && { + template >* = nullptr> + [[nodiscard]] Query&& Sort(Str&& sort, bool desc) && { return std::move(Sort(std::forward(sort), desc)); } @@ -585,8 +599,8 @@ class Query { /// @param p - target point. /// @param desc - is sorting direction descending or ascending. /// @return Query object. - Query &SortStDistance(std::string_view field, reindexer::Point p, bool desc) &; - [[nodiscard]] Query &&SortStDistance(std::string_view field, reindexer::Point p, bool desc) && { + Query& SortStDistance(std::string_view field, reindexer::Point p, bool desc) &; + [[nodiscard]] Query&& SortStDistance(std::string_view field, reindexer::Point p, bool desc) && { return std::move(SortStDistance(field, p, desc)); } /// Performs sorting by ST_Distance() expressions for geometry index. Sorting function will use distance 2 fields. @@ -594,8 +608,8 @@ class Query { /// @param field2 - second field name.This field must contain Point. /// @param desc - is sorting direction descending or ascending. /// @return Query object. - Query &SortStDistance(std::string_view field1, std::string_view field2, bool desc) &; - [[nodiscard]] Query &&SortStDistance(std::string_view field1, std::string_view field2, bool desc) && { + Query& SortStDistance(std::string_view field1, std::string_view field2, bool desc) &; + [[nodiscard]] Query&& SortStDistance(std::string_view field1, std::string_view field2, bool desc) && { return std::move(SortStDistance(field1, field2, desc)); } @@ -604,16 +618,19 @@ class Query { /// @param desc - is sorting direction descending or ascending. /// @param forcedSortOrder - list of values for forced sort order. /// @return Query object. - template > * = nullptr> - Query &Sort(Str &&sort, bool desc, std::initializer_list forcedSortOrder) & { - if (!sortingEntries_.empty() && !std::empty(forcedSortOrder)) + template >* = nullptr> + Query& Sort(Str&& sort, bool desc, std::initializer_list forcedSortOrder) & { + if (!sortingEntries_.empty() && !std::empty(forcedSortOrder)) { throw Error(errParams, "Forced sort order is allowed for the first sorting entry only"); + } sortingEntries_.emplace_back(std::forward(sort), desc); - for (const T &v : forcedSortOrder) forcedSortOrder_.emplace_back(v); + for (const T& v : forcedSortOrder) { + forcedSortOrder_.emplace_back(v); + } return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Sort(Str &&sort, bool desc, std::initializer_list forcedSortOrder) && { + template >* = nullptr> + [[nodiscard]] Query&& Sort(Str&& sort, bool desc, std::initializer_list forcedSortOrder) && { return std::move(Sort(std::forward(sort), desc, std::move(forcedSortOrder))); } @@ -622,57 +639,60 @@ class Query { /// @param desc - is sorting direction descending or ascending. /// @param forcedSortOrder - list of values for forced sort order. /// @return Query object. - template > * = nullptr> - Query &Sort(Str &&sort, bool desc, const T &forcedSortOrder) & { - if (!sortingEntries_.empty() && !forcedSortOrder.empty()) + template >* = nullptr> + Query& Sort(Str&& sort, bool desc, const T& forcedSortOrder) & { + if (!sortingEntries_.empty() && !forcedSortOrder.empty()) { throw Error(errParams, "Forced sort order is allowed for the first sorting entry only"); + } sortingEntries_.emplace_back(std::forward(sort), desc); - for (const auto &v : forcedSortOrder) forcedSortOrder_.emplace_back(v); + for (const auto& v : forcedSortOrder) { + forcedSortOrder_.emplace_back(v); + } return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Sort(Str &&sort, bool desc, const T &forcedSortOrder) && { + template >* = nullptr> + [[nodiscard]] Query&& Sort(Str&& sort, bool desc, const T& forcedSortOrder) && { return std::move(Sort(std::forward(sort), desc, forcedSortOrder)); } /// Performs distinct for a certain index. /// @param indexName - name of index for distinct operation. - template > * = nullptr> - Query &Distinct(Str &&indexName) & { + template >* = nullptr> + Query& Distinct(Str&& indexName) & { if (!strEmpty(indexName)) { aggregations_.emplace_back(AggDistinct, h_vector{std::forward(indexName)}); } return *this; } - template > * = nullptr> - [[nodiscard]] Query &&Distinct(Str &&indexName) && { + template >* = nullptr> + [[nodiscard]] Query&& Distinct(Str&& indexName) && { return std::move(Distinct(std::forward(indexName))); } /// Sets list of columns in this namespace to be finally selected. /// @param l - list of columns to be selected. - template > * = nullptr> - Query &Select(std::initializer_list l) & { + template >* = nullptr> + Query& Select(std::initializer_list l) & { return Select>(std::move(l)); } - template > * = nullptr> - [[nodiscard]] Query &&Select(std::initializer_list l) && { + template >* = nullptr> + [[nodiscard]] Query&& Select(std::initializer_list l) && { return std::move(Select>(std::move(l))); } template - Query &Select(StrCont &&l) & { + Query& Select(StrCont&& l) & { using namespace std::string_view_literals; if (!CanAddSelectFilter()) { throw Error(errConflict, kAggregationWithSelectFieldsMsgError); } selectFilter_.insert(selectFilter_.begin(), l.begin(), l.end()); - selectFilter_.erase(std::remove_if(selectFilter_.begin(), selectFilter_.end(), [](const auto &s) { return s == "*"sv; }), + selectFilter_.erase(std::remove_if(selectFilter_.begin(), selectFilter_.end(), [](const auto& s) { return s == "*"sv; }), selectFilter_.end()); return *this; } template - [[nodiscard]] Query &&Select(StrCont &&l) && { + [[nodiscard]] Query&& Select(StrCont&& l) && { return std::move(Select(std::forward(l))); } @@ -685,118 +705,118 @@ class Query { /// @param limit - number of rows to get from result set. /// @param offset - index of the first row to get from result set. /// @return Query object ready to be executed. - Query &Aggregate(AggType type, h_vector fields, const std::vector> &sort = {}, + Query& Aggregate(AggType type, h_vector fields, const std::vector>& sort = {}, unsigned limit = QueryEntry::kDefaultLimit, unsigned offset = QueryEntry::kDefaultOffset) & { if (!CanAddAggregation(type)) { throw Error(errConflict, kAggregationWithSelectFieldsMsgError); } SortingEntries sorting; sorting.reserve(sort.size()); - for (const auto &s : sort) { + for (const auto& s : sort) { sorting.emplace_back(s.first, s.second); } aggregations_.emplace_back(type, std::move(fields), std::move(sorting), limit, offset); return *this; } - [[nodiscard]] Query &&Aggregate(AggType type, h_vector fields, - const std::vector> &sort = {}, unsigned limit = QueryEntry::kDefaultLimit, + [[nodiscard]] Query&& Aggregate(AggType type, h_vector fields, + const std::vector>& sort = {}, unsigned limit = QueryEntry::kDefaultLimit, unsigned offset = QueryEntry::kDefaultOffset) && { return std::move(Aggregate(type, std::move(fields), sort, limit, offset)); } /// Sets next operation type to Or. /// @return Query object. - Query &Or() & { + Query& Or() & { assertrx_dbg(nextOp_ == OpAnd); nextOp_ = OpOr; return *this; } - [[nodiscard]] Query &&Or() && { return std::move(Or()); } + [[nodiscard]] Query&& Or() && { return std::move(Or()); } /// Sets next operation type to Not. /// @return Query object. - Query &Not() & { + Query& Not() & { assertrx_dbg(nextOp_ == OpAnd); nextOp_ = OpNot; return *this; } - [[nodiscard]] Query &&Not() && { return std::move(Not()); } + [[nodiscard]] Query&& Not() && { return std::move(Not()); } /// Sets next operation type to And. /// @return Query object. - Query &And() & { + Query& And() & { nextOp_ = OpAnd; return *this; } - [[nodiscard]] Query &&And() && { return std::move(And()); } - Query &NextOp(OpType op) & { + [[nodiscard]] Query&& And() && { return std::move(And()); } + Query& NextOp(OpType op) & { nextOp_ = op; return *this; } - [[nodiscard]] Query &&NextOp(OpType op) && { return std::move(NextOp(op)); } + [[nodiscard]] Query&& NextOp(OpType op) && { return std::move(NextOp(op)); } [[nodiscard]] OpType NextOp() const noexcept { return nextOp_; } /// Insert open bracket to order logic operations. /// @return Query object. - Query &OpenBracket() & { + Query& OpenBracket() & { entries_.OpenBracket(nextOp_); nextOp_ = OpAnd; return *this; } - [[nodiscard]] Query &&OpenBracket() && { return std::move(OpenBracket()); } + [[nodiscard]] Query&& OpenBracket() && { return std::move(OpenBracket()); } /// Insert close bracket to order logic operations. /// @return Query object. - Query &CloseBracket() & { + Query& CloseBracket() & { entries_.CloseBracket(); return *this; } - [[nodiscard]] Query &&CloseBracket() && { return std::move(CloseBracket()); } + [[nodiscard]] Query&& CloseBracket() && { return std::move(CloseBracket()); } /// Sets the limit of selected rows. /// Analog to sql LIMIT rowsNumber. /// @param limit - number of rows to get from result set. /// @return Query object. - Query &Limit(unsigned limit) & noexcept { + Query& Limit(unsigned limit) & noexcept { count_ = limit; return *this; } - [[nodiscard]] Query &&Limit(unsigned limit) && noexcept { return std::move(Limit(limit)); } + [[nodiscard]] Query&& Limit(unsigned limit) && noexcept { return std::move(Limit(limit)); } /// Sets the number of the first selected row from result query. /// Analog to sql LIMIT OFFSET. /// @param offset - index of the first row to get from result set. /// @return Query object. - Query &Offset(unsigned offset) & noexcept { + Query& Offset(unsigned offset) & noexcept { start_ = offset; return *this; } - [[nodiscard]] Query &&Offset(unsigned offset) && noexcept { return std::move(Offset(offset)); } + [[nodiscard]] Query&& Offset(unsigned offset) && noexcept { return std::move(Offset(offset)); } /// Set the total count calculation mode to Accurate /// @return Query object - Query &ReqTotal() & noexcept { + Query& ReqTotal() & noexcept { calcTotal_ = ModeAccurateTotal; return *this; } - [[nodiscard]] Query &&ReqTotal() && noexcept { return std::move(ReqTotal()); } + [[nodiscard]] Query&& ReqTotal() && noexcept { return std::move(ReqTotal()); } /// Set the total count calculation mode to Cached. /// It will be use LRUCache for total count result /// @return Query object - Query &CachedTotal() & noexcept { + Query& CachedTotal() & noexcept { calcTotal_ = ModeCachedTotal; return *this; } - [[nodiscard]] Query &&CachedTotal() && noexcept { return std::move(CachedTotal()); } + [[nodiscard]] Query&& CachedTotal() && noexcept { return std::move(CachedTotal()); } /// Output fulltext rank /// Allowed only with fulltext query /// @return Query object - Query &WithRank() & noexcept { + Query& WithRank() & noexcept { withRank_ = true; return *this; } - [[nodiscard]] Query &&WithRank() && noexcept { return std::move(WithRank()); } + [[nodiscard]] Query&& WithRank() && noexcept { return std::move(WithRank()); } [[nodiscard]] bool IsWithRank() const noexcept { return withRank_; } /// Can we add aggregation functions @@ -809,23 +829,23 @@ class Query { /// Serializes query data to stream. /// @param ser - serializer object for write. /// @param mode - serialization mode. - void Serialize(WrSerializer &ser, uint8_t mode = Normal) const; + void Serialize(WrSerializer& ser, uint8_t mode = Normal) const; /// Deserializes query data from stream. /// @param ser - serializer object. - [[nodiscard]] static Query Deserialize(Serializer &ser); + [[nodiscard]] static Query Deserialize(Serializer& ser); - void WalkNested(bool withSelf, bool withMerged, bool withSubQueries, const std::function &visitor) const + void WalkNested(bool withSelf, bool withMerged, bool withSubQueries, const std::function& visitor) const noexcept(noexcept(visitor(std::declval()))); [[nodiscard]] bool HasLimit() const noexcept { return count_ != QueryEntry::kDefaultLimit; } [[nodiscard]] bool HasOffset() const noexcept { return start_ != QueryEntry::kDefaultOffset; } [[nodiscard]] bool IsWALQuery() const noexcept; - [[nodiscard]] const std::vector &UpdateFields() const noexcept { return updateFields_; } + [[nodiscard]] const std::vector& UpdateFields() const noexcept { return updateFields_; } [[nodiscard]] QueryType Type() const noexcept { return type_; } - [[nodiscard]] const std::string &NsName() const & noexcept { return namespace_; } + [[nodiscard]] const std::string& NsName() const& noexcept { return namespace_; } template - void SetNsName(T &&nsName) & noexcept { + void SetNsName(T&& nsName) & noexcept { namespace_ = std::forward(nsName); } [[nodiscard]] unsigned Limit() const noexcept { return count_; } @@ -841,66 +861,68 @@ class Query { std::vector aggregations_; - auto NsName() const && = delete; - [[nodiscard]] const QueryEntries &Entries() const noexcept { return entries_; } + auto NsName() const&& = delete; + [[nodiscard]] const QueryEntries& Entries() const noexcept { return entries_; } template - [[nodiscard]] T &GetUpdatableEntry(size_t i) & noexcept { + [[nodiscard]] T& GetUpdatableEntry(size_t i) & noexcept { return entries_.Get(i); } template - void SetEntry(size_t i, Args &&...args) { + void SetEntry(size_t i, Args&&... args) { entries_.SetValue(i, T{std::forward(args)...}); } - void UpdateField(UpdateEntry &&ue) & { updateFields_.emplace_back(std::move(ue)); } - void SetEqualPositions(EqualPosition_t &&ep) & { entries_.equalPositions.emplace_back(std::move(ep)); } - void SetEqualPositions(size_t bracketPosition, EqualPosition_t &&ep) & { + void UpdateField(UpdateEntry&& ue) & { updateFields_.emplace_back(std::move(ue)); } + void SetEqualPositions(EqualPosition_t&& ep) & { entries_.equalPositions.emplace_back(std::move(ep)); } + void SetEqualPositions(size_t bracketPosition, EqualPosition_t&& ep) & { entries_.Get(bracketPosition).equalPositions.emplace_back(std::move(ep)); } - void Join(JoinedQuery &&) &; + void Join(JoinedQuery&&) &; void ReserveQueryEntries(size_t s) & { entries_.Reserve(s); } template - Query &AppendQueryEntry(OpType op, Args &&...args) & { + Query& AppendQueryEntry(OpType op, Args&&... args) & { entries_.Append(op, std::forward(args)...); return *this; } template - Query &&AppendQueryEntry(OpType op, Args &&...args) && { + Query&& AppendQueryEntry(OpType op, Args&&... args) && { entries_.Append(op, std::forward(args)...); return std::move(*this); } void SetLastOperation(OpType op) & { entries_.SetLastOperation(op); } - [[nodiscard]] const Query &GetSubQuery(size_t i) const & noexcept { return subQueries_.at(i); } - [[nodiscard]] const auto &GetSubQueries() const & noexcept { return subQueries_; } - [[nodiscard]] const auto &GetJoinQueries() const & noexcept { return joinQueries_; } - [[nodiscard]] const auto &GetMergeQueries() const & noexcept { return mergeQueries_; } - [[nodiscard]] const auto &SelectFilters() const & noexcept { return selectFilter_; } - void AddJoinQuery(JoinedQuery &&); + [[nodiscard]] const Query& GetSubQuery(size_t i) const& noexcept { return subQueries_.at(i); } + [[nodiscard]] const auto& GetSubQueries() const& noexcept { return subQueries_; } + [[nodiscard]] const auto& GetJoinQueries() const& noexcept { return joinQueries_; } + [[nodiscard]] const auto& GetMergeQueries() const& noexcept { return mergeQueries_; } + [[nodiscard]] const auto& SelectFilters() const& noexcept { return selectFilter_; } + void AddJoinQuery(JoinedQuery&&); void VerifyForUpdate() const; template - size_t InjectConditionsFromOnConditions(size_t position, const h_vector &joinEntries, - const QueryEntries &joinedQueryEntries, size_t joinedQueryNo, - const std::vector> *indexesFrom) { + size_t InjectConditionsFromOnConditions(size_t position, const h_vector& joinEntries, + const QueryEntries& joinedQueryEntries, size_t joinedQueryNo, + const std::vector>* indexesFrom) { return entries_.InjectConditionsFromOnConditions(position, joinEntries, joinedQueryEntries, joinedQueryNo, indexesFrom); } - auto GetSubQuery(size_t) const && = delete; - auto GetSubQueries() const && = delete; - auto GetJoinQueries() const && = delete; - auto GetMergeQueries() const && = delete; - auto SelectFilters() const && = delete; + auto GetSubQuery(size_t) const&& = delete; + auto GetSubQueries() const&& = delete; + auto GetJoinQueries() const&& = delete; + auto GetMergeQueries() const&& = delete; + auto SelectFilters() const&& = delete; private: class [[nodiscard]] PopBackQEGuard { public: - explicit PopBackQEGuard(QueryEntries *e) noexcept : e_{e} {} + explicit PopBackQEGuard(QueryEntries* e) noexcept : e_{e} {} ~PopBackQEGuard() { - if (e_) e_->PopBack(); + if (e_) { + e_->PopBack(); + } } void Reset() noexcept { e_ = nullptr; } private: - QueryEntries *e_; + QueryEntries* e_; }; template @@ -908,28 +930,28 @@ class Query { template class [[nodiscard]] OnHelperGroup { public: - [[nodiscard]] OnHelperGroup &&Not() && noexcept { + [[nodiscard]] OnHelperGroup&& Not() && noexcept { op_ = OpNot; return std::move(*this); } - [[nodiscard]] OnHelperGroup &&Or() && noexcept { + [[nodiscard]] OnHelperGroup&& Or() && noexcept { op_ = OpOr; return std::move(*this); } - [[nodiscard]] OnHelperGroup &&On(std::string index, CondType cond, std::string joinIndex) &&; + [[nodiscard]] OnHelperGroup&& On(std::string index, CondType cond, std::string joinIndex) &&; [[nodiscard]] Q CloseBracket() && noexcept { return std::forward(q_); } private: - OnHelperGroup(Q q, JoinedQuery &jq) noexcept : q_{std::forward(q)}, jq_{jq} {} + OnHelperGroup(Q q, JoinedQuery& jq) noexcept : q_{std::forward(q)}, jq_{jq} {} Q q_; - JoinedQuery &jq_; + JoinedQuery& jq_; OpType op_{OpAnd}; friend class OnHelperTempl; }; template class [[nodiscard]] OnHelperTempl { public: - [[nodiscard]] OnHelperTempl &&Not() && noexcept { + [[nodiscard]] OnHelperTempl&& Not() && noexcept { op_ = OpNot; return std::move(*this); } @@ -937,23 +959,23 @@ class Query { [[nodiscard]] OnHelperGroup OpenBracket() && noexcept { return {std::forward(q_), jq_}; } private: - OnHelperTempl(Q q, JoinedQuery &jq) noexcept : q_{std::forward(q)}, jq_{jq} {} + OnHelperTempl(Q q, JoinedQuery& jq) noexcept : q_{std::forward(q)}, jq_{jq} {} Q q_; - JoinedQuery &jq_; + JoinedQuery& jq_; OpType op_{OpAnd}; friend class Query; }; - using OnHelper = OnHelperTempl; - using OnHelperR = OnHelperTempl; + using OnHelper = OnHelperTempl; + using OnHelperR = OnHelperTempl; - void deserialize(Serializer &ser, bool &hasJoinConditions); - VariantArray deserializeValues(Serializer &, CondType); + void deserialize(Serializer& ser, bool& hasJoinConditions); + VariantArray deserializeValues(Serializer&, CondType); void checkSubQueryNoData() const; void checkSubQueryWithData() const; void checkSubQuery() const; void walkNested(bool withSelf, bool withMerged, bool withSubQueries, - const std::function &visitor) noexcept(noexcept(visitor(std::declval()))); - void adoptNested(Query &nq) const noexcept { nq.Strict(GetStrictMode()).Explain(NeedExplain()).Debug(GetDebugLevel()); } + const std::function& visitor) noexcept(noexcept(visitor(std::declval()))); + void adoptNested(Query& nq) const noexcept { nq.Strict(GetStrictMode()).Explain(NeedExplain()).Debug(GetDebugLevel()); } std::string namespace_; /// Name of the namespace. unsigned start_ = QueryEntry::kDefaultOffset; /// First row index from result set. @@ -974,10 +996,10 @@ class Query { class JoinedQuery : public Query { public: - JoinedQuery(JoinType jt, const Query &q) : Query(q), joinType{jt} {} - JoinedQuery(JoinType jt, Query &&q) : Query(std::move(q)), joinType{jt} {} + JoinedQuery(JoinType jt, const Query& q) : Query(q), joinType{jt} {} + JoinedQuery(JoinType jt, Query&& q) : Query(std::move(q)), joinType{jt} {} using Query::Query; - [[nodiscard]] bool operator==(const JoinedQuery &obj) const; + [[nodiscard]] bool operator==(const JoinedQuery& obj) const; JoinType joinType{JoinType::LeftJoin}; /// Default join type. h_vector joinEntries_; /// Condition for join. Filled in each subqueries, empty in root query @@ -990,28 +1012,28 @@ template } template -[[nodiscard]] Query::OnHelperGroup &&Query::OnHelperGroup::On(std::string index, CondType cond, std::string joinIndex) && { +[[nodiscard]] Query::OnHelperGroup&& Query::OnHelperGroup::On(std::string index, CondType cond, std::string joinIndex) && { jq_.joinEntries_.emplace_back(op_, cond, std::move(index), std::move(joinIndex)); op_ = OpAnd; return std::move(*this); } -[[nodiscard]] inline auto Query::Join(JoinType joinType, Query &&q) & { +[[nodiscard]] inline auto Query::Join(JoinType joinType, Query&& q) & { Join({joinType, std::move(q)}); return OnHelper{*this, joinQueries_.back()}; } -[[nodiscard]] inline auto Query::Join(JoinType joinType, const Query &q) & { +[[nodiscard]] inline auto Query::Join(JoinType joinType, const Query& q) & { Join({joinType, q}); return OnHelper{*this, joinQueries_.back()}; } -[[nodiscard]] inline auto Query::Join(JoinType joinType, Query &&q) && { +[[nodiscard]] inline auto Query::Join(JoinType joinType, Query&& q) && { Join({joinType, std::move(q)}); return OnHelperR{std::move(*this), joinQueries_.back()}; } -[[nodiscard]] inline auto Query::Join(JoinType joinType, const Query &q) && { +[[nodiscard]] inline auto Query::Join(JoinType joinType, const Query& q) && { Join({joinType, q}); return OnHelperR{std::move(*this), joinQueries_.back()}; } diff --git a/cpp_src/core/query/queryentry.cc b/cpp_src/core/query/queryentry.cc index 8a32d917b..6e2d8fcb6 100644 --- a/cpp_src/core/query/queryentry.cc +++ b/cpp_src/core/query/queryentry.cc @@ -13,13 +13,13 @@ namespace reindexer { template -std::string JoinQueryEntry::Dump(const std::vector &joinedSelectors) const { +std::string JoinQueryEntry::Dump(const std::vector& joinedSelectors) const { WrSerializer ser; - const auto &js = joinedSelectors.at(joinIndex); - const auto &q = js.JoinQuery(); + const auto& js = joinedSelectors.at(joinIndex); + const auto& q = js.JoinQuery(); ser << js.Type() << " (" << q.GetSQL() << ") ON "; ser << '('; - for (const auto &jqe : q.joinEntries_) { + for (const auto& jqe : q.joinEntries_) { if (&jqe != &q.joinEntries_.front()) { ser << ' ' << jqe.Operation() << ' '; } else { @@ -30,16 +30,16 @@ std::string JoinQueryEntry::Dump(const std::vector &joinedSelectors) const { ser << ')'; return std::string{ser.Slice()}; } -template std::string JoinQueryEntry::Dump(const JoinedSelectors &) const; -template std::string JoinQueryEntry::Dump(const std::vector &) const; +template std::string JoinQueryEntry::Dump(const JoinedSelectors&) const; +template std::string JoinQueryEntry::Dump(const std::vector&) const; template -std::string JoinQueryEntry::DumpOnCondition(const std::vector &joinedSelectors) const { +std::string JoinQueryEntry::DumpOnCondition(const std::vector& joinedSelectors) const { WrSerializer ser; - const auto &js = joinedSelectors.at(joinIndex); - const auto &q = js.JoinQuery(); + const auto& js = joinedSelectors.at(joinIndex); + const auto& q = js.JoinQuery(); ser << js.Type() << " ON ("; - for (const auto &jqe : q.joinEntries_) { + for (const auto& jqe : q.joinEntries_) { if (&jqe != &q.joinEntries_.front()) { ser << ' ' << jqe.Operation() << ' '; } @@ -48,9 +48,9 @@ std::string JoinQueryEntry::DumpOnCondition(const std::vector &joinedSelecto ser << ')'; return std::string{ser.Slice()}; } -template std::string JoinQueryEntry::DumpOnCondition(const JoinedSelectors &) const; +template std::string JoinQueryEntry::DumpOnCondition(const JoinedSelectors&) const; -bool QueryField::operator==(const QueryField &other) const noexcept { +bool QueryField::operator==(const QueryField& other) const noexcept { if (fieldName_ != other.fieldName_ || idxNo_ != other.idxNo_ || fieldsSet_ != other.fieldsSet_ || !fieldType_.IsSame(other.fieldType_) || !selectType_.IsSame(other.selectType_) || compositeFieldsTypes_.size() != other.compositeFieldsTypes_.size()) { @@ -58,10 +58,10 @@ bool QueryField::operator==(const QueryField &other) const noexcept { } return std::equal( compositeFieldsTypes_.begin(), compositeFieldsTypes_.end(), other.compositeFieldsTypes_.begin(), - [](const CompositeTypesVecT::value_type &l, const CompositeTypesVecT::value_type &r) noexcept { return l.IsSame(r); }); + [](const CompositeTypesVecT::value_type& l, const CompositeTypesVecT::value_type& r) noexcept { return l.IsSame(r); }); } -void QueryField::SetField(FieldsSet &&fields) & { +void QueryField::SetField(FieldsSet&& fields) & { assertrx_throw(fields.size() == 1); assertrx_throw(fields[0] == IndexValueType::SetByJsonPath); assertrx_throw(idxNo_ == IndexValueType::NotSet); @@ -69,8 +69,8 @@ void QueryField::SetField(FieldsSet &&fields) & { fieldsSet_ = std::move(fields); } -static void checkIndexData([[maybe_unused]] int idxNo, [[maybe_unused]] const FieldsSet &fields, KeyValueType fieldType, - [[maybe_unused]] const QueryField::CompositeTypesVecT &compositeFieldsTypes) { +static void checkIndexData([[maybe_unused]] int idxNo, [[maybe_unused]] const FieldsSet& fields, KeyValueType fieldType, + [[maybe_unused]] const QueryField::CompositeTypesVecT& compositeFieldsTypes) { assertrx_throw(idxNo >= 0); if (fieldType.Is()) { assertrx_throw(fields.size() == compositeFieldsTypes.size()); @@ -80,8 +80,8 @@ static void checkIndexData([[maybe_unused]] int idxNo, [[maybe_unused]] const Fi } } -void QueryField::SetIndexData(int idxNo, FieldsSet &&fields, KeyValueType fieldType, KeyValueType selectType, - QueryField::CompositeTypesVecT &&compositeFieldsTypes) & { +void QueryField::SetIndexData(int idxNo, FieldsSet&& fields, KeyValueType fieldType, KeyValueType selectType, + QueryField::CompositeTypesVecT&& compositeFieldsTypes) & { checkIndexData(idxNo, fields, fieldType, compositeFieldsTypes); idxNo_ = idxNo; fieldsSet_ = std::move(fields); @@ -103,13 +103,13 @@ bool QueryField::HaveEmptyField() const noexcept { return Fields().empty(); } -bool QueryEntry::operator==(const QueryEntry &other) const noexcept { +bool QueryEntry::operator==(const QueryEntry& other) const noexcept { return QueryField::operator==(other) && condition_ == other.condition_ && distinct_ == other.distinct_ && values_.RelaxCompare(other.values_) == ComparationResult::Eq; } template -void VerifyQueryEntryValues(CondType cond, const VariantArray &values) { +void VerifyQueryEntryValues(CondType cond, const VariantArray& values) { if constexpr (flags & VerifyQueryEntryFlags::ignoreEmptyValues) { if (values.empty()) { return; @@ -152,8 +152,8 @@ void VerifyQueryEntryValues(CondType cond, const VariantArray &values) { break; } } -template void VerifyQueryEntryValues(CondType, const VariantArray &); -template void VerifyQueryEntryValues(CondType, const VariantArray &); +template void VerifyQueryEntryValues(CondType, const VariantArray&); +template void VerifyQueryEntryValues(CondType, const VariantArray&); std::string QueryEntry::Dump() const { WrSerializer ser; @@ -162,12 +162,18 @@ std::string QueryEntry::Dump() const { } ser << FieldName() << ' ' << condition_ << ' '; const bool severalValues = (Values().size() > 1); - if (severalValues) ser << '('; - for (auto &v : Values()) { - if (&v != &*Values().begin()) ser << ','; + if (severalValues) { + ser << '('; + } + for (auto& v : Values()) { + if (&v != &*Values().begin()) { + ser << ','; + } ser << '\'' << v.As() << '\''; } - if (severalValues) ser << ')'; + if (severalValues) { + ser << ')'; + } return std::string{ser.Slice()}; } @@ -185,7 +191,7 @@ std::string QueryEntry::DumpBrief() const { return std::string(ser.Slice()); } -AggregateEntry::AggregateEntry(AggType type, h_vector &&fields, SortingEntries &&sort, unsigned limit, unsigned offset) +AggregateEntry::AggregateEntry(AggType type, h_vector&& fields, SortingEntries&& sort, unsigned limit, unsigned offset) : type_(type), fields_(std::move(fields)), sortingEntries_{std::move(sort)}, limit_(limit), offset_(offset) { switch (type_) { case AggFacet: @@ -233,7 +239,7 @@ AggregateEntry::AggregateEntry(AggType type, h_vector &&fields, } } -void AggregateEntry::AddSortingEntry(SortingEntry &&sorting) { +void AggregateEntry::AddSortingEntry(SortingEntry&& sorting) { if (type_ != AggFacet) { throw Error(errQueryExec, "Sort is not available for aggregation %s", AggTypeToStr(type_)); } @@ -254,7 +260,7 @@ void AggregateEntry::SetOffset(unsigned o) { offset_ = o; } -bool BetweenFieldsQueryEntry::operator==(const BetweenFieldsQueryEntry &other) const noexcept { +bool BetweenFieldsQueryEntry::operator==(const BetweenFieldsQueryEntry& other) const noexcept { return leftField_ == other.leftField_ && rightField_ == other.rightField_ && Condition() == other.Condition(); } @@ -264,7 +270,7 @@ std::string BetweenFieldsQueryEntry::Dump() const { return std::string{ser.Slice()}; } -void QueryEntries::serialize(CondType cond, const VariantArray &values, WrSerializer &ser) { +void QueryEntries::serialize(CondType cond, const VariantArray& values, WrSerializer& ser) { ser.PutVarUint(cond); if (cond == CondDWithin) { assertrx_throw(values.size() == 2); @@ -282,15 +288,17 @@ void QueryEntries::serialize(CondType cond, const VariantArray &values, WrSerial } } else { ser.PutVarUint(values.size()); - for (auto &kv : values) ser.PutVariant(kv); + for (auto& kv : values) { + ser.PutVariant(kv); + } } } -void QueryEntries::serialize(const_iterator it, const_iterator to, WrSerializer &ser, const std::vector &subQueries) { +void QueryEntries::serialize(const_iterator it, const_iterator to, WrSerializer& ser, const std::vector& subQueries) { for (; it != to; ++it) { const OpType op = it->operation; it->Visit( - [&ser, op, &subQueries](const SubQueryEntry &sqe) { + [&ser, op, &subQueries](const SubQueryEntry& sqe) { ser.PutVarUint(QuerySubQueryCondition); ser.PutVarUint(op); { @@ -299,7 +307,7 @@ void QueryEntries::serialize(const_iterator it, const_iterator to, WrSerializer } serialize(sqe.Condition(), sqe.Values(), ser); }, - [&ser, op, &subQueries](const SubQueryFieldEntry &sqe) { + [&ser, op, &subQueries](const SubQueryFieldEntry& sqe) { ser.PutVarUint(QueryFieldSubQueryCondition); ser.PutVarUint(op); ser.PutVString(sqe.FieldName()); @@ -309,103 +317,113 @@ void QueryEntries::serialize(const_iterator it, const_iterator to, WrSerializer subQueries.at(sqe.QueryIndex()).Serialize(ser); } }, - [&](const QueryEntriesBracket &) { + [&](const QueryEntriesBracket&) { ser.PutVarUint(QueryOpenBracket); ser.PutVarUint(op); serialize(it.cbegin(), it.cend(), ser, subQueries); ser.PutVarUint(QueryCloseBracket); }, - [&ser, op](const QueryEntry &entry) { + [&ser, op](const QueryEntry& entry) { entry.Distinct() ? ser.PutVarUint(QueryDistinct) : ser.PutVarUint(QueryCondition); ser.PutVString(entry.FieldName()); - if (entry.Distinct()) return; + if (entry.Distinct()) { + return; + } ser.PutVarUint(op); serialize(entry.Condition(), entry.Values(), ser); }, - [&ser, op](const JoinQueryEntry &jqe) { + [&ser, op](const JoinQueryEntry& jqe) { ser.PutVarUint(QueryJoinCondition); ser.PutVarUint((op == OpAnd) ? JoinType::InnerJoin : JoinType::OrInnerJoin); ser.PutVarUint(jqe.joinIndex); }, - [&ser, op](const BetweenFieldsQueryEntry &entry) { + [&ser, op](const BetweenFieldsQueryEntry& entry) { ser.PutVarUint(QueryBetweenFieldsCondition); ser.PutVarUint(op); ser.PutVString(entry.LeftFieldName()); ser.PutVarUint(entry.Condition()); ser.PutVString(entry.RightFieldName()); }, - [&ser, op](const AlwaysFalse &) { + [&ser, op](const AlwaysFalse&) { ser.PutVarUint(QueryAlwaysFalseCondition); ser.PutVarUint(op); }, - [&ser, op](const AlwaysTrue &) { + [&ser, op](const AlwaysTrue&) { ser.PutVarUint(QueryAlwaysTrueCondition); ser.PutVarUint(op); }); } } -bool UpdateEntry::operator==(const UpdateEntry &obj) const noexcept { +bool UpdateEntry::operator==(const UpdateEntry& obj) const noexcept { return isExpression_ == obj.isExpression_ && column_ == obj.column_ && mode_ == obj.mode_ && values_ == obj.values_; } -bool QueryJoinEntry::operator==(const QueryJoinEntry &other) const noexcept { +bool QueryJoinEntry::operator==(const QueryJoinEntry& other) const noexcept { return op_ == other.op_ && condition_ == other.condition_ && leftField_ == other.leftField_ && rightField_ == other.rightField_; } -bool AggregateEntry::operator==(const AggregateEntry &obj) const noexcept { +bool AggregateEntry::operator==(const AggregateEntry& obj) const noexcept { return fields_ == obj.fields_ && type_ == obj.type_ && sortingEntries_ == obj.sortingEntries_ && limit_ == obj.limit_ && offset_ == obj.offset_; } -bool SortingEntry::operator==(const SortingEntry &obj) const noexcept { - if (expression != obj.expression) return false; - if (desc != obj.desc) return false; - if (index != obj.index) return false; +bool SortingEntry::operator==(const SortingEntry& obj) const noexcept { + if (expression != obj.expression) { + return false; + } + if (desc != obj.desc) { + return false; + } + if (index != obj.index) { + return false; + } return true; } -bool QueryEntries::checkIfSatisfyConditions(const_iterator begin, const_iterator end, const ConstPayload &pl) { +bool QueryEntries::checkIfSatisfyConditions(const_iterator begin, const_iterator end, const ConstPayload& pl) { assertrx_dbg(begin != end && begin->operation != OpOr); bool result = true; for (auto it = begin; it != end; ++it) { if (it->operation == OpOr) { - if (result) continue; + if (result) { + continue; + } } else if (!result) { break; } const bool lastResult = it->Visit( - [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry &) RX_POST_LMBD_ALWAYS_INLINE -> bool { + [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE -> bool { assertrx_throw(0); abort(); }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry &) RX_POST_LMBD_ALWAYS_INLINE -> bool { + [] RX_PRE_LMBD_ALWAYS_INLINE(const SubQueryFieldEntry&) RX_POST_LMBD_ALWAYS_INLINE -> bool { assertrx_throw(0); abort(); }, - [&it, &pl] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket &) + [&it, &pl] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntriesBracket&) RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyConditions(it.cbegin(), it.cend(), pl); }, - [&pl] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntry &qe) RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyCondition(qe, pl); }, - [&pl] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry &qe) + [&pl] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntry& qe) RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyCondition(qe, pl); }, + [&pl] RX_PRE_LMBD_ALWAYS_INLINE(const BetweenFieldsQueryEntry& qe) RX_POST_LMBD_ALWAYS_INLINE { return checkIfSatisfyCondition(qe, pl); }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry &) RX_POST_LMBD_ALWAYS_INLINE -> bool { + [] RX_PRE_LMBD_ALWAYS_INLINE(const JoinQueryEntry&) RX_POST_LMBD_ALWAYS_INLINE -> bool { assertrx_throw(0); abort(); }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse &) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, - [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysTrue &) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }); + [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysFalse&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return false; }, + [] RX_PRE_LMBD_ALWAYS_INLINE(const AlwaysTrue&) RX_POST_LMBD_ALWAYS_INLINE noexcept { return true; }); result = (lastResult != (it->operation == OpNot)); } return result; } -bool QueryEntries::checkIfSatisfyCondition(const QueryEntry &qEntry, const ConstPayload &pl) { +bool QueryEntries::checkIfSatisfyCondition(const QueryEntry& qEntry, const ConstPayload& pl) { VariantArray values; pl.GetByFieldsSet(qEntry.Fields(), values, qEntry.FieldType(), qEntry.CompositeFieldsTypes()); return CheckIfSatisfyCondition(values, qEntry.Condition(), qEntry.Values()); } -bool QueryEntries::checkIfSatisfyCondition(const BetweenFieldsQueryEntry &qEntry, const ConstPayload &pl) { +bool QueryEntries::checkIfSatisfyCondition(const BetweenFieldsQueryEntry& qEntry, const ConstPayload& pl) { VariantArray lValues; pl.GetByFieldsSet(qEntry.LeftFields(), lValues, qEntry.LeftFieldType(), qEntry.LeftCompositeFieldsTypes()); VariantArray rValues; @@ -413,7 +431,7 @@ bool QueryEntries::checkIfSatisfyCondition(const BetweenFieldsQueryEntry &qEntry return CheckIfSatisfyCondition(lValues, qEntry.Condition(), rValues); } -bool QueryEntries::CheckIfSatisfyCondition(const VariantArray &lValues, CondType condition, const VariantArray &rValues) { +bool QueryEntries::CheckIfSatisfyCondition(const VariantArray& lValues, CondType condition, const VariantArray& rValues) { switch (condition) { case CondType::CondAny: return !lValues.empty(); @@ -421,63 +439,82 @@ bool QueryEntries::CheckIfSatisfyCondition(const VariantArray &lValues, CondType return lValues.empty(); case CondType::CondEq: case CondType::CondSet: - for (const auto &lhs : lValues) { - for (const auto &rhs : rValues) { - if (lhs.RelaxCompare(rhs) == ComparationResult::Eq) return true; + for (const auto& lhs : lValues) { + for (const auto& rhs : rValues) { + if (lhs.RelaxCompare(rhs) == ComparationResult::Eq) { + return true; + } } } return false; case CondType::CondAllSet: - if (lValues.size() < rValues.size()) return false; - for (const auto &v : rValues) { + if (lValues.size() < rValues.size()) { + return false; + } + for (const auto& v : rValues) { auto it = lValues.cbegin(); for (; it != lValues.cend(); ++it) { - if (it->RelaxCompare(v) == ComparationResult::Eq) break; + if (it->RelaxCompare(v) == ComparationResult::Eq) { + break; + } + } + if (it == lValues.cend()) { + return false; } - if (it == lValues.cend()) return false; } return true; case CondType::CondLt: - for (const auto &lhs : lValues) { - for (const auto &rhs : rValues) { - if (lhs.RelaxCompare(rhs) == ComparationResult::Lt) return true; + for (const auto& lhs : lValues) { + for (const auto& rhs : rValues) { + if (lhs.RelaxCompare(rhs) == ComparationResult::Lt) { + return true; + } } } return false; case CondType::CondLe: - for (const auto &lhs : lValues) { - for (const auto &rhs : rValues) { - if (lhs.RelaxCompare(rhs) & ComparationResult::Le) return true; + for (const auto& lhs : lValues) { + for (const auto& rhs : rValues) { + if (lhs.RelaxCompare(rhs) & ComparationResult::Le) { + return true; + } } } return false; case CondType::CondGt: - for (const auto &lhs : lValues) { - for (const auto &rhs : rValues) { - if (lhs.RelaxCompare(rhs) == ComparationResult::Gt) return true; + for (const auto& lhs : lValues) { + for (const auto& rhs : rValues) { + if (lhs.RelaxCompare(rhs) == ComparationResult::Gt) { + return true; + } } } return false; case CondType::CondGe: - for (const auto &lhs : lValues) { - for (const auto &rhs : rValues) { - if (lhs.RelaxCompare(rhs) & ComparationResult::Ge) return true; + for (const auto& lhs : lValues) { + for (const auto& rhs : rValues) { + if (lhs.RelaxCompare(rhs) & ComparationResult::Ge) { + return true; + } } } return false; case CondType::CondRange: - for (const auto &v : lValues) { + for (const auto& v : lValues) { if (v.RelaxCompare(rValues[0]) == ComparationResult::Lt || - v.RelaxCompare(rValues[1]) == ComparationResult::Gt) + v.RelaxCompare(rValues[1]) == ComparationResult::Gt) { return false; + } } return true; case CondType::CondLike: - for (const auto &v : lValues) { + for (const auto& v : lValues) { if (!v.Type().Is()) { throw Error(errLogic, "Condition LIKE must be applied to data of string type, but %s was provided", v.Type().Name()); } - if (matchLikePattern(std::string_view(v), std::string_view(rValues[0]))) return true; + if (matchLikePattern(std::string_view(v), std::string_view(rValues[0]))) { + return true; + } } return false; case CondType::CondDWithin: { @@ -499,12 +536,12 @@ bool QueryEntries::CheckIfSatisfyCondition(const VariantArray &lValues, CondType } template -size_t QueryEntries::InjectConditionsFromOnConditions(size_t position, const h_vector &joinEntries, - const QueryEntries &joinedQueryEntries, size_t joinedQueryNo, - const std::vector> *indexesFrom) { +size_t QueryEntries::InjectConditionsFromOnConditions(size_t position, const h_vector& joinEntries, + const QueryEntries& joinedQueryEntries, size_t joinedQueryNo, + const std::vector>* indexesFrom) { size_t injectedCount = 0; for (size_t i = 0, s = joinEntries.size(); i < s; ++i) { - const QueryJoinEntry &jEntry = joinEntries[i]; + const QueryJoinEntry& jEntry = joinEntries[i]; if (i + 1 < s && joinEntries[i + 1].Operation() == OpOr) { continue; } @@ -546,16 +583,16 @@ size_t QueryEntries::InjectConditionsFromOnConditions(size_t position, const h_v } return injectedCount; } -template size_t QueryEntries::InjectConditionsFromOnConditions(size_t, const h_vector &, - const QueryEntries &, size_t, - const std::vector> *); -template size_t QueryEntries::InjectConditionsFromOnConditions(size_t, const h_vector &, - const QueryEntries &, size_t, - const std::vector> *); +template size_t QueryEntries::InjectConditionsFromOnConditions(size_t, const h_vector&, + const QueryEntries&, size_t, + const std::vector>*); +template size_t QueryEntries::InjectConditionsFromOnConditions(size_t, const h_vector&, + const QueryEntries&, size_t, + const std::vector>*); -size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std::string &fieldName, const std::string &joinedFieldName, - CondType condition, const QueryEntries &joinedQueryEntries, size_t injectedFrom, - size_t injectingInto, const std::vector> *indexesFrom) { +size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std::string& fieldName, const std::string& joinedFieldName, + CondType condition, const QueryEntries& joinedQueryEntries, size_t injectedFrom, + size_t injectingInto, const std::vector>* indexesFrom) { switch (condition) { case CondEq: case CondSet: @@ -581,7 +618,7 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: if (!joinedQueryEntries.Is(j)) { continue; } - const QueryEntry &qe = joinedQueryEntries.Get(j); + const QueryEntry& qe = joinedQueryEntries.Get(j); if (qe.IsInjectedFrom(injectingInto)) { continue; } @@ -670,7 +707,7 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: if (!qe.IsFieldIndexed() || !indexesFrom) { // TODO relax compare for not indexed after !1438 merge break; } - const CollateOpts &collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; + const CollateOpts& collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; Emplace(position, OpAnd, fieldName, CondLt, VariantArray{*std::max_element(qe.Values().begin(), qe.Values().end(), Variant::Less{collate})}, injectedFrom); @@ -705,7 +742,7 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: if (!qe.IsFieldIndexed() || !indexesFrom) { // TODO relax compare for not indexed after !1438 merge break; } - const CollateOpts &collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; + const CollateOpts& collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; Emplace(position, OpAnd, fieldName, CondLe, VariantArray{*std::max_element(qe.Values().begin(), qe.Values().end(), Variant::Less{collate})}, injectedFrom); @@ -744,7 +781,7 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: if (!qe.IsFieldIndexed() || !indexesFrom) { // TODO relax compare for not indexed after !1438 merge break; } - const CollateOpts &collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; + const CollateOpts& collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; Emplace(position, OpAnd, fieldName, CondGt, VariantArray{*std::min_element(qe.Values().begin(), qe.Values().end(), Variant::Less{collate})}, injectedFrom); @@ -779,7 +816,7 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: if (!qe.IsFieldIndexed() || !indexesFrom) { // TODO relax compare for not indexed after !1438 merge break; } - const CollateOpts &collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; + const CollateOpts& collate = (*indexesFrom)[qe.IndexNo()]->Opts().collateOpts_; Emplace(position, OpAnd, fieldName, CondGe, VariantArray{*std::min_element(qe.Values().begin(), qe.Values().end(), Variant::Less{collate})}, injectedFrom); @@ -822,52 +859,60 @@ size_t QueryEntries::injectConditionsFromOnCondition(size_t position, const std: } template -std::string QueryJoinEntry::DumpCondition(const JS &joinedSelector, bool needOp) const { +std::string QueryJoinEntry::DumpCondition(const JS& joinedSelector, bool needOp) const { WrSerializer ser; - const auto &q = joinedSelector.JoinQuery(); + const auto& q = joinedSelector.JoinQuery(); if (needOp) { ser << ' ' << op_ << ' '; } ser << q.NsName() << '.' << RightFieldName() << ' ' << InvertJoinCondition(condition_) << ' ' << LeftFieldName(); return std::string{ser.Slice()}; } -template std::string QueryJoinEntry::DumpCondition(const JoinedSelector &, bool) const; +template std::string QueryJoinEntry::DumpCondition(const JoinedSelector&, bool) const; -void QueryEntries::dumpEqualPositions(size_t level, WrSerializer &ser, const EqualPositions_t &equalPositions) { - for (const auto &eq : equalPositions) { +void QueryEntries::dumpEqualPositions(size_t level, WrSerializer& ser, const EqualPositions_t& equalPositions) { + for (const auto& eq : equalPositions) { for (size_t i = 0; i < level; ++i) { ser << " "; } ser << "equal_positions("; for (size_t i = 0, s = eq.size(); i < s; ++i) { - if (i != 0) ser << ", "; + if (i != 0) { + ser << ", "; + } ser << eq[i]; } ser << ")\n"; } } -std::string SubQueryEntry::Dump(const std::vector &subQueries) const { +std::string SubQueryEntry::Dump(const std::vector& subQueries) const { std::stringstream ss; ss << '(' << subQueries.at(QueryIndex()).GetSQL() << ") " << Condition() << ' '; - if (Values().size() > 1) ss << '['; + if (Values().size() > 1) { + ss << '['; + } for (size_t i = 0, s = Values().size(); i != s; ++i) { - if (i != 0) ss << ','; + if (i != 0) { + ss << ','; + } ss << '\'' << Values()[i].As() << '\''; } - if (Values().size() > 1) ss << ']'; + if (Values().size() > 1) { + ss << ']'; + } return ss.str(); } -std::string SubQueryFieldEntry::Dump(const std::vector &subQueries) const { +std::string SubQueryFieldEntry::Dump(const std::vector& subQueries) const { std::stringstream ss; ss << FieldName() << ' ' << Condition() << " (" << subQueries.at(QueryIndex()).GetSQL() << ')'; return ss.str(); } template -void QueryEntries::dump(size_t level, const_iterator begin, const_iterator end, const std::vector &joinedSelectors, - const std::vector &subQueries, WrSerializer &ser) { +void QueryEntries::dump(size_t level, const_iterator begin, const_iterator end, const std::vector& joinedSelectors, + const std::vector& subQueries, WrSerializer& ser) { for (const_iterator it = begin; it != end; ++it) { for (size_t i = 0; i < level; ++i) { ser << " "; @@ -875,9 +920,9 @@ void QueryEntries::dump(size_t level, const_iterator begin, const_iterator end, if (it != begin || it->operation != OpAnd) { ser << it->operation << ' '; } - it->Visit([&ser, subQueries](const SubQueryEntry &sqe) { ser << sqe.Dump(subQueries); }, - [&ser, subQueries](const SubQueryFieldEntry &sqe) { ser << sqe.Dump(subQueries); }, - [&](const QueryEntriesBracket &b) { + it->Visit([&ser, subQueries](const SubQueryEntry& sqe) { ser << sqe.Dump(subQueries); }, + [&ser, subQueries](const SubQueryFieldEntry& sqe) { ser << sqe.Dump(subQueries); }, + [&](const QueryEntriesBracket& b) { ser << "(\n"; dump(level + 1, it.cbegin(), it.cend(), joinedSelectors, subQueries, ser); dumpEqualPositions(level + 1, ser, b.equalPositions); @@ -886,15 +931,15 @@ void QueryEntries::dump(size_t level, const_iterator begin, const_iterator end, } ser << ")\n"; }, - [&ser](const QueryEntry &qe) { ser << qe.Dump() << '\n'; }, - [&joinedSelectors, &ser](const JoinQueryEntry &jqe) { ser << jqe.Dump(joinedSelectors) << '\n'; }, - [&ser](const BetweenFieldsQueryEntry &qe) { ser << qe.Dump() << '\n'; }, - [&ser](const AlwaysFalse &) { ser << "AlwaysFalse\n"; }, [&ser](const AlwaysTrue &) { ser << "AlwaysTrue\n"; }); + [&ser](const QueryEntry& qe) { ser << qe.Dump() << '\n'; }, + [&joinedSelectors, &ser](const JoinQueryEntry& jqe) { ser << jqe.Dump(joinedSelectors) << '\n'; }, + [&ser](const BetweenFieldsQueryEntry& qe) { ser << qe.Dump() << '\n'; }, + [&ser](const AlwaysFalse&) { ser << "AlwaysFalse\n"; }, [&ser](const AlwaysTrue&) { ser << "AlwaysTrue\n"; }); } } -template void QueryEntries::dump(size_t, const_iterator, const_iterator, const std::vector &, const std::vector &, - WrSerializer &); -template void QueryEntries::dump(size_t, const_iterator, const_iterator, const std::vector &, - const std::vector &, WrSerializer &); +template void QueryEntries::dump(size_t, const_iterator, const_iterator, const std::vector&, const std::vector&, + WrSerializer&); +template void QueryEntries::dump(size_t, const_iterator, const_iterator, const std::vector&, const std::vector&, + WrSerializer&); } // namespace reindexer diff --git a/cpp_src/core/query/queryentry.h b/cpp_src/core/query/queryentry.h index a18b4dc1e..e8c7969fe 100644 --- a/cpp_src/core/query/queryentry.h +++ b/cpp_src/core/query/queryentry.h @@ -22,14 +22,14 @@ class TagsMatcher; struct JoinQueryEntry { JoinQueryEntry(size_t joinIdx) noexcept : joinIndex{joinIdx} {} size_t joinIndex; - bool operator==(const JoinQueryEntry &other) const noexcept { return joinIndex == other.joinIndex; } - bool operator!=(const JoinQueryEntry &other) const noexcept { return !operator==(other); } + bool operator==(const JoinQueryEntry& other) const noexcept { return joinIndex == other.joinIndex; } + bool operator!=(const JoinQueryEntry& other) const noexcept { return !operator==(other); } template - std::string Dump(const std::vector &joinedSelectors) const; + std::string Dump(const std::vector& joinedSelectors) const; template - std::string DumpOnCondition(const std::vector &joinedSelectors) const; + std::string DumpOnCondition(const std::vector& joinedSelectors) const; }; class QueryField { @@ -37,33 +37,33 @@ class QueryField { using CompositeTypesVecT = h_vector; template - explicit QueryField(Str &&fieldName) noexcept : fieldName_{std::forward(fieldName)} {} - QueryField(std::string &&fieldName, int idxNo, FieldsSet fields, KeyValueType fieldType, - std::vector &&compositeFieldsTypes); - QueryField(QueryField &&) noexcept = default; - QueryField(const QueryField &) = default; - QueryField &operator=(QueryField &&) noexcept = default; + explicit QueryField(Str&& fieldName) noexcept : fieldName_{std::forward(fieldName)} {} + QueryField(std::string&& fieldName, int idxNo, FieldsSet fields, KeyValueType fieldType, + std::vector&& compositeFieldsTypes); + QueryField(QueryField&&) noexcept = default; + QueryField(const QueryField&) = default; + QueryField& operator=(QueryField&&) noexcept = default; - [[nodiscard]] bool operator==(const QueryField &) const noexcept; - [[nodiscard]] bool operator!=(const QueryField &other) const noexcept { return !operator==(other); } + [[nodiscard]] bool operator==(const QueryField&) const noexcept; + [[nodiscard]] bool operator!=(const QueryField& other) const noexcept { return !operator==(other); } [[nodiscard]] int IndexNo() const noexcept { return idxNo_; } [[nodiscard]] bool IsFieldIndexed() const noexcept { return idxNo_ >= 0; } [[nodiscard]] bool FieldsHaveBeenSet() const noexcept { return idxNo_ != IndexValueType::NotSet; } - [[nodiscard]] const FieldsSet &Fields() const & noexcept { return fieldsSet_; } - [[nodiscard]] const std::string &FieldName() const & noexcept { return fieldName_; } + [[nodiscard]] const FieldsSet& Fields() const& noexcept { return fieldsSet_; } + [[nodiscard]] const std::string& FieldName() const& noexcept { return fieldName_; } [[nodiscard]] KeyValueType FieldType() const noexcept { return fieldType_; } [[nodiscard]] KeyValueType SelectType() const noexcept { return selectType_; } - [[nodiscard]] const CompositeTypesVecT &CompositeFieldsTypes() const & noexcept { return compositeFieldsTypes_; } + [[nodiscard]] const CompositeTypesVecT& CompositeFieldsTypes() const& noexcept { return compositeFieldsTypes_; } [[nodiscard]] bool HaveEmptyField() const noexcept; - void SetField(FieldsSet &&fields) &; - void SetIndexData(int idxNo, FieldsSet &&fields, KeyValueType fieldType, KeyValueType selectType, - CompositeTypesVecT &&compositeFieldsTypes) &; + void SetField(FieldsSet&& fields) &; + void SetIndexData(int idxNo, FieldsSet&& fields, KeyValueType fieldType, KeyValueType selectType, + CompositeTypesVecT&& compositeFieldsTypes) &; - QueryField &operator=(const QueryField &) = delete; - auto Fields() const && = delete; - auto FieldName() const && = delete; - auto CompositeFieldsTypes() const && = delete; + QueryField& operator=(const QueryField&) = delete; + auto Fields() const&& = delete; + auto FieldName() const&& = delete; + auto CompositeFieldsTypes() const&& = delete; private: std::string fieldName_; @@ -81,9 +81,9 @@ enum class VerifyQueryEntryFlags : unsigned { null = 0u, ignoreEmptyValues = 1u } template -void VerifyQueryEntryValues(CondType, const VariantArray &); -extern template void VerifyQueryEntryValues(CondType, const VariantArray &); -extern template void VerifyQueryEntryValues(CondType, const VariantArray &); +void VerifyQueryEntryValues(CondType, const VariantArray&); +extern template void VerifyQueryEntryValues(CondType, const VariantArray&); +extern template void VerifyQueryEntryValues(CondType, const VariantArray&); class QueryEntry : private QueryField { public: @@ -94,25 +94,25 @@ class QueryEntry : private QueryField { static constexpr unsigned kDefaultOffset = 0; template && std::is_constructible_v> * = nullptr> - QueryEntry(Str &&fieldName, CondType cond, VA &&v, size_t injectedFrom = NotInjected) + std::enable_if_t && std::is_constructible_v>* = nullptr> + QueryEntry(Str&& fieldName, CondType cond, VA&& v, size_t injectedFrom = NotInjected) : QueryField{std::forward(fieldName)}, values_{std::forward(v)}, condition_{cond}, injectedFrom_{injectedFrom} { Verify(); } template - QueryEntry(Str &&fieldName, DistinctTag) : QueryField{std::forward(fieldName)}, condition_{CondAny}, distinct_{true} { + QueryEntry(Str&& fieldName, DistinctTag) : QueryField{std::forward(fieldName)}, condition_{CondAny}, distinct_{true} { Verify(); } - template > * = nullptr> - QueryEntry(QueryField &&field, CondType cond, VA &&v) : QueryField{std::move(field)}, values_{std::forward(v)}, condition_{cond} { + template >* = nullptr> + QueryEntry(QueryField&& field, CondType cond, VA&& v) : QueryField{std::move(field)}, values_{std::forward(v)}, condition_{cond} { Verify(); } - QueryEntry(QueryField &&field, CondType cond, IgnoreEmptyValues) : QueryField{std::move(field)}, condition_{cond} { + QueryEntry(QueryField&& field, CondType cond, IgnoreEmptyValues) : QueryField{std::move(field)}, condition_{cond} { verifyIgnoringEmptyValues(); } [[nodiscard]] CondType Condition() const noexcept { return condition_; } - [[nodiscard]] const VariantArray &Values() const & noexcept { return values_; } - [[nodiscard]] VariantArray &&Values() && noexcept { return std::move(values_); } + [[nodiscard]] const VariantArray& Values() const& noexcept { return values_; } + [[nodiscard]] VariantArray&& Values() && noexcept { return std::move(values_); } [[nodiscard]] auto UpdatableValues(IgnoreEmptyValues) & noexcept { return VerifyingUpdater{*this}; } @@ -132,31 +132,31 @@ class QueryEntry : private QueryField { using QueryField::SetField; using QueryField::SetIndexData; using QueryField::HaveEmptyField; - void SetCondAndValues(CondType cond, VariantArray &&values) { + void SetCondAndValues(CondType cond, VariantArray&& values) { VerifyQueryEntryValues(cond, values); condition_ = cond; values_ = std::move(values); } - const QueryField &FieldData() const & noexcept { return static_cast(*this); } - QueryField &FieldData() & noexcept { return static_cast(*this); } + const QueryField& FieldData() const& noexcept { return static_cast(*this); } + QueryField& FieldData() & noexcept { return static_cast(*this); } void ConvertValuesToFieldType() & { - for (Variant &v : values_) { + for (Variant& v : values_) { v.convert(SelectType()); } } - void ConvertValuesToFieldType(const PayloadType &pt) & { + void ConvertValuesToFieldType(const PayloadType& pt) & { if (SelectType().Is() || Condition() == CondDWithin) { return; } - for (Variant &v : values_) { + for (Variant& v : values_) { v.convert(SelectType(), &pt, &Fields()); } } void Verify() const { VerifyQueryEntryValues(condition_, values_); } - [[nodiscard]] bool operator==(const QueryEntry &) const noexcept; - [[nodiscard]] bool operator!=(const QueryEntry &other) const noexcept { return !operator==(other); } + [[nodiscard]] bool operator==(const QueryEntry&) const noexcept; + [[nodiscard]] bool operator!=(const QueryEntry& other) const noexcept { return !operator==(other); } [[nodiscard]] std::string Dump() const; [[nodiscard]] std::string DumpBrief() const; @@ -164,8 +164,8 @@ class QueryEntry : private QueryField { [[nodiscard]] bool IsInjectedFrom(size_t joinedQueryNo) const noexcept { return injectedFrom_ == joinedQueryNo; } void InjectedFrom(size_t joinedQueryNo) noexcept { injectedFrom_ = joinedQueryNo; } - auto Values() const && = delete; - auto FieldData() const && = delete; + auto Values() const&& = delete; + auto FieldData() const&& = delete; private: void verifyIgnoringEmptyValues() const { VerifyQueryEntryValues(condition_, values_); } @@ -180,48 +180,48 @@ class QueryEntry : private QueryField { class BetweenFieldsQueryEntry { public: template - BetweenFieldsQueryEntry(StrL &&fstIdx, CondType cond, StrR &&sndIdx) + BetweenFieldsQueryEntry(StrL&& fstIdx, CondType cond, StrR&& sndIdx) : leftField_{std::forward(fstIdx)}, rightField_{std::forward(sndIdx)}, condition_{cond} { if (condition_ == CondAny || condition_ == CondEmpty || condition_ == CondDWithin) { throw Error{errLogic, "Condition '%s' is inapplicable between two fields", CondTypeToStr(condition_)}; } } - [[nodiscard]] bool operator==(const BetweenFieldsQueryEntry &) const noexcept; - [[nodiscard]] bool operator!=(const BetweenFieldsQueryEntry &other) const noexcept { return !operator==(other); } + [[nodiscard]] bool operator==(const BetweenFieldsQueryEntry&) const noexcept; + [[nodiscard]] bool operator!=(const BetweenFieldsQueryEntry& other) const noexcept { return !operator==(other); } [[nodiscard]] CondType Condition() const noexcept { return condition_; } [[nodiscard]] int LeftIdxNo() const noexcept { return leftField_.IndexNo(); } [[nodiscard]] int RightIdxNo() const noexcept { return rightField_.IndexNo(); } - [[nodiscard]] const std::string &LeftFieldName() const & noexcept { return leftField_.FieldName(); } - [[nodiscard]] const std::string &RightFieldName() const & noexcept { return rightField_.FieldName(); } - [[nodiscard]] const FieldsSet &LeftFields() const & noexcept { return leftField_.Fields(); } - [[nodiscard]] const FieldsSet &RightFields() const & noexcept { return rightField_.Fields(); } + [[nodiscard]] const std::string& LeftFieldName() const& noexcept { return leftField_.FieldName(); } + [[nodiscard]] const std::string& RightFieldName() const& noexcept { return rightField_.FieldName(); } + [[nodiscard]] const FieldsSet& LeftFields() const& noexcept { return leftField_.Fields(); } + [[nodiscard]] const FieldsSet& RightFields() const& noexcept { return rightField_.Fields(); } [[nodiscard]] KeyValueType LeftFieldType() const noexcept { return leftField_.FieldType(); } [[nodiscard]] KeyValueType RightFieldType() const noexcept { return rightField_.FieldType(); } - [[nodiscard]] const QueryField::CompositeTypesVecT &LeftCompositeFieldsTypes() const & noexcept { + [[nodiscard]] const QueryField::CompositeTypesVecT& LeftCompositeFieldsTypes() const& noexcept { return leftField_.CompositeFieldsTypes(); } - [[nodiscard]] const QueryField::CompositeTypesVecT &RightCompositeFieldsTypes() const & noexcept { + [[nodiscard]] const QueryField::CompositeTypesVecT& RightCompositeFieldsTypes() const& noexcept { return rightField_.CompositeFieldsTypes(); } - [[nodiscard]] const QueryField &LeftFieldData() const & noexcept { return leftField_; } - [[nodiscard]] QueryField &LeftFieldData() & noexcept { return leftField_; } - [[nodiscard]] const QueryField &RightFieldData() const & noexcept { return rightField_; } - [[nodiscard]] QueryField &RightFieldData() & noexcept { return rightField_; } + [[nodiscard]] const QueryField& LeftFieldData() const& noexcept { return leftField_; } + [[nodiscard]] QueryField& LeftFieldData() & noexcept { return leftField_; } + [[nodiscard]] const QueryField& RightFieldData() const& noexcept { return rightField_; } + [[nodiscard]] QueryField& RightFieldData() & noexcept { return rightField_; } [[nodiscard]] bool FieldsHaveBeenSet() const noexcept { return leftField_.FieldsHaveBeenSet() && rightField_.FieldsHaveBeenSet(); } [[nodiscard]] bool IsLeftFieldIndexed() const noexcept { return leftField_.IsFieldIndexed(); } [[nodiscard]] bool IsRightFieldIndexed() const noexcept { return rightField_.IsFieldIndexed(); } [[nodiscard]] std::string Dump() const; - auto LeftFieldName() const && = delete; - auto RightFieldName() const && = delete; - auto LeftFields() const && = delete; - auto RightFields() const && = delete; - auto LeftCompositeFieldsTypes() const && = delete; - auto RightCompositeFieldsTypes() const && = delete; - auto LeftFieldData() const && = delete; - auto RightFieldData() const && = delete; + auto LeftFieldName() const&& = delete; + auto RightFieldName() const&& = delete; + auto LeftFields() const&& = delete; + auto RightFields() const&& = delete; + auto LeftCompositeFieldsTypes() const&& = delete; + auto RightCompositeFieldsTypes() const&& = delete; + auto LeftFieldData() const&& = delete; + auto RightFieldData() const&& = delete; private: QueryField leftField_; @@ -241,7 +241,7 @@ using EqualPositions_t = std::vector; struct QueryEntriesBracket : public Bracket { using Bracket::Bracket; - bool operator==(const QueryEntriesBracket &other) const noexcept { + bool operator==(const QueryEntriesBracket& other) const noexcept { return Bracket::operator==(other) && equalPositions == other.equalPositions; } EqualPositions_t equalPositions; @@ -249,19 +249,19 @@ struct QueryEntriesBracket : public Bracket { class SubQueryEntry { public: - SubQueryEntry(CondType cond, size_t qIdx, VariantArray &&values) : condition_{cond}, queryIndex_{qIdx}, values_{std::move(values)} { + SubQueryEntry(CondType cond, size_t qIdx, VariantArray&& values) : condition_{cond}, queryIndex_{qIdx}, values_{std::move(values)} { VerifyQueryEntryValues(condition_, values_); } [[nodiscard]] CondType Condition() const noexcept { return condition_; } [[nodiscard]] size_t QueryIndex() const noexcept { return queryIndex_; } - [[nodiscard]] const VariantArray &Values() const & noexcept { return values_; } - [[nodiscard]] bool operator==(const SubQueryEntry &other) const noexcept { + [[nodiscard]] const VariantArray& Values() const& noexcept { return values_; } + [[nodiscard]] bool operator==(const SubQueryEntry& other) const noexcept { return condition_ == other.condition_ && queryIndex_ == other.queryIndex_; } - [[nodiscard]] bool operator!=(const SubQueryEntry &other) const noexcept { return !operator==(other); } - [[nodiscard]] std::string Dump(const std::vector &subQueries) const; + [[nodiscard]] bool operator!=(const SubQueryEntry& other) const noexcept { return !operator==(other); } + [[nodiscard]] std::string Dump(const std::vector& subQueries) const; - auto Values() const && = delete; + auto Values() const&& = delete; private: CondType condition_; @@ -273,22 +273,22 @@ class SubQueryEntry { class SubQueryFieldEntry { public: template - SubQueryFieldEntry(Str &&field, CondType cond, size_t qIdx) : field_{std::forward(field)}, condition_{cond}, queryIndex_{qIdx} { + SubQueryFieldEntry(Str&& field, CondType cond, size_t qIdx) : field_{std::forward(field)}, condition_{cond}, queryIndex_{qIdx} { if (cond == CondAny || cond == CondEmpty) { throw Error{errQueryExec, "Condition %s with field and subquery", cond == CondAny ? "Any" : "Empty"}; } } - [[nodiscard]] const std::string &FieldName() const & noexcept { return field_; } - [[nodiscard]] std::string &&FieldName() && noexcept { return std::move(field_); } + [[nodiscard]] const std::string& FieldName() const& noexcept { return field_; } + [[nodiscard]] std::string&& FieldName() && noexcept { return std::move(field_); } [[nodiscard]] CondType Condition() const noexcept { return condition_; } [[nodiscard]] size_t QueryIndex() const noexcept { return queryIndex_; } - [[nodiscard]] bool operator==(const SubQueryFieldEntry &other) const noexcept { + [[nodiscard]] bool operator==(const SubQueryFieldEntry& other) const noexcept { return field_ == other.field_ && condition_ == other.condition_ && queryIndex_ == other.queryIndex_; } - [[nodiscard]] bool operator!=(const SubQueryFieldEntry &other) const noexcept { return !operator==(other); } - [[nodiscard]] std::string Dump(const std::vector &subQueries) const; + [[nodiscard]] bool operator!=(const SubQueryFieldEntry& other) const noexcept { return !operator==(other); } + [[nodiscard]] std::string Dump(const std::vector& subQueries) const; - auto FieldName() const && = delete; + auto FieldName() const&& = delete; private: std::string field_; @@ -300,17 +300,17 @@ class SubQueryFieldEntry { class UpdateEntry { public: template - UpdateEntry(Str &&c, VariantArray &&v, FieldModifyMode m = FieldModeSet, bool e = false) + UpdateEntry(Str&& c, VariantArray&& v, FieldModifyMode m = FieldModeSet, bool e = false) : column_(std::forward(c)), values_(std::move(v)), mode_(m), isExpression_(e) { if (column_.empty()) { throw Error{errParams, "Empty update column name"}; } } - bool operator==(const UpdateEntry &) const noexcept; - bool operator!=(const UpdateEntry &obj) const noexcept { return !operator==(obj); } + bool operator==(const UpdateEntry&) const noexcept; + bool operator!=(const UpdateEntry& obj) const noexcept { return !operator==(obj); } std::string_view Column() const noexcept { return column_; } - VariantArray const &Values() const noexcept { return values_; } - VariantArray &Values() noexcept { return values_; } + const VariantArray& Values() const noexcept { return values_; } + VariantArray& Values() noexcept { return values_; } FieldModifyMode Mode() const noexcept { return mode_; } void SetMode(FieldModifyMode m) noexcept { mode_ = m; } bool IsExpression() const noexcept { return isExpression_; } @@ -325,56 +325,56 @@ class UpdateEntry { class QueryJoinEntry { public: - QueryJoinEntry(OpType op, CondType cond, std::string &&leftFld, std::string &&rightFld, bool reverseNs = false) noexcept + QueryJoinEntry(OpType op, CondType cond, std::string&& leftFld, std::string&& rightFld, bool reverseNs = false) noexcept : leftField_{std::move(leftFld)}, rightField_{std::move(rightFld)}, op_{op}, condition_{cond}, reverseNamespacesOrder_{reverseNs} {} - [[nodiscard]] bool operator==(const QueryJoinEntry &) const noexcept; - [[nodiscard]] bool operator!=(const QueryJoinEntry &other) const noexcept { return !operator==(other); } + [[nodiscard]] bool operator==(const QueryJoinEntry&) const noexcept; + [[nodiscard]] bool operator!=(const QueryJoinEntry& other) const noexcept { return !operator==(other); } [[nodiscard]] bool IsLeftFieldIndexed() const noexcept { return leftField_.IsFieldIndexed(); } [[nodiscard]] bool IsRightFieldIndexed() const noexcept { return rightField_.IsFieldIndexed(); } [[nodiscard]] int LeftIdxNo() const noexcept { return leftField_.IndexNo(); } [[nodiscard]] int RightIdxNo() const noexcept { return rightField_.IndexNo(); } - [[nodiscard]] const FieldsSet &LeftFields() const & noexcept { return leftField_.Fields(); } - [[nodiscard]] const FieldsSet &RightFields() const & noexcept { return rightField_.Fields(); } + [[nodiscard]] const FieldsSet& LeftFields() const& noexcept { return leftField_.Fields(); } + [[nodiscard]] const FieldsSet& RightFields() const& noexcept { return rightField_.Fields(); } [[nodiscard]] KeyValueType LeftFieldType() const noexcept { return leftField_.FieldType(); } [[nodiscard]] KeyValueType RightFieldType() const noexcept { return rightField_.FieldType(); } - [[nodiscard]] const QueryField::CompositeTypesVecT &LeftCompositeFieldsTypes() const & noexcept { + [[nodiscard]] const QueryField::CompositeTypesVecT& LeftCompositeFieldsTypes() const& noexcept { return leftField_.CompositeFieldsTypes(); } - [[nodiscard]] const QueryField::CompositeTypesVecT &RightCompositeFieldsTypes() const & noexcept { + [[nodiscard]] const QueryField::CompositeTypesVecT& RightCompositeFieldsTypes() const& noexcept { return rightField_.CompositeFieldsTypes(); } [[nodiscard]] OpType Operation() const noexcept { return op_; } [[nodiscard]] CondType Condition() const noexcept { return condition_; } - [[nodiscard]] const std::string &LeftFieldName() const & noexcept { return leftField_.FieldName(); } - [[nodiscard]] const std::string &RightFieldName() const & noexcept { return rightField_.FieldName(); } + [[nodiscard]] const std::string& LeftFieldName() const& noexcept { return leftField_.FieldName(); } + [[nodiscard]] const std::string& RightFieldName() const& noexcept { return rightField_.FieldName(); } [[nodiscard]] bool ReverseNamespacesOrder() const noexcept { return reverseNamespacesOrder_; } - [[nodiscard]] const QueryField &LeftFieldData() const & noexcept { return leftField_; } - [[nodiscard]] QueryField &LeftFieldData() & noexcept { return leftField_; } - [[nodiscard]] const QueryField &RightFieldData() const & noexcept { return rightField_; } - [[nodiscard]] QueryField &RightFieldData() & noexcept { return rightField_; } - void SetLeftIndexData(int idxNo, FieldsSet &&fields, KeyValueType fieldType, KeyValueType selectType, - QueryField::CompositeTypesVecT &&compositeFieldsTypes) & { + [[nodiscard]] const QueryField& LeftFieldData() const& noexcept { return leftField_; } + [[nodiscard]] QueryField& LeftFieldData() & noexcept { return leftField_; } + [[nodiscard]] const QueryField& RightFieldData() const& noexcept { return rightField_; } + [[nodiscard]] QueryField& RightFieldData() & noexcept { return rightField_; } + void SetLeftIndexData(int idxNo, FieldsSet&& fields, KeyValueType fieldType, KeyValueType selectType, + QueryField::CompositeTypesVecT&& compositeFieldsTypes) & { leftField_.SetIndexData(idxNo, std::move(fields), fieldType, selectType, std::move(compositeFieldsTypes)); } - void SetRightIndexData(int idxNo, FieldsSet &&fields, KeyValueType fieldType, KeyValueType selectType, - QueryField::CompositeTypesVecT &&compositeFieldsTypes) & { + void SetRightIndexData(int idxNo, FieldsSet&& fields, KeyValueType fieldType, KeyValueType selectType, + QueryField::CompositeTypesVecT&& compositeFieldsTypes) & { rightField_.SetIndexData(idxNo, std::move(fields), fieldType, selectType, std::move(compositeFieldsTypes)); } - void SetLeftField(FieldsSet &&fields) & { leftField_.SetField(std::move(fields)); } - void SetRightField(FieldsSet &&fields) & { rightField_.SetField(std::move(fields)); } + void SetLeftField(FieldsSet&& fields) & { leftField_.SetField(std::move(fields)); } + void SetRightField(FieldsSet&& fields) & { rightField_.SetField(std::move(fields)); } [[nodiscard]] bool FieldsHaveBeenSet() const noexcept { return leftField_.FieldsHaveBeenSet() && rightField_.FieldsHaveBeenSet(); } template - std::string DumpCondition(const JS &joinedSelector, bool needOp = false) const; + std::string DumpCondition(const JS& joinedSelector, bool needOp = false) const; - auto LeftFields() const && = delete; - auto RightFields() const && = delete; - auto LeftCompositeFieldsTypes() const && = delete; - auto RightCompositeFieldsTypes() const && = delete; - auto LeftFieldName() const && = delete; - auto RightFieldName() const && = delete; - auto LeftFieldData() const && = delete; - auto RightFieldData() const && = delete; + auto LeftFields() const&& = delete; + auto RightFields() const&& = delete; + auto LeftCompositeFieldsTypes() const&& = delete; + auto RightCompositeFieldsTypes() const&& = delete; + auto LeftFieldName() const&& = delete; + auto RightFieldName() const&& = delete; + auto LeftFieldData() const&& = delete; + auto RightFieldData() const&& = delete; private: QueryField leftField_; @@ -393,25 +393,25 @@ class QueryEntries : public ExpressionTree { using Base = ExpressionTree; - QueryEntries(Base &&b) : Base{std::move(b)} {} + QueryEntries(Base&& b) : Base{std::move(b)} {} public: QueryEntries() = default; - QueryEntries(QueryEntries &&) = default; - QueryEntries(const QueryEntries &) = default; - QueryEntries &operator=(QueryEntries &&) = default; - - void ToDsl(const Query &parentQuery, JsonBuilder &builder) const { return toDsl(cbegin(), cend(), parentQuery, builder); } - void WriteSQLWhere(const Query &parentQuery, WrSerializer &, bool stripArgs) const; - void Serialize(WrSerializer &ser, const std::vector &subQueries) const { serialize(cbegin(), cend(), ser, subQueries); } - bool CheckIfSatisfyConditions(const ConstPayload &pl) const { return checkIfSatisfyConditions(cbegin(), cend(), pl); } - static bool CheckIfSatisfyCondition(const VariantArray &lValues, CondType, const VariantArray &rValues); + QueryEntries(QueryEntries&&) = default; + QueryEntries(const QueryEntries&) = default; + QueryEntries& operator=(QueryEntries&&) = default; + + void ToDsl(const Query& parentQuery, JsonBuilder& builder) const { return toDsl(cbegin(), cend(), parentQuery, builder); } + void WriteSQLWhere(const Query& parentQuery, WrSerializer&, bool stripArgs) const; + void Serialize(WrSerializer& ser, const std::vector& subQueries) const { serialize(cbegin(), cend(), ser, subQueries); } + bool CheckIfSatisfyConditions(const ConstPayload& pl) const { return checkIfSatisfyConditions(cbegin(), cend(), pl); } + static bool CheckIfSatisfyCondition(const VariantArray& lValues, CondType, const VariantArray& rValues); template - [[nodiscard]] size_t InjectConditionsFromOnConditions(size_t position, const h_vector &joinEntries, - const QueryEntries &joinedQueryEntries, size_t joinedQueryNo, - const std::vector> *indexesFrom); + [[nodiscard]] size_t InjectConditionsFromOnConditions(size_t position, const h_vector& joinEntries, + const QueryEntries& joinedQueryEntries, size_t joinedQueryNo, + const std::vector>* indexesFrom); template - std::string Dump(const std::vector &joinedSelectors, const std::vector &subQueries) const { + std::string Dump(const std::vector& joinedSelectors, const std::vector& subQueries) const { WrSerializer ser; dump(0, cbegin(), cend(), joinedSelectors, subQueries, ser); dumpEqualPositions(0, ser, equalPositions); @@ -421,35 +421,35 @@ class QueryEntries : public ExpressionTree &subQueries); - static void serialize(CondType, const VariantArray &values, WrSerializer &); - static bool checkIfSatisfyConditions(const_iterator begin, const_iterator end, const ConstPayload &); - static bool checkIfSatisfyCondition(const QueryEntry &, const ConstPayload &); - static bool checkIfSatisfyCondition(const BetweenFieldsQueryEntry &, const ConstPayload &); - [[nodiscard]] size_t injectConditionsFromOnCondition(size_t position, const std::string &fieldName, const std::string &joinedFieldName, - CondType, const QueryEntries &joinedQueryEntries, size_t injectedFrom, - size_t injectingInto, const std::vector> *indexesFrom); + static void toDsl(const_iterator it, const_iterator to, const Query& parentQuery, JsonBuilder&); + static void writeSQL(const Query& parentQuery, const_iterator from, const_iterator to, WrSerializer&, bool stripArgs); + static void serialize(const_iterator it, const_iterator to, WrSerializer&, const std::vector& subQueries); + static void serialize(CondType, const VariantArray& values, WrSerializer&); + static bool checkIfSatisfyConditions(const_iterator begin, const_iterator end, const ConstPayload&); + static bool checkIfSatisfyCondition(const QueryEntry&, const ConstPayload&); + static bool checkIfSatisfyCondition(const BetweenFieldsQueryEntry&, const ConstPayload&); + [[nodiscard]] size_t injectConditionsFromOnCondition(size_t position, const std::string& fieldName, const std::string& joinedFieldName, + CondType, const QueryEntries& joinedQueryEntries, size_t injectedFrom, + size_t injectingInto, const std::vector>* indexesFrom); protected: - static void dumpEqualPositions(size_t level, WrSerializer &, const EqualPositions_t &); + static void dumpEqualPositions(size_t level, WrSerializer&, const EqualPositions_t&); template - static void dump(size_t level, const_iterator begin, const_iterator end, const std::vector &joinedSelectors, - const std::vector &subQueries, WrSerializer &); + static void dump(size_t level, const_iterator begin, const_iterator end, const std::vector& joinedSelectors, + const std::vector& subQueries, WrSerializer&); }; extern template size_t QueryEntries::InjectConditionsFromOnConditions( - size_t, const h_vector &, const QueryEntries &, size_t, const std::vector> *); + size_t, const h_vector&, const QueryEntries&, size_t, const std::vector>*); extern template size_t QueryEntries::InjectConditionsFromOnConditions( - size_t, const h_vector &, const QueryEntries &, size_t, const std::vector> *); + size_t, const h_vector&, const QueryEntries&, size_t, const std::vector>*); struct SortingEntry { SortingEntry() noexcept = default; template - SortingEntry(Str &&e, bool d) noexcept : expression(std::forward(e)), desc(d) {} - bool operator==(const SortingEntry &) const noexcept; - bool operator!=(const SortingEntry &se) const noexcept { return !operator==(se); } + SortingEntry(Str&& e, bool d) noexcept : expression(std::forward(e)), desc(d) {} + bool operator==(const SortingEntry&) const noexcept; + bool operator!=(const SortingEntry& se) const noexcept { return !operator==(se); } std::string expression; bool desc = false; int index = IndexValueType::NotSet; @@ -459,16 +459,16 @@ struct SortingEntries : public h_vector {}; class AggregateEntry { public: - AggregateEntry(AggType type, h_vector &&fields, SortingEntries &&sort = {}, unsigned limit = QueryEntry::kDefaultLimit, + AggregateEntry(AggType type, h_vector&& fields, SortingEntries&& sort = {}, unsigned limit = QueryEntry::kDefaultLimit, unsigned offset = QueryEntry::kDefaultOffset); - [[nodiscard]] bool operator==(const AggregateEntry &) const noexcept; - [[nodiscard]] bool operator!=(const AggregateEntry &ae) const noexcept { return !operator==(ae); } + [[nodiscard]] bool operator==(const AggregateEntry&) const noexcept; + [[nodiscard]] bool operator!=(const AggregateEntry& ae) const noexcept { return !operator==(ae); } [[nodiscard]] AggType Type() const noexcept { return type_; } - [[nodiscard]] const h_vector &Fields() const noexcept { return fields_; } - [[nodiscard]] const SortingEntries &Sorting() const noexcept { return sortingEntries_; } + [[nodiscard]] const h_vector& Fields() const noexcept { return fields_; } + [[nodiscard]] const SortingEntries& Sorting() const noexcept { return sortingEntries_; } [[nodiscard]] unsigned Limit() const noexcept { return limit_; } [[nodiscard]] unsigned Offset() const noexcept { return offset_; } - void AddSortingEntry(SortingEntry &&); + void AddSortingEntry(SortingEntry&&); void SetLimit(unsigned); void SetOffset(unsigned); diff --git a/cpp_src/core/query/sql/sqlencoder.cc b/cpp_src/core/query/sql/sqlencoder.cc index 9a4b6298a..aabbbf98b 100644 --- a/cpp_src/core/query/sql/sqlencoder.cc +++ b/cpp_src/core/query/sql/sqlencoder.cc @@ -10,7 +10,7 @@ enum class NeedQuote : bool { No = false, Yes = true }; template -static void indexToSql(std::string_view index, reindexer::WrSerializer &ser) { +static void indexToSql(std::string_view index, reindexer::WrSerializer& ser) { if (needQuote == NeedQuote::No || index.find('+') == std::string::npos) { ser << index; } else { @@ -18,7 +18,7 @@ static void indexToSql(std::string_view index, reindexer::WrSerializer &ser) { } } -static reindexer::WrSerializer &stringToSql(std::string_view str, reindexer::WrSerializer &ser) { +static reindexer::WrSerializer& stringToSql(std::string_view str, reindexer::WrSerializer& ser) { ser << '\''; for (auto c : str) { switch (c) { @@ -53,9 +53,9 @@ static reindexer::WrSerializer &stringToSql(std::string_view str, reindexer::WrS namespace reindexer { -void SQLEncoder::DumpSingleJoinQuery(size_t idx, WrSerializer &ser, bool stripArgs) const { +void SQLEncoder::DumpSingleJoinQuery(size_t idx, WrSerializer& ser, bool stripArgs) const { assertrx(idx < query_.GetJoinQueries().size()); - const auto &jq = query_.GetJoinQueries()[idx]; + const auto& jq = query_.GetJoinQueries()[idx]; ser << jq.joinType; if (jq.Entries().Empty() && !jq.HasLimit() && jq.sortingEntries_.empty()) { ser << ' ' << jq.NsName() << " ON "; @@ -64,8 +64,10 @@ void SQLEncoder::DumpSingleJoinQuery(size_t idx, WrSerializer &ser, bool stripAr jq.GetSQL(ser, stripArgs); ser << ") ON "; } - if (jq.joinEntries_.size() != 1) ser << "("; - for (auto &e : jq.joinEntries_) { + if (jq.joinEntries_.size() != 1) { + ser << "("; + } + for (auto& e : jq.joinEntries_) { if (&e != &*jq.joinEntries_.begin()) { ser << ' ' << e.Operation() << ' '; } @@ -76,10 +78,12 @@ void SQLEncoder::DumpSingleJoinQuery(size_t idx, WrSerializer &ser, bool stripAr ser << query_.NsName() << '.' << e.LeftFieldName() << ' ' << e.Condition() << ' ' << jq.NsName() << '.' << e.RightFieldName(); } } - if (jq.joinEntries_.size() != 1) ser << ')'; + if (jq.joinEntries_.size() != 1) { + ser << ')'; + } } -void SQLEncoder::dumpJoined(WrSerializer &ser, bool stripArgs) const { +void SQLEncoder::dumpJoined(WrSerializer& ser, bool stripArgs) const { for (size_t i = 0; i < query_.GetJoinQueries().size(); ++i) { if (query_.GetJoinQueries()[i].joinType == JoinType::LeftJoin) { ser << ' '; @@ -88,8 +92,8 @@ void SQLEncoder::dumpJoined(WrSerializer &ser, bool stripArgs) const { } } -void SQLEncoder::dumpMerged(WrSerializer &ser, bool stripArgs) const { - for (auto &me : query_.GetMergeQueries()) { +void SQLEncoder::dumpMerged(WrSerializer& ser, bool stripArgs) const { + for (auto& me : query_.GetMergeQueries()) { ser << ' ' << me.joinType << "( "; me.GetSQL(ser, stripArgs); ser << ')'; @@ -98,16 +102,20 @@ void SQLEncoder::dumpMerged(WrSerializer &ser, bool stripArgs) const { static std::string escapeQuotes(std::string str) { for (size_t i = 0; i < str.size(); ++i) { - if (str[i] == '\'' && (i == 0 || str[i - 1] != '\\')) str.insert(i++, 1, '\\'); + if (str[i] == '\'' && (i == 0 || str[i - 1] != '\\')) { + str.insert(i++, 1, '\\'); + } } return str; } -void SQLEncoder::dumpOrderBy(WrSerializer &ser, bool stripArgs) const { - if (query_.sortingEntries_.empty()) return; +void SQLEncoder::dumpOrderBy(WrSerializer& ser, bool stripArgs) const { + if (query_.sortingEntries_.empty()) { + return; + } ser << " ORDER BY "; for (size_t i = 0; i < query_.sortingEntries_.size(); ++i) { - const SortingEntry &sortingEntry(query_.sortingEntries_[i]); + const SortingEntry& sortingEntry(query_.sortingEntries_[i]); if (query_.forcedSortOrder_.empty()) { ser << '\'' << escapeQuotes(sortingEntry.expression) << '\''; } else { @@ -115,7 +123,7 @@ void SQLEncoder::dumpOrderBy(WrSerializer &ser, bool stripArgs) const { if (stripArgs) { ser << '?'; } else { - for (auto &v : query_.forcedSortOrder_) { + for (auto& v : query_.forcedSortOrder_) { ser << ", "; v.Dump(ser); } @@ -123,23 +131,27 @@ void SQLEncoder::dumpOrderBy(WrSerializer &ser, bool stripArgs) const { ser << ")"; } ser << (sortingEntry.desc ? " DESC" : ""); - if (i != query_.sortingEntries_.size() - 1) ser << ", "; + if (i != query_.sortingEntries_.size() - 1) { + ser << ", "; + } } } -void SQLEncoder::dumpEqualPositions(WrSerializer &ser, const EqualPositions_t &equalPositions) const { - for (const auto &ep : equalPositions) { +void SQLEncoder::dumpEqualPositions(WrSerializer& ser, const EqualPositions_t& equalPositions) const { + for (const auto& ep : equalPositions) { assertrx(ep.size() > 1); ser << " equal_position("; for (size_t i = 0; i < ep.size(); ++i) { - if (i != 0) ser << ", "; + if (i != 0) { + ser << ", "; + } ser << ep[i]; } ser << ")"; } } -WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { +WrSerializer& SQLEncoder::GetSQL(WrSerializer& ser, bool stripArgs) const { switch (realQueryType_) { case QuerySelect: { ser << "SELECT "; @@ -148,23 +160,29 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { ser << "RANK()"; needComma = true; } - for (const auto &a : query_.aggregations_) { + for (const auto& a : query_.aggregations_) { if (needComma) { ser << ", "; } else { needComma = true; } ser << AggTypeToStr(a.Type()) << "("; - for (const auto &f : a.Fields()) { - if (&f != &*a.Fields().begin()) ser << ", "; + for (const auto& f : a.Fields()) { + if (&f != &*a.Fields().begin()) { + ser << ", "; + } ser << f; } - for (const auto &se : a.Sorting()) { + for (const auto& se : a.Sorting()) { ser << " ORDER BY " << '\'' << escapeQuotes(se.expression) << '\'' << (se.desc ? " DESC" : " ASC"); } - if (a.Offset() != QueryEntry::kDefaultOffset && !stripArgs) ser << " OFFSET " << a.Offset(); - if (a.Limit() != QueryEntry::kDefaultLimit && !stripArgs) ser << " LIMIT " << a.Limit(); + if (a.Offset() != QueryEntry::kDefaultOffset && !stripArgs) { + ser << " OFFSET " << a.Offset(); + } + if (a.Limit() != QueryEntry::kDefaultLimit && !stripArgs) { + ser << " LIMIT " << a.Limit(); + } ser << ')'; } if (query_.aggregations_.empty() || (query_.aggregations_.size() == 1 && query_.aggregations_[0].Type() == AggDistinct)) { @@ -175,15 +193,19 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { } if (query_.SelectFilters().empty()) { if (query_.Limit() != 0 || !query_.HasCalcTotal()) { - if (needComma) ser << ", "; + if (needComma) { + ser << ", "; + } ser << '*'; if (query_.HasCalcTotal()) { needComma = true; } } } else { - for (const auto &filter : query_.SelectFilters()) { - if (filter == distinctIndex) continue; + for (const auto& filter : query_.SelectFilters()) { + if (filter == distinctIndex) { + continue; + } if (needComma) { ser << ", "; } else { @@ -194,9 +216,15 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { } } if (query_.HasCalcTotal()) { - if (needComma) ser << ", "; - if (query_.CalcTotal() == ModeAccurateTotal) ser << "COUNT(*)"; - if (query_.CalcTotal() == ModeCachedTotal) ser << "COUNT_CACHED(*)"; + if (needComma) { + ser << ", "; + } + if (query_.CalcTotal() == ModeAccurateTotal) { + ser << "COUNT(*)"; + } + if (query_.CalcTotal() == ModeCachedTotal) { + ser << "COUNT_CACHED(*)"; + } } ser << " FROM " << query_.NsName(); } break; @@ -204,7 +232,9 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { ser << "DELETE FROM " << query_.NsName(); break; case QueryUpdate: { - if (query_.UpdateFields().empty()) break; + if (query_.UpdateFields().empty()) { + break; + } ser << "UPDATE " << query_.NsName(); FieldModifyMode mode = query_.UpdateFields().front().Mode(); bool isUpdate = (mode == FieldModeSet || mode == FieldModeSetJson); @@ -213,15 +243,21 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { } else { ser << " DROP "; } - for (const UpdateEntry &field : query_.UpdateFields()) { - if (&field != &*query_.UpdateFields().begin()) ser << ','; + for (const UpdateEntry& field : query_.UpdateFields()) { + if (&field != &*query_.UpdateFields().begin()) { + ser << ','; + } ser << field.Column(); if (isUpdate) { ser << " = "; bool isArray = (field.Values().IsArrayValue() || field.Values().size() > 1); - if (isArray) ser << '['; - for (const Variant &v : field.Values()) { - if (&v != &*field.Values().begin()) ser << ','; + if (isArray) { + ser << '['; + } + for (const Variant& v : field.Values()) { + if (&v != &*field.Values().begin()) { + ser << ','; + } v.Type().EvaluateOneOf(overloaded{ [&](KeyValueType::String) { if (!field.IsExpression() && mode != FieldModeSetJson) { @@ -236,7 +272,9 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { ser << v.As(); }}); } - if (isArray) ser << "]"; + if (isArray) { + ser << "]"; + } } } break; @@ -253,15 +291,19 @@ WrSerializer &SQLEncoder::GetSQL(WrSerializer &ser, bool stripArgs) const { dumpMerged(ser, stripArgs); dumpOrderBy(ser, stripArgs); - if (query_.HasOffset() && !stripArgs) ser << " OFFSET " << query_.Offset(); - if (query_.HasLimit() && !stripArgs) ser << " LIMIT " << query_.Limit(); + if (query_.HasOffset() && !stripArgs) { + ser << " OFFSET " << query_.Offset(); + } + if (query_.HasLimit() && !stripArgs) { + ser << " LIMIT " << query_.Limit(); + } return ser; } constexpr static std::string_view kOpNames[] = {"-", "OR", "AND", "AND NOT"}; template -static void dumpCondWithValues(WrSerializer &ser, std::string_view fieldName, CondType cond, const VariantArray &values, bool stripArgs) { +static void dumpCondWithValues(WrSerializer& ser, std::string_view fieldName, CondType cond, const VariantArray& values, bool stripArgs) { switch (cond) { case CondDWithin: ser << "ST_DWithin("; @@ -301,21 +343,27 @@ static void dumpCondWithValues(WrSerializer &ser, std::string_view fieldName, Co if (stripArgs) { ser << '?'; } else { - if (values.size() != 1) ser << '('; - for (auto &v : values) { - if (&v != &values[0]) ser << ','; + if (values.size() != 1) { + ser << '('; + } + for (auto& v : values) { + if (&v != &values[0]) { + ser << ','; + } v.Type().EvaluateOneOf(overloaded{ [&](KeyValueType::String) { stringToSql(v.As(), ser); }, [&](KeyValueType::Uuid) { ser << '\'' << v.As() << '\''; }, [&](OneOf) { ser << v.As(); }}); } - if (values.size() != 1) ser << ")"; + if (values.size() != 1) { + ser << ")"; + } } } } -void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntries::const_iterator to, WrSerializer &ser, +void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntries::const_iterator to, WrSerializer& ser, bool stripArgs) const { int encodedEntries = 0; for (auto it = from; it != to; ++it) { @@ -326,22 +374,22 @@ void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntrie ser << "NOT "; } it->Visit( - [&ser](const AlwaysTrue &) { + [&ser](const AlwaysTrue&) { logPrintf(LogTrace, "Not normalized query to dsl"); ser << "true"; }, - [&ser](const AlwaysFalse &) { + [&ser](const AlwaysFalse&) { logPrintf(LogTrace, "Not normalized query to dsl"); ser << "false"; }, - [&](const SubQueryEntry &sqe) { + [&](const SubQueryEntry& sqe) { if (encodedEntries) { ser << kOpNames[op] << ' '; } dumpCondWithValues(ser, '(' + query_.GetSubQuery(sqe.QueryIndex()).GetSQL(stripArgs) + ')', sqe.Condition(), sqe.Values(), stripArgs); }, - [&](const SubQueryFieldEntry &sqe) { + [&](const SubQueryFieldEntry& sqe) { if (encodedEntries) { ser << kOpNames[op] << ' '; } @@ -349,7 +397,7 @@ void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntrie SQLEncoder{query_.GetSubQuery(sqe.QueryIndex())}.GetSQL(ser, stripArgs); ser << ')'; }, - [&](const QueryEntriesBracket &bracket) { + [&](const QueryEntriesBracket& bracket) { if (encodedEntries) { ser << kOpNames[op] << ' '; } @@ -358,19 +406,19 @@ void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntrie dumpEqualPositions(ser, bracket.equalPositions); ser << ')'; }, - [&](const QueryEntry &entry) { + [&](const QueryEntry& entry) { if (encodedEntries) { ser << kOpNames[op] << ' '; } dumpCondWithValues(ser, entry.FieldName(), entry.Condition(), entry.Values(), stripArgs); }, - [&](const JoinQueryEntry &jqe) { + [&](const JoinQueryEntry& jqe) { if (encodedEntries && query_.GetJoinQueries()[jqe.joinIndex].joinType != JoinType::OrInnerJoin) { ser << kOpNames[op] << ' '; } SQLEncoder(query_).DumpSingleJoinQuery(jqe.joinIndex, ser, stripArgs); }, - [&](const BetweenFieldsQueryEntry &entry) { + [&](const BetweenFieldsQueryEntry& entry) { if (encodedEntries) { ser << kOpNames[op] << ' '; } @@ -382,8 +430,10 @@ void SQLEncoder::dumpWhereEntries(QueryEntries::const_iterator from, QueryEntrie } } -void SQLEncoder::dumpSQLWhere(WrSerializer &ser, bool stripArgs) const { - if (query_.Entries().Empty()) return; +void SQLEncoder::dumpSQLWhere(WrSerializer& ser, bool stripArgs) const { + if (query_.Entries().Empty()) { + return; + } ser << " WHERE "; dumpWhereEntries(query_.Entries().cbegin(), query_.Entries().cend(), ser, stripArgs); dumpEqualPositions(ser, query_.Entries().equalPositions); diff --git a/cpp_src/core/query/sql/sqlencoder.h b/cpp_src/core/query/sql/sqlencoder.h index 968f387df..3994555f0 100644 --- a/cpp_src/core/query/sql/sqlencoder.h +++ b/cpp_src/core/query/sql/sqlencoder.h @@ -11,47 +11,47 @@ class WrSerializer; class SQLEncoder { public: - SQLEncoder(const Query &q) noexcept : SQLEncoder(q, q.Type()) {} - SQLEncoder(const Query &q, QueryType queryType) noexcept : query_(q), realQueryType_(queryType) {} + SQLEncoder(const Query& q) noexcept : SQLEncoder(q, q.Type()) {} + SQLEncoder(const Query& q, QueryType queryType) noexcept : query_(q), realQueryType_(queryType) {} - WrSerializer &GetSQL(WrSerializer &ser, bool stripArgs = false) const; + WrSerializer& GetSQL(WrSerializer& ser, bool stripArgs = false) const; /// Gets printable sql version of joined query set by idx. /// @param idx - index of joined query in joinQueries_. /// @param ser - serializer to store SQL string. /// @param stripArgs - replace condition values with '?'. - void DumpSingleJoinQuery(size_t idx, WrSerializer &ser, bool stripArgs) const; + void DumpSingleJoinQuery(size_t idx, WrSerializer& ser, bool stripArgs) const; protected: /// Builds print version of a query with join in sql format. /// @param ser - serializer to store SQL string /// @param stripArgs - replace condition values with '?' - void dumpJoined(WrSerializer &ser, bool stripArgs) const; + void dumpJoined(WrSerializer& ser, bool stripArgs) const; /// Builds a print version of a query with merge queries in sql format. /// @param ser - serializer to store SQL string /// @param stripArgs - replace condition values with '?' - void dumpMerged(WrSerializer &ser, bool stripArgs) const; + void dumpMerged(WrSerializer& ser, bool stripArgs) const; /// Builds a print version of a query's order by statement /// @param ser - serializer to store SQL string /// @param stripArgs - replace condition values with '?' - void dumpOrderBy(WrSerializer &ser, bool stripArgs) const; + void dumpOrderBy(WrSerializer& ser, bool stripArgs) const; /// Builds a print version of all equal_position() functions in query. /// @param ser - serializer to store SQL string /// @param equalPositions - equal positions array - void dumpEqualPositions(WrSerializer &ser, const EqualPositions_t &equalPositions) const; + void dumpEqualPositions(WrSerializer& ser, const EqualPositions_t& equalPositions) const; /// Builds a print version of all where condition entries. /// @param from - iterator to first entry /// @param to - iterator to last entry /// @param ser - serializer to store SQL string /// @param stripArgs - replace condition values with '?' - void dumpWhereEntries(QueryEntries::const_iterator from, QueryEntries::const_iterator to, WrSerializer &ser, bool stripArgs) const; - void dumpSQLWhere(WrSerializer &ser, bool stripArgs) const; + void dumpWhereEntries(QueryEntries::const_iterator from, QueryEntries::const_iterator to, WrSerializer& ser, bool stripArgs) const; + void dumpSQLWhere(WrSerializer& ser, bool stripArgs) const; - const Query &query_; + const Query& query_; const QueryType realQueryType_; }; diff --git a/cpp_src/core/query/sql/sqlparser.cc b/cpp_src/core/query/sql/sqlparser.cc index ae4d7ba1c..6ba7e678c 100644 --- a/cpp_src/core/query/sql/sqlparser.cc +++ b/cpp_src/core/query/sql/sqlparser.cc @@ -1,4 +1,3 @@ - #include "sqlparser.h" #include "core/keyvalue/geometry.h" #include "core/keyvalue/key_string.h" @@ -21,12 +20,12 @@ Query SQLParser::Parse(std::string_view q) { return query; } -bool SQLParser::reachedAutocompleteToken(tokenizer &parser, const token &tok) const { +bool SQLParser::reachedAutocompleteToken(tokenizer& parser, const token& tok) const { size_t pos = parser.getPos() + tok.text().length(); return pos > ctx_.suggestionsPos; } -token SQLParser::peekSqlToken(tokenizer &parser, SqlTokenType tokenType, bool toLower) { +token SQLParser::peekSqlToken(tokenizer& parser, SqlTokenType tokenType, bool toLower) { token tok = parser.peek_token(toLower ? tokenizer::flags::to_lower : tokenizer::flags::no_flags); const bool eof = ((parser.getPos() + tok.text().length()) == parser.length()); if (ctx_.autocompleteMode && reachedAutocompleteToken(parser, tok)) { @@ -40,12 +39,16 @@ token SQLParser::peekSqlToken(tokenizer &parser, SqlTokenType tokenType, bool to ctx_.possibleSuggestionDetectedInThisClause = true; } } - if (!ctx_.foundPossibleSuggestions) ctx_.tokens.push_back(tokenType); - if (eof && ctx_.autocompleteMode) throw Error(errLogic, "SQLParser eof is reached!"); + if (!ctx_.foundPossibleSuggestions) { + ctx_.tokens.push_back(tokenType); + } + if (eof && ctx_.autocompleteMode) { + throw Error(errLogic, "SQLParser eof is reached!"); + } return tok; } -int SQLParser::Parse(tokenizer &parser) { +int SQLParser::Parse(tokenizer& parser) { parser.skip_space(); if (parser.length() == 0) { ctx_.suggestions.emplace_back(std::string(), Start); @@ -81,13 +84,15 @@ int SQLParser::Parse(tokenizer &parser) { tok = parser.next_token(); } parser.skip_space(); - if (!tok.text().empty() || !parser.end()) throw Error(errParseSQL, "Unexpected '%s' in query, %s", tok.text(), parser.where()); + if (!tok.text().empty() || !parser.end()) { + throw Error(errParseSQL, "Unexpected '%s' in query, %s", tok.text(), parser.where()); + } return 0; } template -int SQLParser::selectParse(tokenizer &parser) { +int SQLParser::selectParse(tokenizer& parser) { // Get filter token tok; bool wasSelectFilter = false; @@ -105,14 +110,18 @@ int SQLParser::selectParse(tokenizer &parser) { query_.Limit(0); } tok = parser.next_token(); - if (tok.text() != "*"sv) throw Error(errParseSQL, "Expected '*', but found '%s' in query, %s", tok.text(), parser.where()); + if (tok.text() != "*"sv) { + throw Error(errParseSQL, "Expected '*', but found '%s' in query, %s", tok.text(), parser.where()); + } } else if (name.text() == "count_cached"sv) { query_.CalcTotal(ModeCachedTotal); if (!wasSelectFilter) { query_.Limit(0); } tok = parser.next_token(); - if (tok.text() != "*"sv) throw Error(errParseSQL, "Expected '*', but found '%s' in query, %s", tok.text(), parser.where()); + if (tok.text() != "*"sv) { + throw Error(errParseSQL, "Expected '*', but found '%s' in query, %s", tok.text(), parser.where()); + } } else if (name.text() == "rank"sv) { query_.WithRank(); } else { @@ -187,7 +196,9 @@ int SQLParser::selectParse(tokenizer &parser) { wasSelectFilter = true; selectFilters.clear(); } - if (tok.text() != ","sv) break; + if (tok.text() != ","sv) { + break; + } tok = parser.next_token(); } if (wasSelectFilter) { @@ -211,14 +222,16 @@ int SQLParser::selectParse(tokenizer &parser) { } else if (tok.text() == "limit"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.type != TokenNumber) + if (tok.type != TokenNumber) { throw Error(errParseSQL, "Expected number, but found '%s' in query, %s", tok.text(), parser.where()); + } query_.Limit(stoi(tok.text())); } else if (tok.text() == "offset"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.type != TokenNumber) + if (tok.type != TokenNumber) { throw Error(errParseSQL, "Expected number, but found '%s' in query, %s", tok.text(), parser.where()); + } query_.Offset(stoi(tok.text())); } else if (tok.text() == "order"sv) { parser.next_token(); @@ -261,7 +274,7 @@ int SQLParser::selectParse(tokenizer &parser) { } template -static void moveAppend(T &dst, T &src) { +static void moveAppend(T& dst, T& src) { if (dst.empty()) { dst = std::move(src); } else { @@ -273,7 +286,7 @@ static void moveAppend(T &dst, T &src) { class SQLParser::ParserContextsAppendGuard { public: - ParserContextsAppendGuard(SqlParsingCtx &mainCtx, SqlParsingCtx &nestedCtx) noexcept : mainCtx_{mainCtx}, nestedCtx_{nestedCtx} {} + ParserContextsAppendGuard(SqlParsingCtx& mainCtx, SqlParsingCtx& nestedCtx) noexcept : mainCtx_{mainCtx}, nestedCtx_{nestedCtx} {} ~ParserContextsAppendGuard() { moveAppend(mainCtx_.suggestions, nestedCtx_.suggestions); if (!mainCtx_.foundPossibleSuggestions && nestedCtx_.foundPossibleSuggestions) { @@ -282,17 +295,19 @@ class SQLParser::ParserContextsAppendGuard { } private: - SqlParsingCtx &mainCtx_; - SqlParsingCtx &nestedCtx_; + SqlParsingCtx& mainCtx_; + SqlParsingCtx& nestedCtx_; }; -static KeyValueType detectValueType(const token &currTok) { - const std::string_view val = currTok.text(); - if (currTok.type == TokenNumber) { +static KeyValueType detectValueType(const token& tok) { + const std::string_view val = tok.text(); + if (tok.type == TokenNumber) { unsigned i = 0; bool flt = false; bool digit = val.length() < 21 && val.length() > 0; - if (val[i] == '+' || val[i] == '-') i++; + if (val[i] == '+' || val[i] == '-') { + i++; + } for (; i < val.length() && digit; i++) { if (val[i] == '.') { flt = true; @@ -311,37 +326,44 @@ static KeyValueType detectValueType(const token &currTok) { return {KeyValueType::String{}}; } -Variant token2kv(const token &currTok, tokenizer &parser, bool allowComposite) { - if (currTok.text() == "{"sv) { +Variant token2kv(const token& tok, tokenizer& parser, CompositeAllowed allowComposite, FieldAllowed allowField) { + if (tok.text() == "{"sv) { // Composite value parsing - if (!allowComposite) { + if (allowComposite == CompositeAllowed::No) { throw Error(errParseSQL, "Unexpected '{' in query, %s", parser.where()); } VariantArray compositeValues; for (;;) { - auto tok = parser.next_token(); - compositeValues.push_back(token2kv(tok, parser, false)); - tok = parser.next_token(); - if (tok.text() == "}"sv) { - return Variant(compositeValues); + auto nextTok = parser.next_token(); + compositeValues.push_back(token2kv(nextTok, parser, CompositeAllowed::No, FieldAllowed::No)); + nextTok = parser.next_token(); + if (nextTok.text() == "}"sv) { + return Variant(compositeValues); // end process } - if (tok.text() != ","sv) { - throw Error(errParseSQL, "Expected ',', but found '%s' in query, %s", tok.text(), parser.where()); + if (nextTok.text() != ","sv) { + throw Error(errParseSQL, "Expected ',', but found '%s' in query, %s", nextTok.text(), parser.where()); } } } - std::string_view value = currTok.text(); - if (currTok.type == TokenName) { - if (iequals(value, "true"sv)) return Variant{true}; - if (iequals(value, "false"sv)) return Variant{false}; + std::string_view value = tok.text(); + if (tok.type == TokenName) { + if (iequals(value, "true"sv)) { + return Variant{true}; + } + if (iequals(value, "false"sv)) { + return Variant{false}; + } + if (allowField == FieldAllowed::Yes) { + return Variant(); + } } - if (currTok.type != TokenNumber && currTok.type != TokenString) { - throw Error(errParseSQL, "Expected parameter, but found '%s' in query, %s", currTok.text(), parser.where()); + if (tok.type != TokenNumber && tok.type != TokenString) { + throw Error(errParseSQL, "Expected parameter, but found '%s' in query, %s", tok.text(), parser.where()); } - return detectValueType(currTok).EvaluateOneOf( + return detectValueType(tok).EvaluateOneOf( [&](KeyValueType::Int64) { return Variant(int64_t(stoll(value))); }, [&](KeyValueType::Double) { try { @@ -361,7 +383,7 @@ Variant token2kv(const token &currTok, tokenizer &parser, bool allowComposite) { }); } -int SQLParser::parseOrderBy(tokenizer &parser, SortingEntries &sortingEntries, std::vector &forcedSortOrder_) { +int SQLParser::parseOrderBy(tokenizer& parser, SortingEntries& sortingEntries, std::vector& forcedSortOrder_) { // Just skip token (BY) peekSqlToken(parser, BySqlToken); parser.next_token(); @@ -387,7 +409,9 @@ int SQLParser::parseOrderBy(tokenizer &parser, SortingEntries &sortingEntries, s tok = parser.next_token(tokenizer::flags::no_flags); for (;;) { tok = parser.next_token(); - if (tok.text() == ")"sv) break; + if (tok.text() == ")"sv) { + break; + } if (tok.text() != ","sv) { throw Error(errParseSQL, "Expected ')' or ',', but found '%s' in query, %s", tok.text(), parser.where()); } @@ -396,7 +420,7 @@ int SQLParser::parseOrderBy(tokenizer &parser, SortingEntries &sortingEntries, s throw Error(errParseSQL, "Forced sort order is allowed for the first sorting entry only, '%s', %s", tok.text(), parser.where()); } - forcedSortOrder_.push_back(token2kv(tok, parser, true)); + forcedSortOrder_.push_back(token2kv(tok, parser, CompositeAllowed::Yes, FieldAllowed::No)); } tok = parser.peek_token(); } @@ -408,19 +432,22 @@ int SQLParser::parseOrderBy(tokenizer &parser, SortingEntries &sortingEntries, s sortingEntries.push_back(std::move(sortingEntry)); auto nextToken = parser.peek_token(); - if (nextToken.text() != ","sv) break; + if (nextToken.text() != ","sv) { + break; + } parser.next_token(); } return 0; } -int SQLParser::deleteParse(tokenizer &parser) { +int SQLParser::deleteParse(tokenizer& parser) { // Get filter token tok; peekSqlToken(parser, FromSqlToken); - if (parser.next_token().text() != "from"sv) + if (parser.next_token().text() != "from"sv) { throw Error(errParams, "Expected 'FROM', but found '%s' in query, %s", tok.text(), parser.where()); + } peekSqlToken(parser, NamespaceSqlToken); query_.SetNsName(parser.next_token().text()); @@ -431,13 +458,13 @@ int SQLParser::deleteParse(tokenizer &parser) { return 0; } -static void addUpdateValue(const token &currTok, tokenizer &parser, UpdateEntry &updateField) { - if (currTok.type == TokenString) { - updateField.Values().push_back(token2kv(currTok, parser, false)); +static void addUpdateValue(const token& tok, tokenizer& parser, UpdateEntry& updateField) { + if (tok.type == TokenString) { + updateField.Values().push_back(token2kv(tok, parser, CompositeAllowed::No, FieldAllowed::No)); } else { - if (currTok.text() == "null"sv) { + if (tok.text() == "null"sv) { updateField.Values().push_back(Variant()); - } else if (currTok.text() == "{"sv) { + } else if (tok.text() == "{"sv) { try { size_t jsonPos = parser.getPrevPos(); std::string json(parser.begin() + jsonPos, parser.length() - jsonPos); @@ -447,26 +474,32 @@ static void addUpdateValue(const token &currTok, tokenizer &parser, UpdateEntry updateField.Values().emplace_back(Variant(std::string(parser.begin() + jsonPos, jsonLength))); updateField.SetMode(FieldModeSetJson); parser.setPos(jsonPos + jsonLength); - } catch (const gason::Exception &e) { + } catch (const gason::Exception& e) { throw Error(errParseSQL, "%s, in query %s", e.what(), parser.where()); } } else { - auto eof = [](tokenizer &parser, bool &inArray) -> bool { - if (parser.end()) return true; + auto eof = [](tokenizer& parser, bool& inArray) -> bool { + if (parser.end()) { + return true; + } token nextTok = parser.peek_token(); bool result = (nextTok.text() == "where"sv) || (nextTok.text() == "order"sv) || (nextTok.text() == "limit"sv) || (nextTok.text() == "offset"sv) || (!inArray && nextTok.text() == "]"sv) || (!inArray && nextTok.text() == ","sv); - if (nextTok.text() == "["sv && !inArray) inArray = true; - if (nextTok.text() == "]"sv && inArray) inArray = false; + if (nextTok.text() == "["sv && !inArray) { + inArray = true; + } + if (nextTok.text() == "]"sv && inArray) { + inArray = false; + } return result; }; int count = 0; - std::string expression(currTok.text()); + std::string expression(tok.text()); bool inArray = false; while (!eof(parser, inArray)) { - auto tok = parser.next_token(tokenizer::flags::treat_sign_as_token); - expression += tok.type == TokenString ? '\'' + std::string{tok.text()} + '\'' : std::string{tok.text()}; + auto nextTok = parser.next_token(tokenizer::flags::treat_sign_as_token); + expression += nextTok.type == TokenString ? '\'' + std::string{nextTok.text()} + '\'' : std::string{nextTok.text()}; ++count; } if (count > 0) { @@ -474,9 +507,9 @@ static void addUpdateValue(const token &currTok, tokenizer &parser, UpdateEntry updateField.SetIsExpression(true); } else { try { - Variant val = token2kv(currTok, parser, false); + Variant val = token2kv(tok, parser, CompositeAllowed::No, FieldAllowed::No); updateField.Values().push_back(val); - } catch (const Error &) { + } catch (const Error&) { updateField.Values().push_back(Variant(expression)); updateField.SetIsExpression(true); } @@ -485,29 +518,34 @@ static void addUpdateValue(const token &currTok, tokenizer &parser, UpdateEntry } } -void SQLParser::parseArray(tokenizer &parser, std::string_view tokText, UpdateEntry *updateField) const { +void SQLParser::parseArray(tokenizer& parser, std::string_view tokText, UpdateEntry* updateField) const { if (tokText != "["sv) { throw Error(errParams, "Expected '[' after field parameter, not %s", tokText); } for (;;) { - auto tok = parser.next_token(tokenizer::flags::no_flags); - if (tok.text() == "]"sv) { - if (updateField && updateField->Values().empty()) break; + auto nextTok = parser.next_token(tokenizer::flags::no_flags); + if (nextTok.text() == "]"sv) { + if (updateField && updateField->Values().empty()) { + break; + } throw Error(errParseSQL, "Expected field value, but found ']' in query, %s", parser.where()); } - if (updateField) addUpdateValue(tok, parser, *updateField); - tok = parser.next_token(tokenizer::flags::no_flags); - if (tok.text() == "]"sv) break; - if (tok.text() != ","sv) { - throw Error(errParseSQL, "Expected ']' or ',', but found '%s' in query, %s", tok.text(), parser.where()); + if (updateField) { + addUpdateValue(nextTok, parser, *updateField); + } + nextTok = parser.next_token(tokenizer::flags::no_flags); + if (nextTok.text() == "]"sv) { + break; + } + if (nextTok.text() != ","sv) { + throw Error(errParseSQL, "Expected ']' or ',', but found '%s' in query, %s", nextTok.text(), parser.where()); } } if (updateField && (updateField->Mode() == FieldModeSetJson)) { - for (const auto &it : updateField->Values()) { - if ((!it.Type().Is()) || - std::string_view(it).front() != '{') { + for (const auto& it : updateField->Values()) { + if ((!it.Type().Is()) || std::string_view(it).front() != '{') { throw Error(errLogic, "Unexpected variant type in Array: %s. Expecting KeyValueType::String with JSON-content", it.Type().Name()); } @@ -515,7 +553,7 @@ void SQLParser::parseArray(tokenizer &parser, std::string_view tokText, UpdateEn } } -void SQLParser::parseCommand(tokenizer &parser) const { +void SQLParser::parseCommand(tokenizer& parser) const { // parse input, for example: array_remove(array_field, [24, 3, 81]) || [11,22] auto tok = parser.next_token(); @@ -533,9 +571,12 @@ void SQLParser::parseCommand(tokenizer &parser) const { throw Error(errParams, "Expected ',' after field parameter, not %s", tok.text()); } - // parse list of elements or field to be deleted + // parse item or list of elements or field to be deleted tok = parser.next_token(); - if (tok.type != TokenName) { + // try parse as scalar value + if ((tok.type == TokenNumber) || (tok.type == TokenString) || (tok.type == TokenName)) { + token2kv(tok, parser, CompositeAllowed::No, FieldAllowed::Yes); // ignore result + } else { parseArray(parser, tok.text(), nullptr); } @@ -549,7 +590,9 @@ void SQLParser::parseCommand(tokenizer &parser) const { while (tok.text() == "|"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.text() != "|"sv) throw Error(errLogic, "Expected '|', not '%s'", tok.text()); + if (tok.text() != "|"sv) { + throw Error(errLogic, "Expected '|', not '%s'", tok.text()); + } tok = parser.next_token(); if (tok.type == TokenSymbol) { parseArray(parser, tok.text(), nullptr); @@ -562,7 +605,7 @@ void SQLParser::parseCommand(tokenizer &parser) const { } } -UpdateEntry SQLParser::parseUpdateField(tokenizer &parser) { +UpdateEntry SQLParser::parseUpdateField(tokenizer& parser) { token tok = peekSqlToken(parser, FieldNameSqlToken, false); if (tok.type != TokenName) { throw Error(errParseSQL, "Expected field name but found '%s' in query %s", tok.text(), parser.where()); @@ -571,7 +614,9 @@ UpdateEntry SQLParser::parseUpdateField(tokenizer &parser) { parser.next_token(); tok = parser.next_token(); - if (tok.text() != "="sv) throw Error(errParams, "Expected '=' but found '%s' in query, '%s'", tok.text(), parser.where()); + if (tok.text() != "="sv) { + throw Error(errParams, "Expected '=' but found '%s' in query, '%s'", tok.text(), parser.where()); + } size_t startPos = parser.getPos(); bool withArrayExpressions = false; @@ -594,7 +639,9 @@ UpdateEntry SQLParser::parseUpdateField(tokenizer &parser) { while (tok.text() == "|"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.text() != "|"sv) throw Error(errLogic, "Expected '|', not '%s'", tok.text()); + if (tok.text() != "|"sv) { + throw Error(errLogic, "Expected '|', not '%s'", tok.text()); + } tok = parser.next_token(); if (tok.type != TokenName) { throw Error(errParseSQL, "Expected field name, but found %s in query, %s", tok.text(), parser.where()); @@ -613,7 +660,7 @@ UpdateEntry SQLParser::parseUpdateField(tokenizer &parser) { return updateField; } -int SQLParser::updateParse(tokenizer &parser) { +int SQLParser::updateParse(tokenizer& parser) { parser.next_token(); token tok = peekSqlToken(parser, NamespaceSqlToken); @@ -627,7 +674,9 @@ int SQLParser::updateParse(tokenizer &parser) { while (!parser.end()) { query_.UpdateField(parseUpdateField(parser)); tok = parser.peek_token(); - if (tok.text() != ","sv) break; + if (tok.text() != ","sv) { + break; + } parser.next_token(); } } else if (tok.text() == "drop"sv) { @@ -640,7 +689,9 @@ int SQLParser::updateParse(tokenizer &parser) { query_.Drop(std::string(tok.text())); parser.next_token(); tok = parser.peek_token(); - if (tok.text() != ","sv) break; + if (tok.text() != ","sv) { + break; + } } } else { throw Error(errParseSQL, "Expected 'SET' or 'DROP' but found '%s' in query %s", tok.text(), parser.where()); @@ -651,7 +702,7 @@ int SQLParser::updateParse(tokenizer &parser) { return 0; } -void SQLParser::parseModifyConditions(tokenizer &parser) { +void SQLParser::parseModifyConditions(tokenizer& parser) { while (!parser.end()) { auto tok = peekSqlToken(parser, ModifyConditionsStart); if (tok.text() == "where"sv) { @@ -660,14 +711,16 @@ void SQLParser::parseModifyConditions(tokenizer &parser) { } else if (tok.text() == "limit"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.type != TokenNumber) + if (tok.type != TokenNumber) { throw Error(errParseSQL, "Expected number, but found '%s' in query, %s", tok.text(), parser.where()); + } query_.Limit(stoi(tok.text())); } else if (tok.text() == "offset"sv) { parser.next_token(); tok = parser.next_token(); - if (tok.type != TokenNumber) + if (tok.type != TokenNumber) { throw Error(errParseSQL, "Expected number, but found '%s' in query, %s", tok.text(), parser.where()); + } query_.Offset(stoi(tok.text())); } else if (tok.text() == "order"sv) { parser.next_token(); @@ -679,7 +732,7 @@ void SQLParser::parseModifyConditions(tokenizer &parser) { } } -int SQLParser::truncateParse(tokenizer &parser) { +int SQLParser::truncateParse(tokenizer& parser) { parser.next_token(); token tok = peekSqlToken(parser, NamespaceSqlToken); query_.SetNsName(tok.text()); @@ -693,7 +746,7 @@ static bool isCondition(std::string_view text) noexcept { text == "<="sv || iequals(text, "in"sv) || iequals(text, "range"sv) || iequals(text, "like"sv) || iequals(text, "allset"sv); } -Query SQLParser::parseSubQuery(tokenizer &parser) { +Query SQLParser::parseSubQuery(tokenizer& parser) { Query subquery; SQLParser subparser(subquery); const ParserContextsAppendGuard guard{ctx_, subparser.ctx_}; @@ -714,17 +767,17 @@ Query SQLParser::parseSubQuery(tokenizer &parser) { } template -void SQLParser::parseWhereCondition(tokenizer &parser, T &&firstArg, OpType op) { +void SQLParser::parseWhereCondition(tokenizer& parser, T&& firstArg, OpType op) { // Operator CondType condition; auto tok = peekSqlToken(parser, ConditionSqlToken); if (tok.text() == "<>"sv) { condition = CondEq; - if (op == OpAnd) + if (op == OpAnd) { op = OpNot; - else if (op == OpNot) + } else if (op == OpNot) { op = OpAnd; - else { + } else { throw Error(errParseSQL, "<> condition with OR is not supported, %s", parser.where()); } } else { @@ -733,7 +786,9 @@ void SQLParser::parseWhereCondition(tokenizer &parser, T &&firstArg, OpType op) parser.next_token(); // Value - if (ctx_.autocompleteMode) peekSqlToken(parser, WhereFieldValueSqlToken, false); + if (ctx_.autocompleteMode) { + peekSqlToken(parser, WhereFieldValueSqlToken, false); + } tok = parser.next_token(); if (iequals(tok.text(), "null"sv) || iequals(tok.text(), "empty"sv)) { query_.NextOp(op).Where(std::forward(firstArg), CondEmpty, VariantArray{}); @@ -755,16 +810,21 @@ void SQLParser::parseWhereCondition(tokenizer &parser, T &&firstArg, OpType op) VariantArray values; for (;;) { tok = parser.next_token(); - if (tok.text() == ")"sv && tok.type == TokenSymbol) break; - values.push_back(token2kv(tok, parser, true)); + if (tok.text() == ")"sv && tok.type == TokenSymbol) { + break; + } + values.push_back(token2kv(tok, parser, CompositeAllowed::Yes, FieldAllowed::No)); tok = parser.next_token(); - if (tok.text() == ")"sv) break; - if (tok.text() != ","sv) + if (tok.text() == ")"sv) { + break; + } + if (tok.text() != ","sv) { throw Error(errParseSQL, "Expected ')' or ',', but found '%s' in query, %s", tok.text(), parser.where()); + } } query_.NextOp(op).Where(std::forward(firstArg), condition, std::move(values)); } else if (tok.type != TokenName || iequals(tok.text(), "true"sv) || iequals(tok.text(), "false"sv)) { - query_.NextOp(op).Where(std::forward(firstArg), condition, {token2kv(tok, parser, true)}); + query_.NextOp(op).Where(std::forward(firstArg), condition, {token2kv(tok, parser, CompositeAllowed::Yes, FieldAllowed::No)}); } else { if constexpr (std::is_same_v) { throw Error(errParseSQL, "Field cannot be after subquery. (text = '%s' location = %s)", tok.text(), parser.where()); @@ -776,7 +836,7 @@ void SQLParser::parseWhereCondition(tokenizer &parser, T &&firstArg, OpType op) } template -int SQLParser::parseWhere(tokenizer &parser) { +int SQLParser::parseWhere(tokenizer& parser) { token tok; OpType nextOp = OpAnd; @@ -865,8 +925,9 @@ int SQLParser::parseWhere(tokenizer &parser) { if (iequals(tok.text(), "not"sv)) { parser.next_token(); nextOp = OpNot; - } else + } else { continue; + } } else if (iequals(tok.text(), "or"sv)) { parser.next_token(); peekSqlToken(parser, FieldNameSqlToken); @@ -875,7 +936,7 @@ int SQLParser::parseWhere(tokenizer &parser) { break; } } - for (auto &eqPos : equalPositions) { + for (auto& eqPos : equalPositions) { if (eqPos.first == 0) { query_.SetEqualPositions(std::move(eqPos.second)); } else { @@ -890,7 +951,7 @@ int SQLParser::parseWhere(tokenizer &parser) { return 0; } -void SQLParser::parseEqualPositions(tokenizer &parser, std::vector> &equalPositions, +void SQLParser::parseEqualPositions(tokenizer& parser, std::vector>& equalPositions, size_t lastBracketPosition) { parser.next_token(); auto tok = parser.next_token(); @@ -918,7 +979,9 @@ void SQLParser::parseEqualPositions(tokenizer &parser, std::vector) noexcept {}, [&](OneOf) { @@ -1051,7 +1114,7 @@ void SQLParser::parseDWithin(tokenizer &parser, OpType nextOp) { query_.DWithin(field, point, distance.As()); } -void SQLParser::parseJoin(JoinType type, tokenizer &parser) { +void SQLParser::parseJoin(JoinType type, tokenizer& parser) { JoinedQuery jquery; SQLParser jparser(jquery); const ParserContextsAppendGuard guard{ctx_, jparser.ctx_}; @@ -1086,7 +1149,7 @@ void SQLParser::parseJoin(JoinType type, tokenizer &parser) { query_.Join(std::move(jquery)); } -void SQLParser::parseMerge(tokenizer &parser) { +void SQLParser::parseMerge(tokenizer& parser) { JoinedQuery mquery; SQLParser mparser(mquery); const ParserContextsAppendGuard guard{ctx_, mparser.ctx_}; @@ -1116,7 +1179,7 @@ void SQLParser::parseMerge(tokenizer &parser) { query_.Merge(std::move(mquery)); } -std::string SQLParser::parseJoinedFieldName(tokenizer &parser, std::string &name) { +std::string SQLParser::parseJoinedFieldName(tokenizer& parser, std::string& name) { auto tok = peekSqlToken(parser, JoinedFieldNameSqlToken); if (tok.type != TokenName) { throw Error(errParseSQL, "Expected name, but found %s, %s", tok.text(), parser.where()); @@ -1137,7 +1200,7 @@ std::string SQLParser::parseJoinedFieldName(tokenizer &parser, std::string &name return std::string(tok.text().substr(dotPos + 1)); } -void SQLParser::parseJoinEntries(tokenizer &parser, const std::string &mainNs, JoinedQuery &jquery) { +void SQLParser::parseJoinEntries(tokenizer& parser, const std::string& mainNs, JoinedQuery& jquery) { auto tok = peekSqlToken(parser, OnSqlToken); if (tok.text() != "on"sv) { throw Error(errParseSQL, "Expected 'ON', but found %s, %s", tok.text(), parser.where()); @@ -1147,7 +1210,9 @@ void SQLParser::parseJoinEntries(tokenizer &parser, const std::string &mainNs, J tok = parser.peek_token(); bool braces = tok.text() == "("sv; - if (braces) parser.next_token(); + if (braces) { + parser.next_token(); + } while (!parser.end()) { tok = peekSqlToken(parser, OpSqlToken); diff --git a/cpp_src/core/query/sql/sqlparser.h b/cpp_src/core/query/sql/sqlparser.h index e283b45ff..3a857b51a 100644 --- a/cpp_src/core/query/sql/sqlparser.h +++ b/cpp_src/core/query/sql/sqlparser.h @@ -27,7 +27,7 @@ class SQLParser { [[nodiscard]] static Query Parse(std::string_view sql); protected: - explicit SQLParser(Query &q) noexcept : query_(q) {} + explicit SQLParser(Query& q) noexcept : query_(q) {} /// Sql parser context struct SqlParsingCtx { struct SuggestionData { @@ -36,7 +36,7 @@ class SQLParser { SqlTokenType tokenType = Start; std::unordered_set variants; }; - void updateLinkedNs(const std::string &ns) { + void updateLinkedNs(const std::string& ns) { if (autocompleteMode && (!foundPossibleSuggestions || possibleSuggestionDetectedInThisClause)) { suggestionLinkedNs = ns; } @@ -54,79 +54,79 @@ class SQLParser { /// Parses query. /// @param tok - tokenizer object instance. /// @return always returns zero. - int Parse(tokenizer &tok); + int Parse(tokenizer& tok); /// Peeks next sql token. /// @param parser - tokenizer object instance. /// @param tokenType - token type. /// @param toLower - transform to lower representation. /// @return sql token object. - token peekSqlToken(tokenizer &parser, SqlTokenType tokenType, bool toLower = true); + token peekSqlToken(tokenizer& parser, SqlTokenType tokenType, bool toLower = true); /// Is current token last in autocomplete mode? - bool reachedAutocompleteToken(tokenizer &parser, const token &tok) const; + bool reachedAutocompleteToken(tokenizer& parser, const token& tok) const; /// Parses filter part of sql query. /// @param parser - tokenizer object instance. /// @return always returns zero. template - int selectParse(tokenizer &parser); + int selectParse(tokenizer& parser); /// Parses filter part of sql delete query. /// @param parser - tokenizer object instance. /// @return always returns zero. - int deleteParse(tokenizer &parser); + int deleteParse(tokenizer& parser); /// Parses filter part of sql update query. /// @param parser - tokenizer object instance. /// @return always returns zero. - int updateParse(tokenizer &parser); + int updateParse(tokenizer& parser); /// Parses filter part of sql truncate query. /// @param parser - tokenizer object instance. /// @return always returns zero. - int truncateParse(tokenizer &parser); + int truncateParse(tokenizer& parser); /// Parse where entries template - int parseWhere(tokenizer &parser); + int parseWhere(tokenizer& parser); template - void parseWhereCondition(tokenizer &, T &&firstArg, OpType); + void parseWhereCondition(tokenizer&, T&& firstArg, OpType); /// Parse order by - int parseOrderBy(tokenizer &parser, SortingEntries &sortingEntries, std::vector &forcedSortOrder); + int parseOrderBy(tokenizer& parser, SortingEntries& sortingEntries, std::vector& forcedSortOrder); /// Parse join entries - void parseJoin(JoinType type, tokenizer &tok); + void parseJoin(JoinType type, tokenizer& tok); /// Parse join entries - void parseJoinEntries(tokenizer &parser, const std::string &mainNs, JoinedQuery &jquery); + void parseJoinEntries(tokenizer& parser, const std::string& mainNs, JoinedQuery& jquery); /// Parse equal_positions - void parseEqualPositions(tokenizer &parser, std::vector> &equalPositions, size_t openBracketsCount); + void parseEqualPositions(tokenizer& parser, std::vector>& equalPositions, size_t openBracketsCount); - Point parseGeomFromText(tokenizer &parser) const; - void parseDWithin(tokenizer &parser, OpType nextOp); + Point parseGeomFromText(tokenizer& parser) const; + void parseDWithin(tokenizer& parser, OpType nextOp); /// Parse update field entries - UpdateEntry parseUpdateField(tokenizer &parser); + UpdateEntry parseUpdateField(tokenizer& parser); /// Parse joined Ns name: [Namespace.field] - std::string parseJoinedFieldName(tokenizer &parser, std::string &name); + std::string parseJoinedFieldName(tokenizer& parser, std::string& name); /// Parse merge entries - void parseMerge(tokenizer &parser); + void parseMerge(tokenizer& parser); - void parseModifyConditions(tokenizer &parser); + void parseModifyConditions(tokenizer& parser); - Query parseSubQuery(tokenizer &parser); + Query parseSubQuery(tokenizer& parser); - void parseArray(tokenizer &parser, std::string_view tokText, UpdateEntry *updateField) const; - void parseCommand(tokenizer &parser) const; + void parseArray(tokenizer& parser, std::string_view tokText, UpdateEntry* updateField) const; + void parseCommand(tokenizer& parser) const; static CondType getCondType(std::string_view cond); SqlParsingCtx ctx_; - Query &query_; + Query& query_; }; } // namespace reindexer diff --git a/cpp_src/core/query/sql/sqlsuggester.cc b/cpp_src/core/query/sql/sqlsuggester.cc index 249e05d06..0890c70ea 100644 --- a/cpp_src/core/query/sql/sqlsuggester.cc +++ b/cpp_src/core/query/sql/sqlsuggester.cc @@ -25,15 +25,15 @@ std::vector SQLSuggester::GetSuggestions(std::string_view q, size_t tokenizer tokens{q}; (void)(suggester.Parse(tokens)); // NOLINTBEGIN(bugprone-empty-catch) - } catch (const Error &) { + } catch (const Error&) { } // NOLINTEND(bugprone-empty-catch) - for (SqlParsingCtx::SuggestionData &item : suggester.ctx_.suggestions) { + for (SqlParsingCtx::SuggestionData& item : suggester.ctx_.suggestions) { suggester.checkForTokenSuggestions(item); } - for (auto &it : suggester.ctx_.suggestions) { + for (auto& it : suggester.ctx_.suggestions) { if (!it.variants.empty()) { return {it.variants.begin(), it.variants.end()}; } @@ -72,8 +72,8 @@ std::unordered_map> sqlTokenMatchings = { {ST_GeomFromTextSqlToken, {"ST_GeomFromText"}}, }; -static void getMatchingTokens(int tokenType, const std::string &token, std::unordered_set &variants) { - const std::unordered_set &suggestions = sqlTokenMatchings[tokenType]; +static void getMatchingTokens(int tokenType, const std::string& token, std::unordered_set& variants) { + const std::unordered_set& suggestions = sqlTokenMatchings[tokenType]; for (auto it = suggestions.begin(); it != suggestions.end(); ++it) { if (isBlank(token) || checkIfStartsWith(token, *it)) { variants.insert(*it); @@ -81,21 +81,27 @@ static void getMatchingTokens(int tokenType, const std::string &token, std::unor } } -void SQLSuggester::getMatchingNamespacesNames(const std::string &token, std::unordered_set &variants) { +void SQLSuggester::getMatchingNamespacesNames(const std::string& token, std::unordered_set& variants) { auto namespaces = enumNamespaces_(EnumNamespacesOpts().OnlyNames()); - for (auto &ns : namespaces) { - if (isBlank(token) || checkIfStartsWith(token, ns.name)) variants.insert(ns.name); + for (auto& ns : namespaces) { + if (isBlank(token) || checkIfStartsWith(token, ns.name)) { + variants.insert(ns.name); + } } } -void SQLSuggester::getMatchingFieldsNames(const std::string &token, std::unordered_set &variants) { +void SQLSuggester::getMatchingFieldsNames(const std::string& token, std::unordered_set& variants) { auto namespaces = enumNamespaces_(EnumNamespacesOpts().WithFilter(ctx_.suggestionLinkedNs)); - if (namespaces.empty() || (namespaces.size() > 1 && isBlank(token))) return; + if (namespaces.empty() || (namespaces.size() > 1 && isBlank(token))) { + return; + } auto dotPos = token.find('.'); - for (const auto &ns : namespaces) { - for (auto &idx : ns.indexes) { - if (idx.name_ == "#pk" || idx.name_ == "-tuple") continue; + for (const auto& ns : namespaces) { + for (auto& idx : ns.indexes) { + if (idx.name_ == "#pk" || idx.name_ == "-tuple") { + continue; + } if (isBlank(token) || (dotPos != std::string::npos ? checkIfStartsWith(token, idx.name_) : checkIfStartsWith(token, idx.name_))) { if (dotPos == std::string::npos) { @@ -108,11 +114,11 @@ void SQLSuggester::getMatchingFieldsNames(const std::string &token, std::unorder } if (getSchema_) { - for (const auto &ns : namespaces) { + for (const auto& ns : namespaces) { auto schema = getSchema_(ns.name); if (schema) { auto fieldsSuggestions = schema->GetSuggestions(token); - for (auto &suggestion : fieldsSuggestions) { + for (auto& suggestion : fieldsSuggestions) { variants.insert(std::move(suggestion)); } } @@ -120,7 +126,7 @@ void SQLSuggester::getMatchingFieldsNames(const std::string &token, std::unorder } } -void SQLSuggester::getSuggestionsForToken(SqlParsingCtx::SuggestionData &ctx) { +void SQLSuggester::getSuggestionsForToken(SqlParsingCtx::SuggestionData& ctx) { switch (ctx.tokenType) { case Start: case StartAfterExplain: @@ -203,16 +209,18 @@ void SQLSuggester::getSuggestionsForToken(SqlParsingCtx::SuggestionData &ctx) { } } -bool SQLSuggester::findInPossibleTokens(int type, const std::string &v) { - const std::unordered_set &values = sqlTokenMatchings[type]; +bool SQLSuggester::findInPossibleTokens(int type, const std::string& v) { + const std::unordered_set& values = sqlTokenMatchings[type]; return (values.find(v) != values.end()); } -bool SQLSuggester::findInPossibleFields(const std::string &tok) { +bool SQLSuggester::findInPossibleFields(const std::string& tok) { auto namespaces = enumNamespaces_(EnumNamespacesOpts().WithFilter(ctx_.suggestionLinkedNs)); - if (namespaces.empty()) return false; - if (std::find_if(namespaces[0].indexes.begin(), namespaces[0].indexes.end(), [&](const IndexDef &lhs) { return lhs.name_ == tok; }) != + if (namespaces.empty()) { + return false; + } + if (std::find_if(namespaces[0].indexes.begin(), namespaces[0].indexes.end(), [&](const IndexDef& lhs) { return lhs.name_ == tok; }) != namespaces[0].indexes.end()) { return true; } @@ -223,11 +231,11 @@ bool SQLSuggester::findInPossibleFields(const std::string &tok) { return false; } -bool SQLSuggester::findInPossibleNamespaces(const std::string &tok) { +bool SQLSuggester::findInPossibleNamespaces(const std::string& tok) { return !enumNamespaces_(EnumNamespacesOpts().WithFilter(tok).OnlyNames()).empty(); } -void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) { +void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData& data) { switch (data.tokenType) { case Start: case StartAfterExplain: @@ -240,10 +248,14 @@ void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) getSuggestionsForToken(data); break; } - if (data.token == "*") break; + if (data.token == "*") { + break; + } bool isIndex = false, isAggregationFunction = false; isIndex = findInPossibleFields(data.token); - if (!isIndex) isAggregationFunction = findInPossibleTokens(AggregationSqlToken, data.token); + if (!isIndex) { + isAggregationFunction = findInPossibleTokens(AggregationSqlToken, data.token); + } if (!isIndex && !isAggregationFunction) { getSuggestionsForToken(data); } @@ -272,7 +284,9 @@ void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) getSuggestionsForToken(data); break; } - if (iequals(data.token, "not")) break; + if (iequals(data.token, "not")) { + break; + } if (!findInPossibleFields(data.token)) { getSuggestionsForToken(data); } @@ -283,7 +297,9 @@ void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) } break; case WhereFieldValueSqlToken: - if (isBlank(data.token)) break; + if (isBlank(data.token)) { + break; + } if (checkIfTokenStartsWith(data.token, "null")) { getSuggestionsForToken(data); break; @@ -382,7 +398,9 @@ void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) getSuggestionsForToken(data); break; } - if (findInPossibleFields(data.token)) break; + if (findInPossibleFields(data.token)) { + break; + } getSuggestionsForToken(data); break; case FieldNameSqlToken: @@ -395,7 +413,9 @@ void SQLSuggester::checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data) getSuggestionsForToken(data); break; } - if (data.token == "(") break; + if (data.token == "(") { + break; + } if (checkIfTokenStartsWith(data.token, "field")) { getSuggestionsForToken(data); break; diff --git a/cpp_src/core/query/sql/sqlsuggester.h b/cpp_src/core/query/sql/sqlsuggester.h index 274201ed0..0280c5254 100644 --- a/cpp_src/core/query/sql/sqlsuggester.h +++ b/cpp_src/core/query/sql/sqlsuggester.h @@ -26,20 +26,20 @@ class SQLSuggester : public SQLParser { private: /// Finds suggestions for token /// @param ctx - suggestion context. - void getSuggestionsForToken(SqlParsingCtx::SuggestionData &ctx); + void getSuggestionsForToken(SqlParsingCtx::SuggestionData& ctx); /// Checks if token suggestion is required - void checkForTokenSuggestions(SqlParsingCtx::SuggestionData &data); + void checkForTokenSuggestions(SqlParsingCtx::SuggestionData& data); /// Tries to find token value among accepted tokens. - [[nodiscard]] bool findInPossibleTokens(int type, const std::string &v); + [[nodiscard]] bool findInPossibleTokens(int type, const std::string& v); /// Tries to find token value among indexes. - [[nodiscard]] bool findInPossibleFields(const std::string &tok); + [[nodiscard]] bool findInPossibleFields(const std::string& tok); /// Tries to find among possible namespaces. - [[nodiscard]] bool findInPossibleNamespaces(const std::string &tok); + [[nodiscard]] bool findInPossibleNamespaces(const std::string& tok); /// Gets names of indexes that start with 'token'. - void getMatchingFieldsNames(const std::string &token, std::unordered_set &variants); - void getMatchingNamespacesNames(const std::string &token, std::unordered_set &variants); + void getMatchingFieldsNames(const std::string& token, std::unordered_set& variants); + void getMatchingNamespacesNames(const std::string& token, std::unordered_set& variants); EnumNamespacesF enumNamespaces_; GetSchemaF getSchema_; }; diff --git a/cpp_src/core/queryresults/aggregationresult.cc b/cpp_src/core/queryresults/aggregationresult.cc index 921f26382..d054cb93b 100644 --- a/cpp_src/core/queryresults/aggregationresult.cc +++ b/cpp_src/core/queryresults/aggregationresult.cc @@ -54,23 +54,29 @@ AggType AggregationResult::strToAggType(std::string_view type) { return AggUnknown; } -void AggregationResult::GetJSON(WrSerializer &ser) const { +void AggregationResult::GetJSON(WrSerializer& ser) const { JsonBuilder builder(ser); ParameterFieldGetter fieldsGetter; get(builder, ParametersFields(fieldsGetter)); } -void AggregationResult::GetMsgPack(WrSerializer &wrser) const { +void AggregationResult::GetMsgPack(WrSerializer& wrser) const { int elements = 2; - if (value_) ++elements; - if (!facets.empty()) ++elements; - if (!distincts.empty()) ++elements; + if (value_) { + ++elements; + } + if (!facets.empty()) { + ++elements; + } + if (!distincts.empty()) { + ++elements; + } MsgPackBuilder msgpackBuilder(wrser, ObjType::TypeObject, elements); ParameterFieldGetter fieldsGetter; get(msgpackBuilder, ParametersFields(fieldsGetter)); } -void AggregationResult::GetProtobuf(WrSerializer &wrser) const { +void AggregationResult::GetProtobuf(WrSerializer& wrser) const { ProtobufBuilder builder(&wrser, ObjType::TypePlain); get(builder, ParametersFields(kParametersFieldNumbers)); } @@ -84,7 +90,7 @@ Error AggregationResult::FromMsgPack(span msgpack) { return Error(errLogic, "Error unpacking aggregation data in msgpack"); } from(root); - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; @@ -95,13 +101,13 @@ Error AggregationResult::FromJSON(span json) { gason::JsonParser parser; auto root = parser.Parse(json); from(root); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "AggregationResult: %s", ex.what()); } return errOK; } -void AggregationResult::GetProtobufSchema(ProtobufSchemaBuilder &builder) { +void AggregationResult::GetProtobufSchema(ProtobufSchemaBuilder& builder) { ParametersFields fields(kParametersFieldNumbers); ProtobufSchemaBuilder results = builder.Object(0, "AggregationResults"); results.Field(Parameters::Value(), fields.Value(), FieldProps{KeyValueType::Double{}}); diff --git a/cpp_src/core/queryresults/aggregationresult.h b/cpp_src/core/queryresults/aggregationresult.h index 17f36a22f..deb3a9be5 100644 --- a/cpp_src/core/queryresults/aggregationresult.h +++ b/cpp_src/core/queryresults/aggregationresult.h @@ -35,7 +35,7 @@ struct Parameters { template class ParametersFields { public: - explicit ParametersFields(const T &fieldsStorage) : fieldsStorage_(fieldsStorage) {} + explicit ParametersFields(const T& fieldsStorage) : fieldsStorage_(fieldsStorage) {} K Value() const { return fieldsStorage_.at(Parameters::Value()); } K Type() const { return fieldsStorage_.at(Parameters::Type()); } @@ -46,11 +46,11 @@ class ParametersFields { K Fields() const { return fieldsStorage_.at(Parameters::Fields()); } private: - const T &fieldsStorage_; + const T& fieldsStorage_; }; struct FacetResult { - FacetResult(const h_vector &v, int c) noexcept : values(v), count(c) {} + FacetResult(const h_vector& v, int c) noexcept : values(v), count(c) {} FacetResult() noexcept : count(0) {} h_vector values; @@ -58,9 +58,9 @@ struct FacetResult { }; struct AggregationResult { - void GetJSON(WrSerializer &ser) const; - void GetMsgPack(WrSerializer &wrser) const; - void GetProtobuf(WrSerializer &wrser) const; + void GetJSON(WrSerializer& ser) const; + void GetMsgPack(WrSerializer& wrser) const; + void GetProtobuf(WrSerializer& wrser) const; Error FromJSON(span json); Error FromMsgPack(span msgpack); double GetValueOrZero() const noexcept { return value_ ? *value_ : 0; } @@ -74,15 +74,21 @@ struct AggregationResult { PayloadType payloadType; static AggType strToAggType(std::string_view type); - static void GetProtobufSchema(ProtobufSchemaBuilder &); + static void GetProtobufSchema(ProtobufSchemaBuilder&); template void from(Node root) { - const Node &node = root[Parameters::Value()]; + const Node& node = root[Parameters::Value()]; bool isValid = false; - if constexpr (std::is_same_v) isValid = node.isValid(); - if constexpr (std::is_same_v) isValid = !node.empty(); - if (isValid) value_ = node.template As(); + if constexpr (std::is_same_v) { + isValid = node.isValid(); + } + if constexpr (std::is_same_v) { + isValid = !node.empty(); + } + if (isValid) { + value_ = node.template As(); + } type = strToAggType(root[Parameters::Type()].template As()); @@ -105,35 +111,41 @@ struct AggregationResult { } template - void get(Builder &builder, const Fields ¶metersFields) const { - if (value_) builder.Put(parametersFields.Value(), *value_); + void get(Builder& builder, const Fields& parametersFields) const { + if (value_) { + builder.Put(parametersFields.Value(), *value_); + } builder.Put(parametersFields.Type(), AggTypeToStr(type)); if (!facets.empty()) { auto facetsArray = builder.Array(parametersFields.Facets(), facets.size()); - for (auto &facet : facets) { + for (auto& facet : facets) { auto facetObj = facetsArray.Object(0, 2); facetObj.Put(parametersFields.Count(), facet.count); auto valuesArray = facetObj.Array(parametersFields.Values(), facet.values.size()); - for (const auto &v : facet.values) valuesArray.Put(0, v); + for (const auto& v : facet.values) { + valuesArray.Put(0, v); + } } } if (!distincts.empty()) { auto distinctsArray = builder.Array(parametersFields.Distincts(), distincts.size()); - for (const Variant &v : distincts) { + for (const Variant& v : distincts) { distinctsArray.Put(0, v.As(payloadType, distinctsFields)); } } auto fieldsArray = builder.Array(parametersFields.Fields(), fields.size()); - for (auto &v : fields) fieldsArray.Put(0, v); + for (auto& v : fields) { + fieldsArray.Put(0, v); + } fieldsArray.End(); } template - S &DumpFields(S &os) { + S& DumpFields(S& os) { os << '['; bool first = true; - for (const auto &f : fields) { + for (const auto& f : fields) { if (!first) { os << ", "; } diff --git a/cpp_src/core/queryresults/itemref.h b/cpp_src/core/queryresults/itemref.h index 2c417fc3f..49a838cc5 100644 --- a/cpp_src/core/queryresults/itemref.h +++ b/cpp_src/core/queryresults/itemref.h @@ -21,7 +21,9 @@ class ItemRef { valueInitialized_(other.valueInitialized_), nsid_(other.nsid_), sortExprResultsIdx_(other.sortExprResultsIdx_) { - if (valueInitialized_) new (&value_) PayloadValue(std::move(other.value_)); + if (valueInitialized_) { + new (&value_) PayloadValue(std::move(other.value_)); + } } ItemRef(const ItemRef& other) : id_(other.id_), @@ -30,10 +32,14 @@ class ItemRef { valueInitialized_(other.valueInitialized_), nsid_(other.nsid_), sortExprResultsIdx_(other.sortExprResultsIdx_) { - if (valueInitialized_) new (&value_) PayloadValue(other.value_); + if (valueInitialized_) { + new (&value_) PayloadValue(other.value_); + } } ItemRef& operator=(ItemRef&& other) { - if (&other == this) return *this; + if (&other == this) { + return *this; + } id_ = other.id_; proc_ = other.proc_; raw_ = other.raw_; @@ -56,7 +62,9 @@ class ItemRef { return *this; } ItemRef& operator=(const ItemRef& other) { - if (&other == this) return *this; + if (&other == this) { + return *this; + } id_ = other.id_; proc_ = other.proc_; raw_ = other.raw_; @@ -79,7 +87,9 @@ class ItemRef { return *this; } ~ItemRef() { - if (valueInitialized_) value_.~PayloadValue(); + if (valueInitialized_) { + value_.~PayloadValue(); + } } IdType Id() const noexcept { return id_; } diff --git a/cpp_src/core/queryresults/joinresults.cc b/cpp_src/core/queryresults/joinresults.cc index 1b24c121a..496aab927 100644 --- a/cpp_src/core/queryresults/joinresults.cc +++ b/cpp_src/core/queryresults/joinresults.cc @@ -6,15 +6,23 @@ namespace reindexer { namespace joins { bool JoinedFieldIterator::operator==(const JoinedFieldIterator& other) const { - if (joinRes_ != other.joinRes_) throw Error(errLogic, "Comparising joined fields of different namespaces!"); - if (offsets_ != other.offsets_) throw Error(errLogic, "Comparising joined fields of different items!"); - if (order_ != other.order_) return false; + if (joinRes_ != other.joinRes_) { + throw Error(errLogic, "Comparising joined fields of different namespaces!"); + } + if (offsets_ != other.offsets_) { + throw Error(errLogic, "Comparising joined fields of different items!"); + } + if (order_ != other.order_) { + return false; + } return true; } void JoinedFieldIterator::updateOffset() noexcept { currField_ = -1; - if (order_ == joinRes_->GetJoinedSelectorsCount()) return; + if (order_ == joinRes_->GetJoinedSelectorsCount()) { + return; + } size_t i = 0; for (; i < offsets_->size(); ++i) { @@ -34,7 +42,9 @@ ItemImpl JoinedFieldIterator::GetItem(int itemIdx, const PayloadType& pt, const } QueryResults JoinedFieldIterator::ToQueryResults() const { - if (ItemsCount() == 0) return QueryResults(); + if (ItemsCount() == 0) { + return QueryResults(); + } ItemRefVector::const_iterator begin = joinRes_->items_.begin() + currOffset_; ItemRefVector::const_iterator end = begin + ItemsCount(); return QueryResults(begin, end); @@ -96,7 +106,9 @@ ItemIterator ItemIterator::CreateFrom(const QueryResults::Iterator& it) noexcept static NamespaceResults empty; static ItemIterator ret(&empty, 0); auto& itemRef = it.qr_->Items()[it.idx_]; - if ((itemRef.Nsid() >= it.qr_->joined_.size())) return ret; + if ((itemRef.Nsid() >= it.qr_->joined_.size())) { + return ret; + } return ItemIterator(&(it.qr_->joined_[itemRef.Nsid()]), itemRef.Id()); } diff --git a/cpp_src/core/queryresults/joinresults.h b/cpp_src/core/queryresults/joinresults.h index 07a2a062e..3fce7be52 100644 --- a/cpp_src/core/queryresults/joinresults.h +++ b/cpp_src/core/queryresults/joinresults.h @@ -73,7 +73,9 @@ class JoinedFieldIterator { JoinedFieldIterator(const NamespaceResults* parent, const ItemOffsets& offsets, uint8_t joinedFieldOrder) noexcept : joinRes_(parent), offsets_(&offsets), order_(joinedFieldOrder) { - if (offsets_->size() > 0) updateOffset(); + if (offsets_->size() > 0) { + updateOffset(); + } } bool operator==(const JoinedFieldIterator& other) const; diff --git a/cpp_src/core/queryresults/queryresults.cc b/cpp_src/core/queryresults/queryresults.cc index df94408b5..0a1ee037d 100644 --- a/cpp_src/core/queryresults/queryresults.cc +++ b/cpp_src/core/queryresults/queryresults.cc @@ -14,9 +14,9 @@ namespace reindexer { void QueryResults::AddNamespace(NamespaceImplPtr ns, [[maybe_unused]] bool noLock) { assertrx(noLock); - const NamespaceImpl *nsPtr = ns.get(); + const NamespaceImpl* nsPtr = ns.get(); auto strHolder = ns->strHolder(); - const auto it = std::find_if(nsData_.cbegin(), nsData_.cend(), [nsPtr](const NsDataHolder &nsData) { return nsData.ns == nsPtr; }); + const auto it = std::find_if(nsData_.cbegin(), nsData_.cend(), [nsPtr](const NsDataHolder& nsData) { return nsData.ns == nsPtr; }); if (it != nsData_.cend()) { assertrx(it->strHolder.get() == strHolder.get()); return; @@ -24,10 +24,10 @@ void QueryResults::AddNamespace(NamespaceImplPtr ns, [[maybe_unused]] bool noLoc nsData_.emplace_back(std::move(ns), std::move(strHolder)); } -void QueryResults::AddNamespace(NamespaceImpl *ns, [[maybe_unused]] bool noLock) { +void QueryResults::AddNamespace(NamespaceImpl* ns, [[maybe_unused]] bool noLock) { assertrx(noLock); auto strHolder = ns->strHolder(); - const auto it = std::find_if(nsData_.cbegin(), nsData_.cend(), [ns](const NsDataHolder &nsData) { return nsData.ns == ns; }); + const auto it = std::find_if(nsData_.cbegin(), nsData_.cend(), [ns](const NsDataHolder& nsData) { return nsData.ns == ns; }); if (it != nsData_.cend()) { assertrx(it->strHolder.get() == strHolder.get()); return; @@ -35,15 +35,15 @@ void QueryResults::AddNamespace(NamespaceImpl *ns, [[maybe_unused]] bool noLock) nsData_.emplace_back(ns, std::move(strHolder)); } -void QueryResults::RemoveNamespace(const NamespaceImpl *ns) { - const auto it = std::find_if(nsData_.begin(), nsData_.end(), [ns](const NsDataHolder &nsData) { return nsData.ns == ns; }); +void QueryResults::RemoveNamespace(const NamespaceImpl* ns) { + const auto it = std::find_if(nsData_.begin(), nsData_.end(), [ns](const NsDataHolder& nsData) { return nsData.ns == ns; }); assertrx(it != nsData_.end()); nsData_.erase(it); } struct QueryResults::Context { Context() = default; - Context(PayloadType type, TagsMatcher tagsMatcher, const FieldsSet &fieldsFilter, std::shared_ptr schema) + Context(PayloadType type, TagsMatcher tagsMatcher, const FieldsSet& fieldsFilter, std::shared_ptr schema) : type_(std::move(type)), tagsMatcher_(std::move(tagsMatcher)), fieldsFilter_(fieldsFilter), schema_(std::move(schema)) {} PayloadType type_; @@ -57,7 +57,7 @@ static_assert(QueryResults::kSizeofContext >= sizeof(QueryResults::Context), QueryResults::QueryResults(std::initializer_list l) : items_(l) {} QueryResults::QueryResults(int /*flags*/) {} -QueryResults::QueryResults(QueryResults &&obj) noexcept +QueryResults::QueryResults(QueryResults&& obj) noexcept : joined_(std::move(obj.joined_)), aggregationResults(std::move(obj.aggregationResults)), totalCount(obj.totalCount), @@ -74,9 +74,9 @@ QueryResults::QueryResults(QueryResults &&obj) noexcept obj.isWalQuery_ = false; } -QueryResults::QueryResults(const ItemRefVector::const_iterator &begin, const ItemRefVector::const_iterator &end) : items_(begin, end) {} +QueryResults::QueryResults(const ItemRefVector::const_iterator& begin, const ItemRefVector::const_iterator& end) : items_(begin, end) {} -QueryResults &QueryResults::operator=(QueryResults &&obj) noexcept { +QueryResults& QueryResults::operator=(QueryResults&& obj) noexcept { if (this != &obj) { items_ = std::move(obj.items_); assertrx(!obj.items_.size()); @@ -107,22 +107,30 @@ void QueryResults::Clear() { *this = QueryResults(); } void QueryResults::Erase(ItemRefVector::iterator start, ItemRefVector::iterator finish) { items_.erase(start, finish); } -void QueryResults::Add(const ItemRef &i) { items_.push_back(i); } +void QueryResults::Add(const ItemRef& i) { items_.push_back(i); } std::string QueryResults::Dump() const { std::string buf; for (size_t i = 0; i < items_.size(); ++i) { - if (&items_[i] != &*items_.begin()) buf += ","; + if (&items_[i] != &*items_.begin()) { + buf += ","; + } buf += std::to_string(items_[i].Id()); - if (joined_.empty()) continue; + if (joined_.empty()) { + continue; + } Iterator itemIt{this, int(i), errOK, {}}; auto joinIt = itemIt.GetJoined(); if (joinIt.getJoinedItemsCount() > 0) { buf += "["; for (auto fieldIt = joinIt.begin(); fieldIt != joinIt.end(); ++fieldIt) { - if (fieldIt != joinIt.begin()) buf += ";"; + if (fieldIt != joinIt.begin()) { + buf += ";"; + } for (int j = 0; j < fieldIt.ItemsCount(); ++j) { - if (j != 0) buf += ","; + if (j != 0) { + buf += ","; + } buf += std::to_string(fieldIt[j].Id()); } } @@ -135,7 +143,9 @@ std::string QueryResults::Dump() const { h_vector QueryResults::GetNamespaces() const { h_vector ret; ret.reserve(ctxs.size()); - for (auto &ctx : ctxs) ret.push_back(ctx.type_.Name()); + for (auto& ctx : ctxs) { + ret.push_back(ctx.type_.Name()); + } return ret; } @@ -149,7 +159,7 @@ int QueryResults::GetJoinedNsCtxIndex(int nsid) const noexcept { class QueryResults::EncoderDatasourceWithJoins final : public IEncoderDatasourceWithJoins { public: - EncoderDatasourceWithJoins(const joins::ItemIterator &joinedItemIt, const ContextsVector &ctxs, Iterator::NsNamesCache &nsNamesCache, + EncoderDatasourceWithJoins(const joins::ItemIterator& joinedItemIt, const ContextsVector& ctxs, Iterator::NsNamesCache& nsNamesCache, int ctxIdx, size_t nsid, size_t joinedCount) noexcept : joinedItemIt_(joinedItemIt), ctxs_(ctxs), nsNamesCache_(nsNamesCache), ctxId_(ctxIdx), nsid_{nsid} { if (nsNamesCache.size() <= nsid_) { @@ -161,14 +171,14 @@ class QueryResults::EncoderDatasourceWithJoins final : public IEncoderDatasource fast_hash_map namesCounters; assertrx_dbg(ctxs_.size() >= ctxId_ + joinedCount); for (size_t i = ctxId_, end = ctxId_ + joinedCount; i < end; ++i) { - const std::string &n = ctxs_[i].type_.Name(); + const std::string& n = ctxs_[i].type_.Name(); if (auto [it, emplaced] = namesCounters.emplace(n, -1); !emplaced) { --it->second; } } for (size_t i = ctxId_, end = ctxId_ + joinedCount; i < end; ++i) { - const std::string &n = ctxs_[i].type_.Name(); - int &count = namesCounters[n]; + const std::string& n = ctxs_[i].type_.Name(); + int& count = namesCounters[n]; if (count < 0) { if (count == -1) { nsNamesCache[nsid_].emplace_back(n); @@ -191,57 +201,59 @@ class QueryResults::EncoderDatasourceWithJoins final : public IEncoderDatasource } ConstPayload GetJoinedItemPayload(size_t rowid, size_t plIndex) const override final { auto fieldIt = joinedItemIt_.at(rowid); - const ItemRef &itemRef = fieldIt[plIndex]; - const Context &ctx = ctxs_[ctxId_ + rowid]; + const ItemRef& itemRef = fieldIt[plIndex]; + const Context& ctx = ctxs_[ctxId_ + rowid]; return ConstPayload(ctx.type_, itemRef.Value()); } - const TagsMatcher &GetJoinedItemTagsMatcher(size_t rowid) noexcept override final { - const Context &ctx = ctxs_[ctxId_ + rowid]; + const TagsMatcher& GetJoinedItemTagsMatcher(size_t rowid) noexcept override final { + const Context& ctx = ctxs_[ctxId_ + rowid]; return ctx.tagsMatcher_; } - virtual const FieldsSet &GetJoinedItemFieldsFilter(size_t rowid) noexcept override final { - const Context &ctx = ctxs_[ctxId_ + rowid]; + virtual const FieldsSet& GetJoinedItemFieldsFilter(size_t rowid) noexcept override final { + const Context& ctx = ctxs_[ctxId_ + rowid]; return ctx.fieldsFilter_; } - const std::string &GetJoinedItemNamespace(size_t rowid) const noexcept override final { return nsNamesCache_[nsid_][rowid]; } + const std::string& GetJoinedItemNamespace(size_t rowid) const noexcept override final { return nsNamesCache_[nsid_][rowid]; } private: - const joins::ItemIterator &joinedItemIt_; - const ContextsVector &ctxs_; - const Iterator::NsNamesCache &nsNamesCache_; + const joins::ItemIterator& joinedItemIt_; + const ContextsVector& ctxs_; + const Iterator::NsNamesCache& nsNamesCache_; const int ctxId_; const size_t nsid_; }; class AdditionalDatasource : public IAdditionalDatasource { public: - AdditionalDatasource(double r, IEncoderDatasourceWithJoins *jds) noexcept : joinsDs_(jds), withRank_(true), rank_(r) {} - AdditionalDatasource(IEncoderDatasourceWithJoins *jds) noexcept : joinsDs_(jds), withRank_(false), rank_(0.0) {} - void PutAdditionalFields(JsonBuilder &builder) const override final { - if (withRank_) builder.Put("rank()", rank_); + AdditionalDatasource(double r, IEncoderDatasourceWithJoins* jds) noexcept : joinsDs_(jds), withRank_(true), rank_(r) {} + AdditionalDatasource(IEncoderDatasourceWithJoins* jds) noexcept : joinsDs_(jds), withRank_(false), rank_(0.0) {} + void PutAdditionalFields(JsonBuilder& builder) const override final { + if (withRank_) { + builder.Put("rank()", rank_); + } } - IEncoderDatasourceWithJoins *GetJoinsDatasource() noexcept override final { return joinsDs_; } + IEncoderDatasourceWithJoins* GetJoinsDatasource() noexcept override final { return joinsDs_; } private: - IEncoderDatasourceWithJoins *joinsDs_; + IEncoderDatasourceWithJoins* joinsDs_; bool withRank_; double rank_; }; class AdditionalDatasourceCSV : public IAdditionalDatasource { public: - AdditionalDatasourceCSV(IEncoderDatasourceWithJoins *jds) noexcept : joinsDs_(jds) {} - void PutAdditionalFields(CsvBuilder &) const override final {} - IEncoderDatasourceWithJoins *GetJoinsDatasource() noexcept override final { return joinsDs_; } + AdditionalDatasourceCSV(IEncoderDatasourceWithJoins* jds) noexcept : joinsDs_(jds) {} + void PutAdditionalFields(CsvBuilder&) const override final {} + IEncoderDatasourceWithJoins* GetJoinsDatasource() noexcept override final { return joinsDs_; } private: - IEncoderDatasourceWithJoins *joinsDs_; + IEncoderDatasourceWithJoins* joinsDs_; }; -void QueryResults::encodeJSON(int idx, WrSerializer &ser, Iterator::NsNamesCache &nsNamesCache) const { - auto &itemRef = items_[idx]; +void QueryResults::encodeJSON(int idx, WrSerializer& ser, Iterator::NsNamesCache& nsNamesCache) const { + auto& itemRef = items_[idx]; assertrx(ctxs.size() > itemRef.Nsid()); - auto &ctx = ctxs[itemRef.Nsid()]; + auto& ctx = ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { ser << "{}"; @@ -277,10 +289,10 @@ void QueryResults::encodeJSON(int idx, WrSerializer &ser, Iterator::NsNamesCache joins::ItemIterator QueryResults::Iterator::GetJoined() { return reindexer::joins::ItemIterator::CreateFrom(*this); } -Error QueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { - auto &itemRef = qr_->items_[idx_]; +Error QueryResults::Iterator::GetMsgPack(WrSerializer& wrser, bool withHdrLen) { + auto& itemRef = qr_->items_[idx_]; assertrx(qr_->ctxs.size() > itemRef.Nsid()); - auto &ctx = qr_->ctxs[itemRef.Nsid()]; + auto& ctx = qr_->ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { return Error(errNotFound, "Item not found"); @@ -289,8 +301,8 @@ Error QueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { int startTag = 0; ConstPayload pl(ctx.type_, itemRef.Value()); MsgPackEncoder msgpackEncoder(&ctx.tagsMatcher_); - const TagsLengths &tagsLengths = msgpackEncoder.GetTagsMeasures(pl); - MsgPackBuilder msgpackBuilder(wrser, &tagsLengths, &startTag, ObjType::TypePlain, const_cast(&ctx.tagsMatcher_)); + const TagsLengths& tagsLengths = msgpackEncoder.GetTagsMeasures(pl); + MsgPackBuilder msgpackBuilder(wrser, &tagsLengths, &startTag, ObjType::TypePlain, const_cast(&ctx.tagsMatcher_)); if (withHdrLen) { auto slicePosSaver = wrser.StartSlice(); msgpackEncoder.Encode(pl, msgpackBuilder); @@ -300,10 +312,10 @@ Error QueryResults::Iterator::GetMsgPack(WrSerializer &wrser, bool withHdrLen) { return errOK; } -Error QueryResults::Iterator::GetProtobuf(WrSerializer &wrser, bool withHdrLen) { - auto &itemRef = qr_->items_[idx_]; +Error QueryResults::Iterator::GetProtobuf(WrSerializer& wrser, bool withHdrLen) { + auto& itemRef = qr_->items_[idx_]; assertrx(qr_->ctxs.size() > itemRef.Nsid()); - auto &ctx = qr_->ctxs[itemRef.Nsid()]; + auto& ctx = qr_->ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { return Error(errNotFound, "Item not found"); @@ -311,7 +323,7 @@ Error QueryResults::Iterator::GetProtobuf(WrSerializer &wrser, bool withHdrLen) ConstPayload pl(ctx.type_, itemRef.Value()); ProtobufEncoder encoder(&ctx.tagsMatcher_); - ProtobufBuilder builder(&wrser, ObjType::TypePlain, ctx.schema_.get(), const_cast(&ctx.tagsMatcher_)); + ProtobufBuilder builder(&wrser, ObjType::TypePlain, ctx.schema_.get(), const_cast(&ctx.tagsMatcher_)); if (withHdrLen) { auto slicePosSaver = wrser.StartSlice(); encoder.Encode(pl, builder); @@ -322,7 +334,7 @@ Error QueryResults::Iterator::GetProtobuf(WrSerializer &wrser, bool withHdrLen) return errOK; } -Error QueryResults::Iterator::GetJSON(WrSerializer &ser, bool withHdrLen) { +Error QueryResults::Iterator::GetJSON(WrSerializer& ser, bool withHdrLen) { try { if (withHdrLen) { auto slicePosSaver = ser.StartSlice(); @@ -330,7 +342,7 @@ Error QueryResults::Iterator::GetJSON(WrSerializer &ser, bool withHdrLen) { } else { qr_->encodeJSON(idx_, ser, nsNamesCache); } - } catch (const Error &err) { + } catch (const Error& err) { err_ = err; return err; } @@ -341,7 +353,7 @@ CsvOrdering QueryResults::MakeCSVTagOrdering(unsigned limit, unsigned offset) co if (!ctxs[0].fieldsFilter_.empty()) { std::vector ordering; ordering.reserve(ctxs[0].fieldsFilter_.size()); - for (const auto &tag : ctxs[0].fieldsFilter_) { + for (const auto& tag : ctxs[0].fieldsFilter_) { ordering.emplace_back(tag); } return ordering; @@ -351,7 +363,7 @@ CsvOrdering QueryResults::MakeCSVTagOrdering(unsigned limit, unsigned offset) co ordering.reserve(128); fast_hash_set fieldsTmIds; WrSerializer ser; - const auto &tm = getTagsMatcher(0); + const auto& tm = getTagsMatcher(0); Iterator::NsNamesCache nsNamesCache; for (size_t i = offset; i < items_.size() && i < offset + limit; ++i) { ser.Reset(); @@ -360,7 +372,7 @@ CsvOrdering QueryResults::MakeCSVTagOrdering(unsigned limit, unsigned offset) co gason::JsonParser parser; auto jsonNode = parser.Parse(giftStr(ser.Slice())); - for (const auto &child : jsonNode) { + for (const auto& child : jsonNode) { auto [it, inserted] = fieldsTmIds.insert(tm.name2tag(child.key)); if (inserted && *it > 0) { ordering.emplace_back(*it); @@ -370,11 +382,11 @@ CsvOrdering QueryResults::MakeCSVTagOrdering(unsigned limit, unsigned offset) co return ordering; } -Error QueryResults::Iterator::GetCSV(WrSerializer &ser, CsvOrdering &ordering) noexcept { +Error QueryResults::Iterator::GetCSV(WrSerializer& ser, CsvOrdering& ordering) noexcept { try { - auto &itemRef = qr_->items_[idx_]; + auto& itemRef = qr_->items_[idx_]; assertrx(qr_->ctxs.size() > itemRef.Nsid()); - auto &ctx = qr_->ctxs[itemRef.Nsid()]; + auto& ctx = qr_->ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { return Error(errNotFound, "Item not found"); @@ -401,11 +413,11 @@ Error QueryResults::Iterator::GetCSV(WrSerializer &ser, CsvOrdering &ordering) n return errOK; } -Error QueryResults::Iterator::GetCJSON(WrSerializer &ser, bool withHdrLen) { +Error QueryResults::Iterator::GetCJSON(WrSerializer& ser, bool withHdrLen) { try { - auto &itemRef = qr_->items_[idx_]; + auto& itemRef = qr_->items_[idx_]; assertrx(qr_->ctxs.size() > itemRef.Nsid()); - auto &ctx = qr_->ctxs[itemRef.Nsid()]; + auto& ctx = qr_->ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { return Error(errNotFound, "Item not found"); @@ -421,7 +433,7 @@ Error QueryResults::Iterator::GetCJSON(WrSerializer &ser, bool withHdrLen) { } else { cjsonEncoder.Encode(pl, builder); } - } catch (const Error &err) { + } catch (const Error& err) { err_ = err; return err; } @@ -429,10 +441,10 @@ Error QueryResults::Iterator::GetCJSON(WrSerializer &ser, bool withHdrLen) { } Item QueryResults::Iterator::GetItem(bool enableHold) { - auto &itemRef = qr_->items_[idx_]; + auto& itemRef = qr_->items_[idx_]; assertrx(qr_->ctxs.size() > itemRef.Nsid()); - auto &ctx = qr_->ctxs[itemRef.Nsid()]; + auto& ctx = qr_->ctxs[itemRef.Nsid()]; if (itemRef.Value().IsFree()) { return Item(Error(errNotFound, "Item not found")); @@ -441,7 +453,9 @@ Item QueryResults::Iterator::GetItem(bool enableHold) { auto item = Item(new ItemImpl(ctx.type_, itemRef.Value(), ctx.tagsMatcher_, ctx.schema_)); item.impl_->payloadValue_.Clone(); if (enableHold) { - if (!item.impl_->keyStringsHolder_) item.impl_->keyStringsHolder_.reset(new std::vector); + if (!item.impl_->keyStringsHolder_) { + item.impl_->keyStringsHolder_.reset(new std::vector); + } Payload{ctx.type_, item.impl_->payloadValue_}.CopyStrings(*(item.impl_->keyStringsHolder_)); } @@ -449,7 +463,7 @@ Item QueryResults::Iterator::GetItem(bool enableHold) { return item; } -void QueryResults::AddItem(Item &item, bool withData, bool enableHold) { +void QueryResults::AddItem(Item& item, bool withData, bool enableHold) { auto ritem = item.impl_; if (item.GetID() != -1) { if (ctxs.empty()) { @@ -467,15 +481,15 @@ void QueryResults::AddItem(Item &item, bool withData, bool enableHold) { } } -const TagsMatcher &QueryResults::getTagsMatcher(int nsid) const noexcept { return ctxs[nsid].tagsMatcher_; } +const TagsMatcher& QueryResults::getTagsMatcher(int nsid) const noexcept { return ctxs[nsid].tagsMatcher_; } -const PayloadType &QueryResults::getPayloadType(int nsid) const noexcept { return ctxs[nsid].type_; } +const PayloadType& QueryResults::getPayloadType(int nsid) const noexcept { return ctxs[nsid].type_; } -const FieldsSet &QueryResults::getFieldsFilter(int nsid) const noexcept { return ctxs[nsid].fieldsFilter_; } +const FieldsSet& QueryResults::getFieldsFilter(int nsid) const noexcept { return ctxs[nsid].fieldsFilter_; } -TagsMatcher &QueryResults::getTagsMatcher(int nsid) noexcept { return ctxs[nsid].tagsMatcher_; } +TagsMatcher& QueryResults::getTagsMatcher(int nsid) noexcept { return ctxs[nsid].tagsMatcher_; } -PayloadType &QueryResults::getPayloadType(int nsid) noexcept { return ctxs[nsid].type_; } +PayloadType& QueryResults::getPayloadType(int nsid) noexcept { return ctxs[nsid].type_; } std::shared_ptr QueryResults::getSchema(int nsid) const noexcept { return ctxs[nsid].schema_; } @@ -484,17 +498,19 @@ int QueryResults::getNsNumber(int nsid) const noexcept { return ctxs[nsid].schema_->GetProtobufNsNumber(); } -void QueryResults::addNSContext(const PayloadType &type, const TagsMatcher &tagsMatcher, const FieldsSet &filter, +void QueryResults::addNSContext(const PayloadType& type, const TagsMatcher& tagsMatcher, const FieldsSet& filter, std::shared_ptr schema) { - if (filter.getTagsPathsLength()) nonCacheableData = true; + if (filter.getTagsPathsLength()) { + nonCacheableData = true; + } ctxs.push_back(Context(type, tagsMatcher, filter, std::move(schema))); } -QueryResults::NsDataHolder::NsDataHolder(QueryResults::NamespaceImplPtr &&_ns, StringsHolderPtr &&strHldr) noexcept +QueryResults::NsDataHolder::NsDataHolder(QueryResults::NamespaceImplPtr&& _ns, StringsHolderPtr&& strHldr) noexcept : nsPtr_{std::move(_ns)}, ns(nsPtr_.get()), strHolder{std::move(strHldr)} {} -QueryResults::NsDataHolder::NsDataHolder(NamespaceImpl *_ns, StringsHolderPtr &&strHldr) noexcept +QueryResults::NsDataHolder::NsDataHolder(NamespaceImpl* _ns, StringsHolderPtr&& strHldr) noexcept : ns(_ns), strHolder(std::move(strHldr)) {} } // namespace reindexer diff --git a/cpp_src/core/queryresults/queryresults.h b/cpp_src/core/queryresults/queryresults.h index dc3f510d5..880f1e80a 100644 --- a/cpp_src/core/queryresults/queryresults.h +++ b/cpp_src/core/queryresults/queryresults.h @@ -38,27 +38,27 @@ class QueryResults { using NamespaceImplPtr = intrusive_ptr; QueryResults(int flags = 0); - QueryResults(const ItemRefVector::const_iterator &b, const ItemRefVector::const_iterator &e); + QueryResults(const ItemRefVector::const_iterator& b, const ItemRefVector::const_iterator& e); QueryResults(std::initializer_list l); - QueryResults(const QueryResults &) = delete; - QueryResults(QueryResults &&) noexcept; + QueryResults(const QueryResults&) = delete; + QueryResults(QueryResults&&) noexcept; ~QueryResults(); - QueryResults &operator=(const QueryResults &) = delete; - QueryResults &operator=(QueryResults &&obj) noexcept; - void Add(const ItemRef &); + QueryResults& operator=(const QueryResults&) = delete; + QueryResults& operator=(QueryResults&& obj) noexcept; + void Add(const ItemRef&); // use enableHold = false only if you are sure that the queryResults will be destroyed before the item // or if data from the item are contained in namespace added to the queryResults // enableHold is ignored when withData = false - void AddItem(Item &item, bool withData = false, bool enableHold = true); + void AddItem(Item& item, bool withData = false, bool enableHold = true); std::string Dump() const; void Erase(ItemRefVector::iterator begin, ItemRefVector::iterator end); size_t Count() const noexcept { return items_.size(); } size_t TotalCount() const noexcept { return totalCount; } - const std::string &GetExplainResults() const & noexcept { return explainResults; } - const std::string &GetExplainResults() const && = delete; - std::string &&MoveExplainResults() & noexcept { return std::move(explainResults); } - const std::vector &GetAggregationResults() const & noexcept { return aggregationResults; } - const std::vector &GetAggregationResults() const && = delete; + const std::string& GetExplainResults() const& noexcept { return explainResults; } + const std::string& GetExplainResults() const&& = delete; + std::string&& MoveExplainResults() & noexcept { return std::move(explainResults); } + const std::vector& GetAggregationResults() const& noexcept { return aggregationResults; } + const std::vector& GetAggregationResults() const&& = delete; void Clear(); h_vector GetNamespaces() const; bool IsCacheEnabled() const { return !nonCacheableData; } @@ -67,38 +67,38 @@ class QueryResults { class Iterator { public: - Error GetJSON(WrSerializer &wrser, bool withHdrLen = true); - Error GetCJSON(WrSerializer &wrser, bool withHdrLen = true); - Error GetMsgPack(WrSerializer &wrser, bool withHdrLen = true); - Error GetProtobuf(WrSerializer &wrser, bool withHdrLen = true); - Error GetCSV(WrSerializer &wrser, CsvOrdering &ordering) noexcept; + Error GetJSON(WrSerializer& wrser, bool withHdrLen = true); + Error GetCJSON(WrSerializer& wrser, bool withHdrLen = true); + Error GetMsgPack(WrSerializer& wrser, bool withHdrLen = true); + Error GetProtobuf(WrSerializer& wrser, bool withHdrLen = true); + Error GetCSV(WrSerializer& wrser, CsvOrdering& ordering) noexcept; // use enableHold = false only if you are sure that the item will be destroyed before the queryResults Item GetItem(bool enableHold = true); joins::ItemIterator GetJoined(); - const ItemRef &GetItemRef() const noexcept { return qr_->items_[idx_]; } + const ItemRef& GetItemRef() const noexcept { return qr_->items_[idx_]; } int64_t GetLSN() const noexcept { return qr_->items_[idx_].Value().GetLSN(); } bool IsRaw() const noexcept { return qr_->items_[idx_].Raw(); } std::string_view GetRaw() const noexcept { - auto &itemRef = qr_->items_[idx_]; + auto& itemRef = qr_->items_[idx_]; assertrx(itemRef.Raw()); - return std::string_view(reinterpret_cast(itemRef.Value().Ptr()), itemRef.Value().GetCapacity()); + return std::string_view(reinterpret_cast(itemRef.Value().Ptr()), itemRef.Value().GetCapacity()); } - Iterator &operator++() noexcept { + Iterator& operator++() noexcept { idx_++; return *this; } - Iterator &operator+(int delta) noexcept { + Iterator& operator+(int delta) noexcept { idx_ += delta; return *this; } Error Status() const noexcept { return err_; } - bool operator==(const Iterator &other) const noexcept { return idx_ == other.idx_; } - bool operator!=(const Iterator &other) const noexcept { return !operator==(other); } - Iterator &operator*() noexcept { return *this; } + bool operator==(const Iterator& other) const noexcept { return idx_ == other.idx_; } + bool operator!=(const Iterator& other) const noexcept { return !operator==(other); } + Iterator& operator*() noexcept { return *this; } - const QueryResults *qr_; + const QueryResults* qr_; int idx_; Error err_; using NsNamesCache = h_vector, 1>; @@ -127,28 +127,28 @@ class QueryResults { using ContextsVector = h_vector; ContextsVector ctxs; - void addNSContext(const PayloadType &type, const TagsMatcher &tagsMatcher, const FieldsSet &fieldsFilter, + void addNSContext(const PayloadType& type, const TagsMatcher& tagsMatcher, const FieldsSet& fieldsFilter, std::shared_ptr schema); - const TagsMatcher &getTagsMatcher(int nsid) const noexcept; - const PayloadType &getPayloadType(int nsid) const noexcept; - const FieldsSet &getFieldsFilter(int nsid) const noexcept; - TagsMatcher &getTagsMatcher(int nsid) noexcept; - PayloadType &getPayloadType(int nsid) noexcept; + const TagsMatcher& getTagsMatcher(int nsid) const noexcept; + const PayloadType& getPayloadType(int nsid) const noexcept; + const FieldsSet& getFieldsFilter(int nsid) const noexcept; + TagsMatcher& getTagsMatcher(int nsid) noexcept; + PayloadType& getPayloadType(int nsid) noexcept; std::shared_ptr getSchema(int nsid) const noexcept; int getNsNumber(int nsid) const noexcept; int getMergedNSCount() const noexcept { return ctxs.size(); } - ItemRefVector &Items() noexcept { return items_; } - const ItemRefVector &Items() const { return items_; } + ItemRefVector& Items() noexcept { return items_; } + const ItemRefVector& Items() const { return items_; } int GetJoinedNsCtxIndex(int nsid) const noexcept; // Add owning ns pointer // noLock has always to be 'true' (i.e. this method can only be called unders Namespace's lock) void AddNamespace(NamespaceImplPtr, bool noLock); // Add non-owning ns pointer // noLock has always to be 'true' (i.e. this method can only be called unders Namespace's lock) - void AddNamespace(NamespaceImpl *, bool noLock); - void RemoveNamespace(const NamespaceImpl *ns); - bool IsNamespaceAdded(const NamespaceImpl *ns) const noexcept { - return std::find_if(nsData_.cbegin(), nsData_.cend(), [ns](const NsDataHolder &nsData) { return nsData.ns == ns; }) != + void AddNamespace(NamespaceImpl*, bool noLock); + void RemoveNamespace(const NamespaceImpl* ns); + bool IsNamespaceAdded(const NamespaceImpl* ns) const noexcept { + return std::find_if(nsData_.cbegin(), nsData_.cend(), [ns](const NsDataHolder& nsData) { return nsData.ns == ns; }) != nsData_.cend(); } void MarkAsWALQuery() noexcept { isWalQuery_ = true; } @@ -159,7 +159,7 @@ class QueryResults { private: class EncoderDatasourceWithJoins; class EncoderAdditionalDatasource; - void encodeJSON(int idx, WrSerializer &ser, Iterator::NsNamesCache &) const; + void encodeJSON(int idx, WrSerializer& ser, Iterator::NsNamesCache&) const; public: ItemRefVector items_; @@ -168,18 +168,18 @@ class QueryResults { friend SelectFunctionsHolder; class NsDataHolder { public: - NsDataHolder(NamespaceImplPtr &&_ns, StringsHolderPtr &&strHldr) noexcept; - NsDataHolder(NamespaceImpl *_ns, StringsHolderPtr &&strHldr) noexcept; - NsDataHolder(const NsDataHolder &) = delete; - NsDataHolder(NsDataHolder &&) noexcept = default; - NsDataHolder &operator=(const NsDataHolder &) = delete; - NsDataHolder &operator=(NsDataHolder &&) = default; + NsDataHolder(NamespaceImplPtr&& _ns, StringsHolderPtr&& strHldr) noexcept; + NsDataHolder(NamespaceImpl* _ns, StringsHolderPtr&& strHldr) noexcept; + NsDataHolder(const NsDataHolder&) = delete; + NsDataHolder(NsDataHolder&&) noexcept = default; + NsDataHolder& operator=(const NsDataHolder&) = delete; + NsDataHolder& operator=(NsDataHolder&&) = default; private: NamespaceImplPtr nsPtr_; public: - NamespaceImpl *ns; + NamespaceImpl* ns; StringsHolderPtr strHolder; }; diff --git a/cpp_src/core/queryresults/tableviewbuilder.cc b/cpp_src/core/queryresults/tableviewbuilder.cc index 9b13b5fce..64dc8ca3e 100644 --- a/cpp_src/core/queryresults/tableviewbuilder.cc +++ b/cpp_src/core/queryresults/tableviewbuilder.cc @@ -37,9 +37,13 @@ void TableCalculator::calculate(size_t limit) { const size_t size = std::min(limit, r_.Count()); rows_.reserve(size); for (auto it : r_) { - if (it.IsRaw()) continue; + if (it.IsRaw()) { + continue; + } Error err = it.GetJSON(ser, false); - if (!err.ok()) continue; + if (!err.ok()) { + continue; + } gason::JsonParser parser; gason::JsonNode root = parser.Parse(reindexer::giftStr(ser.Slice())); @@ -59,14 +63,18 @@ void TableCalculator::calculate(size_t limit) { columnData.maxWidthCh = std::max(columnData.maxWidthCh, reindexer::getStringTerminalWidth(fieldName)); } - if (fieldValue.empty()) ++columnData.emptyValues; + if (fieldValue.empty()) { + ++columnData.emptyValues; + } columnData.entries++; rowData[fieldName] = fieldValue; } rows_.emplace_back(std::move(rowData)); - if (++i == size) break; + if (++i == size) { + break; + } ser.Reset(); } @@ -141,7 +149,9 @@ TableViewBuilder::TableViewBuilder(const QueryResultsT& r) : r_(r template void TableViewBuilder::Build(std::ostream& o, const std::function& isCanceled) { - if (isCanceled()) return; + if (isCanceled()) { + return; + } TerminalSize terminalSize = reindexer::getTerminalSize(); TableCalculator tableCalculator(r_, terminalSize.width); BuildHeader(o, tableCalculator, isCanceled); @@ -151,7 +161,9 @@ void TableViewBuilder::Build(std::ostream& o, const std::function template void TableViewBuilder::BuildHeader(std::ostream& o, TableCalculator& tableCalculator, const std::function& isCanceled) { - if (isCanceled()) return; + if (isCanceled()) { + return; + } auto& header = tableCalculator.GetHeader(); auto& columnsData = tableCalculator.GetColumnsSettings(); @@ -166,7 +178,9 @@ void TableViewBuilder::BuildHeader(std::ostream& o, TableCalculat auto& columnData = columnsData[columnName]; ensureFieldWidthIsOk(columnName, columnData.widthCh); o << std::setw(computeFieldWidth(columnName, columnData.widthCh)) << columnName; - if (rowIdx != header.size() - 1) o << kSeparator; + if (rowIdx != header.size() - 1) { + o << kSeparator; + } } o << std::endl << headerLine << std::endl; } @@ -182,7 +196,9 @@ bool TableViewBuilder::isValueMultiline(std::string_view value, b template void TableViewBuilder::startLine(std::ostream& o, const int& currLineWidth) { o << std::endl; - for (size_t i = 0; i < currLineWidth - kSeparator.length(); ++i) o << " "; + for (size_t i = 0; i < currLineWidth - kSeparator.length(); ++i) { + o << " "; + } o << kSeparator; } @@ -217,7 +233,9 @@ void TableViewBuilder::BuildRow(std::ostream& o, int idx, TableCa for (wchar_t wc; (sz = std::mbtowc(&wc, cstr, end - cstr)) > 0; cstr += sz) { currWidth += mk_wcwidth(wc); if (currWidth >= symbolsTillTheEOFLine) { - if (pos != 0) startLine(o, currLineWidth); + if (pos != 0) { + startLine(o, currLineWidth); + } o << std::left; o << value.substr(pos, count); pos = total; @@ -228,7 +246,9 @@ void TableViewBuilder::BuildRow(std::ostream& o, int idx, TableCa } if (count > 0) { - if (pos != 0) startLine(o, currLineWidth); + if (pos != 0) { + startLine(o, currLineWidth); + } o << value.substr(pos, count); } } else { @@ -262,10 +282,14 @@ void TableViewBuilder::BuildRow(std::ostream& o, int idx, TableCa template void TableViewBuilder::BuildTable(std::ostream& o, TableCalculator& tableCalculator, const std::function& isCanceled) { - if (isCanceled()) return; + if (isCanceled()) { + return; + } auto& rows = tableCalculator.GetRows(); for (size_t i = 0; i < rows.size(); ++i) { - if (isCanceled()) return; + if (isCanceled()) { + return; + } BuildRow(o, i, tableCalculator); } } @@ -289,11 +313,15 @@ void TableViewBuilder::ensureFieldWidthIsOk(std::string& str, int int newWidth = 0; static const std::string dots = " ..."; bool withDots = (maxWidth > 10); - if (withDots) maxWidth -= dots.length(); + if (withDots) { + maxWidth -= dots.length(); + } try { for (auto it = str.begin(); it != str.end() && (sz = utf8::internal::sequence_length(it)) > 0;) { newWidth += mk_wcwidth(utf8::next(it, str.end())); - if (newWidth > maxWidth) break; + if (newWidth > maxWidth) { + break; + } n += sz; } } catch (const std::exception&) { @@ -301,7 +329,9 @@ void TableViewBuilder::ensureFieldWidthIsOk(std::string& str, int n = maxWidth; } str = str.substr(0, n); - if (withDots) str += dots; + if (withDots) { + str += dots; + } } } diff --git a/cpp_src/core/querystat.cc b/cpp_src/core/querystat.cc index 7a62b1885..59910ab3f 100644 --- a/cpp_src/core/querystat.cc +++ b/cpp_src/core/querystat.cc @@ -7,7 +7,7 @@ namespace reindexer { template -void QueriesStatTracer::hit(const QuerySQL &sql, std::chrono::microseconds time) { +void QueriesStatTracer::hit(const QuerySQL& sql, std::chrono::microseconds time) { std::unique_lock lck(mtx_); const auto it = stat_.find(sql.normalized); if (it == stat_.end()) { @@ -20,19 +20,21 @@ void QueriesStatTracer::hit(const QuerySQL &sql, std::chrono::microseconds time) } } } -template void QueriesStatTracer::hit<&PerfStatCounterST::Hit>(const QuerySQL &, std::chrono::microseconds); -template void QueriesStatTracer::hit<&PerfStatCounterST::LockHit>(const QuerySQL &, std::chrono::microseconds); +template void QueriesStatTracer::hit<&PerfStatCounterST::Hit>(const QuerySQL&, std::chrono::microseconds); +template void QueriesStatTracer::hit<&PerfStatCounterST::LockHit>(const QuerySQL&, std::chrono::microseconds); const std::vector QueriesStatTracer::Data() { std::unique_lock lck(mtx_); std::vector ret; ret.reserve(stat_.size()); - for (auto &stat : stat_) ret.push_back({stat.first, stat.second.Get(), stat.second.longestQuery}); + for (auto& stat : stat_) { + ret.push_back({stat.first, stat.second.Get(), stat.second.longestQuery}); + } return ret; } -void QueryPerfStat::GetJSON(WrSerializer &ser) const { +void QueryPerfStat::GetJSON(WrSerializer& ser) const { JsonBuilder builder(ser); builder.Put("query", query); diff --git a/cpp_src/core/querystat.h b/cpp_src/core/querystat.h index 2c7dafb08..a6de2b2c1 100644 --- a/cpp_src/core/querystat.h +++ b/cpp_src/core/querystat.h @@ -55,16 +55,22 @@ class QueryStatCalculator { QueryStatCalculator(std::function hitter, std::chrono::microseconds threshold, bool enable, Logger logger = Logger{}) : hitter_(std::move(hitter)), threshold_(threshold), enable_(enable), logger_(std::move(logger)) { - if (enable_) tmStart = system_clock_w::now(); + if (enable_) { + tmStart = system_clock_w::now(); + } } QueryStatCalculator(Logger logger, bool enable = true) : enable_(enable), logger_(std::move(logger)) { - if (enable_) tmStart = system_clock_w::now(); + if (enable_) { + tmStart = system_clock_w::now(); + } } ~QueryStatCalculator() { if (enable_) { auto time = std::chrono::duration_cast(system_clock_w::now() - tmStart); - if (hitter_ && time >= threshold_) hitter_(false, time); + if (hitter_ && time >= threshold_) { + hitter_(false, time); + } if constexpr (Logger::isEnabled) { logger_.Dump(time); @@ -74,7 +80,9 @@ class QueryStatCalculator { void LockHit() { if (enable_ && hitter_) { auto time = std::chrono::duration_cast(system_clock_w::now() - tmStart); - if (time >= threshold_) hitter_(true, time); + if (time >= threshold_) { + hitter_(true, time); + } } } diff --git a/cpp_src/core/rdxcontext.cc b/cpp_src/core/rdxcontext.cc index 37455582d..897203924 100644 --- a/cpp_src/core/rdxcontext.cc +++ b/cpp_src/core/rdxcontext.cc @@ -93,7 +93,9 @@ RdxContext InternalRdxContext::CreateRdxContext(std::string_view query, Activity RdxContext InternalRdxContext::CreateRdxContext(std::string_view query, ActivityContainer& activityContainer, QueryResults& qresults) const { - if (activityTracer_.empty() || query.empty()) return {(deadlineCtx_.IsCancelable() ? &deadlineCtx_ : nullptr), cmpl_}; + if (activityTracer_.empty() || query.empty()) { + return {(deadlineCtx_.IsCancelable() ? &deadlineCtx_ : nullptr), cmpl_}; + } assertrx(!qresults.activityCtx_); qresults.activityCtx_.emplace(activityTracer_, user_, query, activityContainer, connectionId_, true); return RdxContext{&*(qresults.activityCtx_), (deadlineCtx_.IsCancelable() ? &deadlineCtx_ : nullptr), cmpl_}; diff --git a/cpp_src/core/rdxcontext.h b/cpp_src/core/rdxcontext.h index 230d2c401..679b40e78 100644 --- a/cpp_src/core/rdxcontext.h +++ b/cpp_src/core/rdxcontext.h @@ -23,7 +23,9 @@ constexpr std::string_view kDefaultCancelError = "Context was canceled"; template void ThrowOnCancel(const Context& ctx, std::string_view errMsg = std::string_view()) { - if (!ctx.isCancelable()) return; + if (!ctx.isCancelable()) { + return; + } const auto cancel = ctx.checkCancel(); switch (cancel) { @@ -89,7 +91,9 @@ class RdxContext { cmpl_(std::move(cmpl)) {} explicit RdxContext(RdxActivityContext* ptr, const IRdxCancelContext* cancelCtx = nullptr, Completion cmpl = nullptr) noexcept : fromReplication_(false), holdStatus_(ptr ? kPtr : kEmpty), activityPtr_(ptr), cancelCtx_(cancelCtx), cmpl_(std::move(cmpl)) { - if (holdStatus_ == kPtr) activityPtr_->refCount_.fetch_add(1u, std::memory_order_relaxed); + if (holdStatus_ == kPtr) { + activityPtr_->refCount_.fetch_add(1u, std::memory_order_relaxed); + } } RdxContext(RdxContext&& other) noexcept; @@ -101,7 +105,9 @@ class RdxContext { bool isCancelable() const noexcept { return cancelCtx_ && cancelCtx_->IsCancelable(); } CancelType checkCancel() const noexcept { - if (!cancelCtx_) return CancelType::None; + if (!cancelCtx_) { + return CancelType::None; + } return cancelCtx_->GetCancelType(); } /// returning value should be assined to a local variable which will be destroyed after the locking complete diff --git a/cpp_src/core/reindexer.cc b/cpp_src/core/reindexer.cc index 74eb7c2f5..38201cab3 100644 --- a/cpp_src/core/reindexer.cc +++ b/cpp_src/core/reindexer.cc @@ -51,12 +51,8 @@ Error Reindexer::GetMeta(std::string_view nsName, const std::string& key, std::s Error Reindexer::PutMeta(std::string_view nsName, const std::string& key, std::string_view data) { return impl_->PutMeta(nsName, key, data, ctx_); } -Error Reindexer::EnumMeta(std::string_view nsName, std::vector& keys) { - return impl_->EnumMeta(nsName, keys, ctx_); -} -Error Reindexer::DeleteMeta(std::string_view nsName, const std::string& key) { - return impl_->DeleteMeta(nsName, key, ctx_); -} +Error Reindexer::EnumMeta(std::string_view nsName, std::vector& keys) { return impl_->EnumMeta(nsName, keys, ctx_); } +Error Reindexer::DeleteMeta(std::string_view nsName, const std::string& key) { return impl_->DeleteMeta(nsName, key, ctx_); } Error Reindexer::Delete(const Query& q, QueryResults& result) { return impl_->Delete(q, result, ctx_); } Error Reindexer::Select(std::string_view query, QueryResults& result) { return impl_->Select(query, result, ctx_); } Error Reindexer::Select(const Query& q, QueryResults& result) { return impl_->Select(q, result, ctx_); } diff --git a/cpp_src/core/reindexer.h b/cpp_src/core/reindexer.h index c8574cbbd..e3b8adc2b 100644 --- a/cpp_src/core/reindexer.h +++ b/cpp_src/core/reindexer.h @@ -28,7 +28,7 @@ class UpdatesFilters; class Reindexer { public: /// Completion routine - using Completion = std::function; + using Completion = std::function; /// Create Reindexer database object /// @param cfg - general database options @@ -37,10 +37,10 @@ class Reindexer { /// Destroy Reindexer database object ~Reindexer(); /// Create not holding copy - Reindexer(const Reindexer &) noexcept; - Reindexer(Reindexer &&) noexcept; - Reindexer &operator=(const Reindexer &) = delete; - Reindexer &operator=(Reindexer &&) = delete; + Reindexer(const Reindexer&) noexcept; + Reindexer(Reindexer&&) noexcept; + Reindexer& operator=(const Reindexer&) = delete; + Reindexer& operator=(Reindexer&&) = delete; /// Connect - connect to reindexer database in embedded mode /// Cancellation context doesn't affect this call @@ -48,12 +48,12 @@ class Reindexer { /// @param opts - Connect options. May contain any of
/// ConnectOpts::AllowNamespaceErrors() - true: Ignore errors during existing NS's load; false: Return error occurred during NS's load /// ConnectOpts::OpenNamespaces() - true: Need to open all the namespaces; false: Don't open namespaces - Error Connect(const std::string &dsn, ConnectOpts opts = ConnectOpts()); + Error Connect(const std::string& dsn, ConnectOpts opts = ConnectOpts()); /// Enable storage. Must be called before InitSystemNamespaces /// @param storagePath - file system path to database storage /// @param skipPlaceholderCheck - If set, then reindexer will not check folder for placeholder - Error EnableStorage(const std::string &storagePath, bool skipPlaceholderCheck = false); + Error EnableStorage(const std::string& storagePath, bool skipPlaceholderCheck = false); /// Open or create namespace /// @param nsName - Name of namespace @@ -61,10 +61,10 @@ class Reindexer { /// StorageOpts::Enabled() - Enable storage. If storage is disabled, then namespace will be completely in-memory
/// StorageOpts::CreateIfMissing () - Storage will be created, if missing /// @return errOK - On success - Error OpenNamespace(std::string_view nsName, const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing()); + Error OpenNamespace(std::string_view nsName, const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing()); /// Create new namespace. Will fail, if namespace already exists /// @param nsDef - NamespaceDef with namespace initial parameters - Error AddNamespace(const NamespaceDef &nsDef); + Error AddNamespace(const NamespaceDef& nsDef); /// Close namespace. Will free all memory resources, associated with namespace. Forces sync changes to disk /// @param nsName - Name of namespace Error CloseNamespace(std::string_view nsName); @@ -77,19 +77,19 @@ class Reindexer { /// Rename namespace. If namespace with dstNsName exists, then it is replaced. /// @param srcNsName - Name of namespace /// @param dstNsName - desired name of namespace - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName); /// Add index to namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error AddIndex(std::string_view nsName, const IndexDef &index); + Error AddIndex(std::string_view nsName, const IndexDef& index); /// Update index in namespace /// @param nsName - Name of namespace /// @param index - IndexDef with index name and parameters - Error UpdateIndex(std::string_view nsName, const IndexDef &index); + Error UpdateIndex(std::string_view nsName, const IndexDef& index); /// Drop index from namespace /// @param nsName - Name of namespace /// @param index - index name - Error DropIndex(std::string_view nsName, const IndexDef &index); + Error DropIndex(std::string_view nsName, const IndexDef& index); /// Set fields schema for namespace /// @param nsName - Name of namespace /// @param schema - JSON in JsonSchema format @@ -98,79 +98,79 @@ class Reindexer { /// @param nsName - Name of namespace /// @param format - type of Schema: JSON or Protobuf /// @param schema - text representation of schema - Error GetSchema(std::string_view nsName, int format, std::string &schema); + Error GetSchema(std::string_view nsName, int format, std::string& schema); /// Get list of all available namespaces /// @param defs - std::vector of NamespaceDef of available namespaces /// @param opts - Enumeration options - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts); /// Insert new Item to namespace. If item with same PK is already exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Insert(std::string_view nsName, Item &item); + Error Insert(std::string_view nsName, Item& item); /// Insert new Item to namespace. If item with same PK is already exists, when item.GetID will /// return -1, on success inserted item will be added to the result and item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace /// @param result - QueryResults with inserted item. - Error Insert(std::string_view nsName, Item &item, QueryResults &result); + Error Insert(std::string_view nsName, Item& item, QueryResults& result); /// Update Item in namespace. If item with same PK is not exists, when item.GetID will /// return -1, on success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Update(std::string_view nsName, Item &item); + Error Update(std::string_view nsName, Item& item); /// Update Item in namespace. If item with same PK is not exists, when item.GetID will /// return -1, on success updated item will be added to result and item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace /// @param result - QueryResults with updated item. - Error Update(std::string_view nsName, Item &item, QueryResults &result); + Error Update(std::string_view nsName, Item& item, QueryResults& result); /// Updates all items in namespace, that satisfy provided query /// @param query - Query to define items set for update. /// @param result - QueryResults with IDs of updated items. - Error Update(const Query &query, QueryResults &result); + Error Update(const Query& query, QueryResults& result); /// Update or Insert Item in namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Upsert(std::string_view nsName, Item &item); + Error Upsert(std::string_view nsName, Item& item); /// Update or Insert Item in namespace. /// On success upserted item will be added to result and item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace /// @param result - QueryResults with upserted item. - Error Upsert(std::string_view nsName, Item &item, QueryResults &result); + Error Upsert(std::string_view nsName, Item& item, QueryResults& result); /// Delete Item from namespace. On success item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace - Error Delete(std::string_view nsName, Item &item); + Error Delete(std::string_view nsName, Item& item); /// Delete Item from namespace. /// On success deleted item will be added to result and item.GetID() will return internal Item ID /// May be used with completion /// @param nsName - Name of namespace /// @param item - Item, obtained by call to NewItem of the same namespace /// @param result - QueryResults with deleted item. - Error Delete(std::string_view nsName, Item &item, QueryResults &result); + Error Delete(std::string_view nsName, Item& item, QueryResults& result); /// Delete all items from namespace, which matches provided Query /// @param query - Query with conditions /// @param result - QueryResults with IDs of deleted items - Error Delete(const Query &query, QueryResults &result); + Error Delete(const Query& query, QueryResults& result); /// Execute SQL Query and return results /// May be used with completion /// @param query - SQL query. Only "SELECT" semantic is supported /// @param result - QueryResults with found items - Error Select(std::string_view query, QueryResults &result); + Error Select(std::string_view query, QueryResults& result); /// Execute Query and return results /// May be used with completion /// @param query - Query object with query attributes /// @param result - QueryResults with found items - Error Select(const Query &query, QueryResults &result); + Error Select(const Query& query, QueryResults& result); /// Flush changes to storage /// Cancellation context doesn't affect this call /// @param nsName - Name of namespace @@ -186,35 +186,35 @@ class Reindexer { /// Commit transaction - transaction will be deleted after commit /// @param tr - transaction to commit /// @param result - QueryResults with IDs of changed by tx items. - Error CommitTransaction(Transaction &tr, QueryResults &result); + Error CommitTransaction(Transaction& tr, QueryResults& result); /// RollBack transaction - transaction will be deleted after rollback /// Cancellation context doesn't affect this call /// @param tr - transaction to rollback - Error RollBackTransaction(Transaction &tr); + Error RollBackTransaction(Transaction& tr); /// Get metadata from storage by key /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - output string with metadata - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data); /// Put metadata to storage by key /// @param nsName - Name of namespace /// @param key - string with meta key /// @param data - string with metadata - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data); /// Get list of all metadata keys /// @param nsName - Name of namespace /// @param keys - std::vector filled with meta keys - Error EnumMeta(std::string_view nsName, std::vector &keys); + Error EnumMeta(std::string_view nsName, std::vector& keys); /// Delete metadata from storage by key /// @param nsName - Name of namespace /// @param key - string with meta key - Error DeleteMeta(std::string_view nsName, const std::string &key); + Error DeleteMeta(std::string_view nsName, const std::string& key); /// Get possible suggestions for token (set by 'pos') in Sql query. /// Cancellation context doesn't affect this call /// @param sqlQuery - sql query. /// @param pos - position in sql query for suggestions. /// @param suggestions - all the suggestions for 'pos' position in query. - Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector &suggestions); + Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector& suggestions); /// Get current connection status Error Status(); @@ -227,20 +227,20 @@ class Reindexer { /// @param observer - Observer interface, which will receive updates /// @param filters - Subscription filters set /// @param opts - Subscription options (allows to either add new filters or reset them) - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts = SubscriptionOpts()); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts = SubscriptionOpts()); /// Unsubscribe from updates of database /// Cancellation context doesn't affect this call /// @param observer - Observer interface, which will be unsubscribed updates - Error UnsubscribeUpdates(IUpdatesObserver *observer); + Error UnsubscribeUpdates(IUpdatesObserver* observer); /// Builds Protobuf schema in ser. /// @param ser - schema output buffer /// @param namespaces - list of namespaces to be embedded in .proto - Error GetProtobufSchema(WrSerializer &ser, std::vector &namespaces); + Error GetProtobufSchema(WrSerializer& ser, std::vector& namespaces); /// Add cancelable context /// @param ctx - context pointer - Reindexer WithContext(const IRdxCancelContext *ctx) const { return Reindexer(impl_, ctx_.WithCancelParent(ctx)); } + Reindexer WithContext(const IRdxCancelContext* ctx) const { return Reindexer(impl_, ctx_.WithCancelParent(ctx)); } /// Add execution timeout to the next query /// @param timeout - Execution timeout Reindexer WithTimeout(milliseconds timeout) const { return Reindexer(impl_, ctx_.WithTimeout(timeout)); } @@ -251,10 +251,10 @@ class Reindexer { /// @param activityTracer - name of activity tracer /// @param user - user identifying information /// @param connectionId - unique identifier for the connection - Reindexer WithActivityTracer(std::string_view activityTracer, std::string &&user, int connectionId) const { + Reindexer WithActivityTracer(std::string_view activityTracer, std::string&& user, int connectionId) const { return Reindexer(impl_, ctx_.WithActivityTracer(activityTracer, std::move(user), connectionId)); } - Reindexer WithActivityTracer(std::string_view activityTracer, std::string &&user) const { + Reindexer WithActivityTracer(std::string_view activityTracer, std::string&& user) const { return Reindexer(impl_, ctx_.WithActivityTracer(activityTracer, std::move(user))); } /// Allows to set multiple context params at once @@ -270,10 +270,10 @@ class Reindexer { /// @param activityTracer - name of activity tracer /// @param user - user identifying information /// @param connectionId - unique identifier for the connection - void SetActivityTracer(std::string &&activityTracer, std::string &&user, int connectionId) { + void SetActivityTracer(std::string&& activityTracer, std::string&& user, int connectionId) { ctx_.SetActivityTracer(std::move(activityTracer), std::move(user), connectionId); } - void SetActivityTracer(std::string &&activityTracer, std::string &&user) { + void SetActivityTracer(std::string&& activityTracer, std::string&& user) { ctx_.SetActivityTracer(std::move(activityTracer), std::move(user)); } @@ -282,12 +282,12 @@ class Reindexer { typedef QueryResults QueryResultsT; typedef Item ItemT; - Error DumpIndex(std::ostream &os, std::string_view nsName, std::string_view index); + Error DumpIndex(std::ostream& os, std::string_view nsName, std::string_view index); private: - Reindexer(ReindexerImpl *impl, InternalRdxContext &&ctx) noexcept : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} + Reindexer(ReindexerImpl* impl, InternalRdxContext&& ctx) noexcept : impl_(impl), owner_(false), ctx_(std::move(ctx)) {} - ReindexerImpl *impl_; + ReindexerImpl* impl_; bool owner_; InternalRdxContext ctx_; }; diff --git a/cpp_src/core/reindexer_impl/reindexerimpl.cc b/cpp_src/core/reindexer_impl/reindexerimpl.cc index 6913236c0..278d5cb91 100644 --- a/cpp_src/core/reindexer_impl/reindexerimpl.cc +++ b/cpp_src/core/reindexer_impl/reindexerimpl.cc @@ -114,7 +114,9 @@ Error ReindexerImpl::EnableStorage(const std::string& storagePath, bool skipPlac return Error(errParams, "Storage already enabled"); } - if (storagePath.empty()) return errOK; + if (storagePath.empty()) { + return errOK; + } if (fs::MkDirAll(storagePath) < 0) { return Error(errParams, "Can't create directory '%s' for reindexer storage - reason %s", storagePath, strerror(errno)); } @@ -129,7 +131,9 @@ Error ReindexerImpl::EnableStorage(const std::string& storagePath, bool skipPlac if (entry.name != "." && entry.name != ".." && entry.name != kStoragePlaceholderFilename) { isEmpty = false; } - if (entry.name == kConfigNamespace) isHaveConfig = true; + if (entry.name == kConfigNamespace) { + isHaveConfig = true; + } } if (!isEmpty && !skipPlaceholderCheck) { @@ -228,14 +232,18 @@ Error ReindexerImpl::Connect(const std::string& dsn, ConnectOpts opts) { bool enableStorage = (path.length() > 0 && path != "/"); if (enableStorage) { auto err = EnableStorage(path); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } if (fs::ReadDir(path, foundNs) < 0) { return Error(errParams, "Can't read database dir %s", path); } } Error err = InitSystemNamespaces(); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } if (enableStorage && opts.IsOpenNamespaces()) { boost::sort::pdqsort_branchless(foundNs.begin(), foundNs.end(), [](const fs::DirEntry& ld, const fs::DirEntry& rd) noexcept { @@ -277,7 +285,9 @@ Error ReindexerImpl::Connect(const std::string& dsn, ConnectOpts opts) { } }); } - for (size_t i = 0; i < maxLoadWorkers; ++i) thrs[i].join(); + for (size_t i = 0; i < maxLoadWorkers; ++i) { + thrs[i].join(); + } if (!opts.IsAllowNamespaceErrors() && hasNsErrors.test_and_set(std::memory_order_relaxed)) { return Error(errNotValid, "Namespaces load error"); @@ -286,7 +296,9 @@ Error ReindexerImpl::Connect(const std::string& dsn, ConnectOpts opts) { if (replicationEnabled_) { err = checkReplConf(opts); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } replicator_->Enable(); bool needStart = replicator_->Configure(configProvider_.GetReplicationConfig()); @@ -367,12 +379,16 @@ Error ReindexerImpl::addNamespace(const NamespaceDef& nsDef, const RdxContext& r ULock lock(mtx_, rdxCtx); namespaces_.insert({nsDef.name, ns}); } - if (!nsDef.isTemporary) observers_.OnWALUpdate(LSNPair(), nsDef.name, WALRecord(WalNamespaceAdd)); + if (!nsDef.isTemporary) { + observers_.OnWALUpdate(LSNPair(), nsDef.name, WALRecord(WalNamespaceAdd)); + } for (auto& indexDef : nsDef.indexes) { ns->AddIndex(indexDef, rdxCtx); } ns->SetSchema(nsDef.schemaJson, rdxCtx); - if (nsDef.storage.IsSlaveMode()) ns->setSlaveMode(rdxCtx); + if (nsDef.storage.IsSlaveMode()) { + ns->setSlaveMode(rdxCtx); + } } catch (const Error& err) { return err; @@ -387,7 +403,9 @@ Error ReindexerImpl::openNamespace(std::string_view name, const StorageOpts& sto SLock lock(mtx_, rdxCtx); auto nsIt = namespaces_.find(name); if (nsIt != namespaces_.end() && nsIt->second) { - if (storageOpts.IsSlaveMode()) nsIt->second->setSlaveMode(rdxCtx); + if (storageOpts.IsSlaveMode()) { + nsIt->second->setSlaveMode(rdxCtx); + } return {}; } } @@ -396,7 +414,9 @@ Error ReindexerImpl::openNamespace(std::string_view name, const StorageOpts& sto } std::string nameStr(name); auto ns = std::make_shared(nameStr, observers_, bgDeleter_); - if (storageOpts.IsSlaveMode()) ns->setSlaveMode(rdxCtx); + if (storageOpts.IsSlaveMode()) { + ns->setSlaveMode(rdxCtx); + } if (storageOpts.IsEnabled() && !storagePath_.empty()) { auto opts = storageOpts; ns->EnableStorage(storagePath_, opts.Autorepair(autorepairEnabled_), storageType_, rdxCtx); @@ -493,7 +513,9 @@ Error ReindexerImpl::TruncateNamespace(std::string_view nsName, const InternalRd } catch (const Error& e) { err = e; } - if (ctx.Compl()) ctx.Compl()(err); + if (ctx.Compl()) { + ctx.Compl()(err); + } return err; } @@ -582,7 +604,9 @@ Error ReindexerImpl::renameNamespace(std::string_view srcNsName, const std::stri } namespaces_.erase(srcIt); namespaces_[dstNsName] = std::move(srcNs); - if (needWalUpdate) observers_.OnWALUpdate(LSNPair(), srcNsName, WALRecord(WalNamespaceRename, dstNsName)); + if (needWalUpdate) { + observers_.OnWALUpdate(LSNPair(), srcNsName, WALRecord(WalNamespaceRename, dstNsName)); + } } else { return Error(errLogic, "Can't rename namespace in slave mode '%s'", srcNsName); } @@ -607,7 +631,9 @@ Error ReindexerImpl::applyNsFunction(std::string_view nsName, const InternalRdxC } catch (const Error& e) { err = e; } - if (ctx.Compl()) ctx.Compl()(err); + if (ctx.Compl()) { + ctx.Compl()(err); + } return err; } @@ -636,7 +662,9 @@ Error ReindexerImpl::applyNsFunction(std::string_view nsName, const InternalRdxC } catch (const Error& e) { err = e; } - if (ctx.Compl()) ctx.Compl()(err); + if (ctx.Compl()) { + ctx.Compl()(err); + } return err; } @@ -667,7 +695,9 @@ static WrSerializer& printPkFields(const Item& item, WrSerializer& ser) { size_t jsonPathIdx = 0; const FieldsSet fields = item.PkFields(); for (auto it = fields.begin(); it != fields.end(); ++it) { - if (it != fields.begin()) ser << " AND "; + if (it != fields.begin()) { + ser << " AND "; + } int field = *it; if (field == IndexValueType::SetByJsonPath) { assertrx(jsonPathIdx < fields.getTagsPathsLength()); @@ -846,14 +876,18 @@ Error ReindexerImpl::Select(std::string_view query, QueryResults& result, const err = e; } - if (ctx.Compl()) ctx.Compl()(err); + if (ctx.Compl()) { + ctx.Compl()(err); + } return err; } Error ReindexerImpl::Select(const Query& q, QueryResults& result, const InternalRdxContext& ctx) { try { WrSerializer normalizedSQL, nonNormalizedSQL; - if (ctx.NeedTraceActivity()) q.GetSQL(nonNormalizedSQL, false); + if (ctx.NeedTraceActivity()) { + q.GetSQL(nonNormalizedSQL, false); + } const auto rdxCtx = ctx.CreateRdxContext(ctx.NeedTraceActivity() ? nonNormalizedSQL.Slice() : "", activities_, result); RxSelector::NsLocker locks(rdxCtx); @@ -866,16 +900,20 @@ Error ReindexerImpl::Select(const Query& q, QueryResults& result, const Internal auto& tracker = queriesStatTracker_; if (queriesPerfStatsEnabled) { q.GetSQL(normalizedSQL, true); - if (!ctx.NeedTraceActivity()) q.GetSQL(nonNormalizedSQL, false); + if (!ctx.NeedTraceActivity()) { + q.GetSQL(nonNormalizedSQL, false); + } } const QueriesStatTracer::QuerySQL sql{normalizedSQL.Slice(), nonNormalizedSQL.Slice()}; auto hitter = queriesPerfStatsEnabled ? [&sql, &tracker](bool lockHit, std::chrono::microseconds time) { - if (lockHit) + if (lockHit){ tracker.LockHit(sql, time); - else +} + else{ tracker.Hit(sql, time); +} } : std::function{}; const bool isSystemNsRequest = isSystemNamespaceNameFast(q.NsName()); @@ -916,10 +954,14 @@ Error ReindexerImpl::Select(const Query& q, QueryResults& result, const Internal RxSelector::DoSelect(q, result, locks, func, rdxCtx, statCalculator); func.Process(result); } catch (const Error& err) { - if (ctx.Compl()) ctx.Compl()(err); + if (ctx.Compl()) { + ctx.Compl()(err); + } return err; } - if (ctx.Compl()) ctx.Compl()(Error()); + if (ctx.Compl()) { + ctx.Compl()(Error()); + } return Error(); } @@ -1016,7 +1058,9 @@ Error ReindexerImpl::EnumNamespaces(std::vector& defs, EnumNamespa const auto rdxCtx = ctx.CreateRdxContext("SELECT NAMESPACES", activities_); auto nsarray = getNamespaces(rdxCtx); for (auto& nspair : nsarray) { - if (!opts.MatchFilter(nspair.first)) continue; + if (!opts.MatchFilter(nspair.first)) { + continue; + } NamespaceDef nsDef(nspair.first); if (!opts.IsOnlyNames()) { nsDef = nspair.second->GetDefinition(rdxCtx); @@ -1028,13 +1072,17 @@ Error ReindexerImpl::EnumNamespaces(std::vector& defs, EnumNamespa if (opts.IsWithClosed() && !storagePath_.empty()) { std::vector dirs; - if (fs::ReadDir(storagePath_, dirs) != 0) return Error(errLogic, "Could not read database dir"); + if (fs::ReadDir(storagePath_, dirs) != 0) { + return Error(errLogic, "Could not read database dir"); + } for (auto& d : dirs) { if (d.isDir && d.name != "." && d.name != ".." && opts.MatchFilter(d.name)) { { SLock lock(mtx_, rdxCtx); - if (namespaces_.find(d.name) != namespaces_.end()) continue; + if (namespaces_.find(d.name) != namespaces_.end()) { + continue; + } } std::unique_ptr tmpNs{new NamespaceImpl(d.name, observers_)}; try { @@ -1188,7 +1236,9 @@ Error ReindexerImpl::InitSystemNamespaces() { QueryResults results; auto err = Select(Query(kConfigNamespace), results); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } bool hasReplicatorConfig = false; if (results.Count() == 0) { @@ -1206,11 +1256,17 @@ Error ReindexerImpl::InitSystemNamespaces() { } Item item = NewItem(kConfigNamespace); - if (!item.Status().ok()) return item.Status(); + if (!item.Status().ok()) { + return item.Status(); + } err = item.FromJSON(conf); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } err = Insert(kConfigNamespace, item); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } } else { // Load config from namespace #config @@ -1298,7 +1354,9 @@ void ReindexerImpl::updateToSystemNamespace(std::string_view nsName, Item& item, } } if (replicationEnabled_ && needStartReplicator && !dbDestroyed_) { - if (Error err = replicator_->Start()) throw err; + if (Error err = replicator_->Start()) { + throw err; + } } } catch (gason::Exception& e) { throw Error(errParseJson, "JSON parsing error: %s", e.what()); @@ -1306,7 +1364,9 @@ void ReindexerImpl::updateToSystemNamespace(std::string_view nsName, Item& item, } else if (nsName == kQueriesPerfStatsNamespace) { queriesStatTracker_.Reset(); } else if (nsName == kPerfStatsNamespace) { - for (auto& ns : getNamespaces(ctx)) ns.second->ResetPerfStat(ctx); + for (auto& ns : getNamespaces(ctx)) { + ns.second->ResetPerfStat(ctx); + } } } @@ -1317,7 +1377,9 @@ void ReindexerImpl::updateConfigProvider(const gason::JsonNode& config) { } catch (const gason::Exception& ex) { err = Error(errParseJson, "updateConfigProvider: %s", ex.what()); } - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } } void ReindexerImpl::updateReplicationConfFile() { @@ -1412,7 +1474,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) continue; } } - if (isSystemNamespaceNameFast(nspair.first) && !withSystem) continue; + if (isSystemNamespaceNameFast(nspair.first) && !withSystem) { + continue; + } ser.Reset(); if (filler(nspair.first, nspair.second, ser)) { auto& item = items.emplace_back(sysNs->NewItem(ctx)); @@ -1435,7 +1499,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) [&ctx](std::string_view nsName, const Namespace::Ptr& nsPtr, WrSerializer& ser) { auto stats = nsPtr->GetPerfStat(ctx); bool notRenamed = (stats.name == nsName); - if (notRenamed) stats.GetJSON(ser); + if (notRenamed) { + stats.GetJSON(ser); + } return notRenamed; }); } @@ -1445,7 +1511,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) [&ctx](std::string_view nsName, const Namespace::Ptr& nsPtr, WrSerializer& ser) { auto stats = nsPtr->GetMemStat(ctx); bool notRenamed = (stats.name == nsName); - if (notRenamed) stats.GetJSON(ser); + if (notRenamed) { + stats.GetJSON(ser); + } return notRenamed; }); } @@ -1454,7 +1522,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) [&ctx](std::string_view nsName, const Namespace::Ptr& nsPtr, WrSerializer& ser) { auto stats = nsPtr->GetDefinition(ctx); bool notRenamed = (stats.name == nsName); - if (notRenamed) stats.GetJSON(ser, kIndexJSONWithDescribe); + if (notRenamed) { + stats.GetJSON(ser, kIndexJSONWithDescribe); + } return notRenamed; }); } else if (sysNsName == kQueriesPerfStatsNamespace) { @@ -1472,7 +1542,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) throw item.Status(); } auto err = item.FromJSON(ser.Slice()); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } } queriesperfstatsNs->Refill(items, ctx); } @@ -1490,7 +1562,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) throw item.Status(); } auto err = item.FromJSON(ser.Slice()); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } } activityNs->Refill(items, ctx); } else if (sysNsName == kClientsStatsNamespace) { @@ -1521,7 +1595,9 @@ ReindexerImpl::FilterNsNamesT ReindexerImpl::detectFilterNsNames(const Query& q) throw item.Status(); } auto err = item.FromJSON(ser.Slice()); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } } clientsNs->Refill(items, ctx); } @@ -1587,7 +1663,9 @@ Error ReindexerImpl::GetProtobufSchema(WrSerializer& ser, std::vector; template - Error applyNsFunction(std::string_view nsName, const InternalRdxContext &ctx, const MakeCtxStrFn &makeCtxStr, Arg arg, Args... args); + Error applyNsFunction(std::string_view nsName, const InternalRdxContext& ctx, const MakeCtxStrFn& makeCtxStr, Arg arg, Args... args); template - Error applyNsFunction(std::string_view nsName, const InternalRdxContext &ctx, const MakeCtxStrFn &makeCtxStr, Arg &, Args...); + Error applyNsFunction(std::string_view nsName, const InternalRdxContext& ctx, const MakeCtxStrFn& makeCtxStr, Arg&, Args...); public: - using Completion = std::function; + using Completion = std::function; ReindexerImpl(ReindexerConfig cfg = ReindexerConfig()); ~ReindexerImpl(); - Error Connect(const std::string &dsn, ConnectOpts opts = ConnectOpts()); - Error EnableStorage(const std::string &storagePath, bool skipPlaceholderCheck = false, - const InternalRdxContext &ctx = InternalRdxContext()); - Error OpenNamespace(std::string_view nsName, const StorageOpts &opts = StorageOpts().Enabled().CreateIfMissing(), - const InternalRdxContext &ctx = InternalRdxContext()); - Error AddNamespace(const NamespaceDef &nsDef, const InternalRdxContext &ctx = InternalRdxContext()); - Error CloseNamespace(std::string_view nsName, const InternalRdxContext &ctx = InternalRdxContext()); - Error DropNamespace(std::string_view nsName, const InternalRdxContext &ctx = InternalRdxContext()); - Error TruncateNamespace(std::string_view nsName, const InternalRdxContext &ctx = InternalRdxContext()); - Error RenameNamespace(std::string_view srcNsName, const std::string &dstNsName, const InternalRdxContext &ctx = InternalRdxContext()); - Error AddIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx = InternalRdxContext()); - Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext &ctx = InternalRdxContext()); - Error GetSchema(std::string_view nsName, int format, std::string &schema, const InternalRdxContext &ctx = InternalRdxContext()); - Error UpdateIndex(std::string_view nsName, const IndexDef &indexDef, const InternalRdxContext &ctx = InternalRdxContext()); - Error DropIndex(std::string_view nsName, const IndexDef &index, const InternalRdxContext &ctx = InternalRdxContext()); - Error EnumNamespaces(std::vector &defs, EnumNamespacesOpts opts, const InternalRdxContext &ctx = InternalRdxContext()); - Error Insert(std::string_view nsName, Item &item, const InternalRdxContext &ctx = InternalRdxContext()); - Error Insert(std::string_view nsName, Item &item, QueryResults &, const InternalRdxContext &ctx = InternalRdxContext()); - Error Update(std::string_view nsName, Item &item, const InternalRdxContext &ctx = InternalRdxContext()); - Error Update(std::string_view nsName, Item &item, QueryResults &, const InternalRdxContext &ctx = InternalRdxContext()); - Error Update(const Query &query, QueryResults &result, const InternalRdxContext &ctx = InternalRdxContext()); - Error Upsert(std::string_view nsName, Item &item, const InternalRdxContext &ctx = InternalRdxContext()); - Error Upsert(std::string_view nsName, Item &item, QueryResults &, const InternalRdxContext &ctx = InternalRdxContext()); - Error Delete(std::string_view nsName, Item &item, const InternalRdxContext &ctx = InternalRdxContext()); - Error Delete(std::string_view nsName, Item &item, QueryResults &, const InternalRdxContext &ctx = InternalRdxContext()); - Error Delete(const Query &query, QueryResults &result, const InternalRdxContext &ctx = InternalRdxContext()); - Error Select(std::string_view query, QueryResults &result, const InternalRdxContext &ctx = InternalRdxContext()); - Error Select(const Query &query, QueryResults &result, const InternalRdxContext &ctx = InternalRdxContext()); + Error Connect(const std::string& dsn, ConnectOpts opts = ConnectOpts()); + Error EnableStorage(const std::string& storagePath, bool skipPlaceholderCheck = false, + const InternalRdxContext& ctx = InternalRdxContext()); + Error OpenNamespace(std::string_view nsName, const StorageOpts& opts = StorageOpts().Enabled().CreateIfMissing(), + const InternalRdxContext& ctx = InternalRdxContext()); + Error AddNamespace(const NamespaceDef& nsDef, const InternalRdxContext& ctx = InternalRdxContext()); + Error CloseNamespace(std::string_view nsName, const InternalRdxContext& ctx = InternalRdxContext()); + Error DropNamespace(std::string_view nsName, const InternalRdxContext& ctx = InternalRdxContext()); + Error TruncateNamespace(std::string_view nsName, const InternalRdxContext& ctx = InternalRdxContext()); + Error RenameNamespace(std::string_view srcNsName, const std::string& dstNsName, const InternalRdxContext& ctx = InternalRdxContext()); + Error AddIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx = InternalRdxContext()); + Error SetSchema(std::string_view nsName, std::string_view schema, const InternalRdxContext& ctx = InternalRdxContext()); + Error GetSchema(std::string_view nsName, int format, std::string& schema, const InternalRdxContext& ctx = InternalRdxContext()); + Error UpdateIndex(std::string_view nsName, const IndexDef& indexDef, const InternalRdxContext& ctx = InternalRdxContext()); + Error DropIndex(std::string_view nsName, const IndexDef& index, const InternalRdxContext& ctx = InternalRdxContext()); + Error EnumNamespaces(std::vector& defs, EnumNamespacesOpts opts, const InternalRdxContext& ctx = InternalRdxContext()); + Error Insert(std::string_view nsName, Item& item, const InternalRdxContext& ctx = InternalRdxContext()); + Error Insert(std::string_view nsName, Item& item, QueryResults&, const InternalRdxContext& ctx = InternalRdxContext()); + Error Update(std::string_view nsName, Item& item, const InternalRdxContext& ctx = InternalRdxContext()); + Error Update(std::string_view nsName, Item& item, QueryResults&, const InternalRdxContext& ctx = InternalRdxContext()); + Error Update(const Query& query, QueryResults& result, const InternalRdxContext& ctx = InternalRdxContext()); + Error Upsert(std::string_view nsName, Item& item, const InternalRdxContext& ctx = InternalRdxContext()); + Error Upsert(std::string_view nsName, Item& item, QueryResults&, const InternalRdxContext& ctx = InternalRdxContext()); + Error Delete(std::string_view nsName, Item& item, const InternalRdxContext& ctx = InternalRdxContext()); + Error Delete(std::string_view nsName, Item& item, QueryResults&, const InternalRdxContext& ctx = InternalRdxContext()); + Error Delete(const Query& query, QueryResults& result, const InternalRdxContext& ctx = InternalRdxContext()); + Error Select(std::string_view query, QueryResults& result, const InternalRdxContext& ctx = InternalRdxContext()); + Error Select(const Query& query, QueryResults& result, const InternalRdxContext& ctx = InternalRdxContext()); Error Commit(std::string_view nsName); - Item NewItem(std::string_view nsName, const InternalRdxContext &ctx = InternalRdxContext()); + Item NewItem(std::string_view nsName, const InternalRdxContext& ctx = InternalRdxContext()); - Transaction NewTransaction(std::string_view nsName, const InternalRdxContext &ctx = InternalRdxContext()); - Error CommitTransaction(Transaction &tr, QueryResults &result, const InternalRdxContext &ctx = InternalRdxContext()); - Error RollBackTransaction(Transaction &tr); + Transaction NewTransaction(std::string_view nsName, const InternalRdxContext& ctx = InternalRdxContext()); + Error CommitTransaction(Transaction& tr, QueryResults& result, const InternalRdxContext& ctx = InternalRdxContext()); + Error RollBackTransaction(Transaction& tr); - Error GetMeta(std::string_view nsName, const std::string &key, std::string &data, const InternalRdxContext &ctx = InternalRdxContext()); - Error PutMeta(std::string_view nsName, const std::string &key, std::string_view data, - const InternalRdxContext &ctx = InternalRdxContext()); - Error EnumMeta(std::string_view nsName, std::vector &keys, const InternalRdxContext &ctx = InternalRdxContext()); - Error DeleteMeta(std::string_view nsName, const std::string &key, const InternalRdxContext &ctx = InternalRdxContext()); + Error GetMeta(std::string_view nsName, const std::string& key, std::string& data, const InternalRdxContext& ctx = InternalRdxContext()); + Error PutMeta(std::string_view nsName, const std::string& key, std::string_view data, + const InternalRdxContext& ctx = InternalRdxContext()); + Error EnumMeta(std::string_view nsName, std::vector& keys, const InternalRdxContext& ctx = InternalRdxContext()); + Error DeleteMeta(std::string_view nsName, const std::string& key, const InternalRdxContext& ctx = InternalRdxContext()); Error InitSystemNamespaces(); - Error SubscribeUpdates(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts); - Error UnsubscribeUpdates(IUpdatesObserver *observer); - Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector &suggestions, - const InternalRdxContext &ctx = InternalRdxContext()); - Error GetProtobufSchema(WrSerializer &ser, std::vector &namespaces); + Error SubscribeUpdates(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts); + Error UnsubscribeUpdates(IUpdatesObserver* observer); + Error GetSqlSuggestions(std::string_view sqlQuery, int pos, std::vector& suggestions, + const InternalRdxContext& ctx = InternalRdxContext()); + Error GetProtobufSchema(WrSerializer& ser, std::vector& namespaces); Error Status(); bool NeedTraceActivity() const noexcept { return configProvider_.ActivityStatsEnabled(); } - Error DumpIndex(std::ostream &os, std::string_view nsName, std::string_view index, - const InternalRdxContext &ctx = InternalRdxContext()); + Error DumpIndex(std::ostream& os, std::string_view nsName, std::string_view index, + const InternalRdxContext& ctx = InternalRdxContext()); private: typedef contexted_shared_lock SLock; @@ -101,10 +101,10 @@ class ReindexerImpl { ~BackgroundThread() { Stop(); } template - void Run(F &&f) { + void Run(F&& f) { Stop(); async_.set(loop_); - async_.set([this](net::ev::async &) noexcept { loop_.break_loop(); }); + async_.set([this](net::ev::async&) noexcept { loop_.break_loop(); }); async_.start(); th_ = std::thread(std::forward(f), std::ref(loop_)); } @@ -127,37 +127,37 @@ class ReindexerImpl { using StatsLockT = contexted_unique_lock; StatsLocker(); - [[nodiscard]] StatsLockT LockIfRequired(std::string_view sysNsName, const RdxContext &); + [[nodiscard]] StatsLockT LockIfRequired(std::string_view sysNsName, const RdxContext&); private: std::unordered_map mtxMap_; }; - FilterNsNamesT detectFilterNsNames(const Query &q); - [[nodiscard]] StatsLocker::StatsLockT syncSystemNamespaces(std::string_view sysNsName, const FilterNsNamesT &, const RdxContext &); + FilterNsNamesT detectFilterNsNames(const Query& q); + [[nodiscard]] StatsLocker::StatsLockT syncSystemNamespaces(std::string_view sysNsName, const FilterNsNamesT&, const RdxContext&); void createSystemNamespaces(); - void updateToSystemNamespace(std::string_view nsName, Item &, const RdxContext &ctx); - void updateConfigProvider(const gason::JsonNode &config); + void updateToSystemNamespace(std::string_view nsName, Item&, const RdxContext& ctx); + void updateConfigProvider(const gason::JsonNode& config); void updateReplicationConfFile(); void onProfiligConfigLoad(); Error tryLoadReplicatorConfFromFile(); - Error tryLoadReplicatorConfFromYAML(const std::string &yamlReplConf); + Error tryLoadReplicatorConfFromYAML(const std::string& yamlReplConf); - void backgroundRoutine(net::ev::dynamic_loop &loop); - void storageFlushingRoutine(net::ev::dynamic_loop &loop); - Error closeNamespace(std::string_view nsName, const RdxContext &ctx, bool dropStorage, bool enableDropSlave = false); + void backgroundRoutine(net::ev::dynamic_loop& loop); + void storageFlushingRoutine(net::ev::dynamic_loop& loop); + Error closeNamespace(std::string_view nsName, const RdxContext& ctx, bool dropStorage, bool enableDropSlave = false); - Error syncDownstream(std::string_view nsName, bool force, const InternalRdxContext &ctx = InternalRdxContext()); + Error syncDownstream(std::string_view nsName, bool force, const InternalRdxContext& ctx = InternalRdxContext()); - Namespace::Ptr getNamespace(std::string_view nsName, const RdxContext &ctx); - Namespace::Ptr getNamespaceNoThrow(std::string_view nsName, const RdxContext &ctx); + Namespace::Ptr getNamespace(std::string_view nsName, const RdxContext& ctx); + Namespace::Ptr getNamespaceNoThrow(std::string_view nsName, const RdxContext& ctx); - std::vector> getNamespaces(const RdxContext &ctx); - std::vector getNamespacesNames(const RdxContext &ctx); - Error renameNamespace(std::string_view srcNsName, const std::string &dstNsName, bool fromReplication = false, - const InternalRdxContext &ctx = InternalRdxContext()); - Error openNamespace(std::string_view name, const StorageOpts &storageOpts, const RdxContext &rdxCtx); - Error addNamespace(const NamespaceDef &nsDef, const RdxContext &rdxCtx); + std::vector> getNamespaces(const RdxContext& ctx); + std::vector getNamespacesNames(const RdxContext& ctx); + Error renameNamespace(std::string_view srcNsName, const std::string& dstNsName, bool fromReplication = false, + const InternalRdxContext& ctx = InternalRdxContext()); + Error openNamespace(std::string_view name, const StorageOpts& storageOpts, const RdxContext& rdxCtx); + Error addNamespace(const NamespaceDef& nsDef, const RdxContext& rdxCtx); [[nodiscard]] bool isSystemNamespaceNameStrict(std::string_view name) noexcept; @@ -190,7 +190,7 @@ class ReindexerImpl { bool replicationEnabled_ = true; std::atomic connected_ = {false}; - IClientsStats *clientsStats_ = nullptr; + IClientsStats* clientsStats_ = nullptr; friend class Replicator; friend class TransactionImpl; diff --git a/cpp_src/core/reindexer_impl/rx_selector.cc b/cpp_src/core/reindexer_impl/rx_selector.cc index ac49dd50f..bba7b9e87 100644 --- a/cpp_src/core/reindexer_impl/rx_selector.cc +++ b/cpp_src/core/reindexer_impl/rx_selector.cc @@ -188,7 +188,9 @@ void RxSelector::DoSelect(const Query& q, QueryResults& result, NsLocker& loc } } // Adding context to QueryResults - for (const auto& jctx : joinQueryResultsContexts) result.addNSContext(jctx.type_, jctx.tagsMatcher_, jctx.fieldsFilter_, jctx.schema_); + for (const auto& jctx : joinQueryResultsContexts) { + result.addNSContext(jctx.type_, jctx.tagsMatcher_, jctx.fieldsFilter_, jctx.schema_); + } } [[nodiscard]] static bool byJoinedField(std::string_view sortExpr, std::string_view joinedNs) { @@ -198,21 +200,31 @@ void RxSelector::DoSelect(const Query& q, QueryResults& result, NsLocker& loc 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '.', '+'}; std::string_view::size_type i = 0; const auto s = sortExpr.size(); - while (i < s && isspace(sortExpr[i])) ++i; + while (i < s && isspace(sortExpr[i])) { + ++i; + } bool inQuotes = false; if (i < s && sortExpr[i] == '"') { ++i; inQuotes = true; } - while (i < s && isspace(sortExpr[i])) ++i; + while (i < s && isspace(sortExpr[i])) { + ++i; + } std::string_view::size_type j = 0, s2 = joinedNs.size(); for (; j < s2 && i < s; ++i, ++j) { - if (sortExpr[i] != joinedNs[j]) return false; + if (sortExpr[i] != joinedNs[j]) { + return false; + } + } + if (i >= s || sortExpr[i] != '.') { + return false; } - if (i >= s || sortExpr[i] != '.') return false; for (++i; i < s; ++i) { if (!kJoinedIndexNameSyms.test(sortExpr[i])) { - if (isspace(sortExpr[i])) break; + if (isspace(sortExpr[i])) { + break; + } if (inQuotes && sortExpr[i] == '"') { inQuotes = false; ++i; @@ -221,9 +233,15 @@ void RxSelector::DoSelect(const Query& q, QueryResults& result, NsLocker& loc return false; } } - while (i < s && isspace(sortExpr[i])) ++i; - if (inQuotes && i < s && sortExpr[i] == '"') ++i; - while (i < s && isspace(sortExpr[i])) ++i; + while (i < s && isspace(sortExpr[i])) { + ++i; + } + if (inQuotes && i < s && sortExpr[i] == '"') { + ++i; + } + while (i < s && isspace(sortExpr[i])) { + ++i; + } return i == s; } @@ -395,7 +413,9 @@ template JoinedSelectors RxSelector::prepareJoinedSelectors(const Query& q, QueryResults& result, NsLocker& locks, SelectFunctionsHolder& func, std::vector& queryResultsContexts, const RdxContext& rdxCtx) { JoinedSelectors joinedSelectors; - if (q.GetJoinQueries().empty()) return joinedSelectors; + if (q.GetJoinQueries().empty()) { + return joinedSelectors; + } auto ns = locks.Get(q.NsName()); assertrx_throw(ns); diff --git a/cpp_src/core/reindexer_impl/rx_selector.h b/cpp_src/core/reindexer_impl/rx_selector.h index a96209985..a0f4ccefc 100644 --- a/cpp_src/core/reindexer_impl/rx_selector.h +++ b/cpp_src/core/reindexer_impl/rx_selector.h @@ -17,7 +17,7 @@ class RxSelector { template class NsLocker : private h_vector { public: - explicit NsLocker(const Context &context) noexcept : context_(context) {} + explicit NsLocker(const Context& context) noexcept : context_(context) {} ~NsLocker() { // Unlock first for (auto it = rbegin(), re = rend(); it != re; ++it) { @@ -31,7 +31,7 @@ class RxSelector { // Clean (ns may will release, if locker holds last ref) } - void Add(NamespaceImpl::Ptr &&ns) { + void Add(NamespaceImpl::Ptr&& ns) { assertrx(!locked_); for (auto it = begin(), e = end(); it != e; ++it) { if (it->ns.get() == ns.get()) { @@ -42,10 +42,12 @@ class RxSelector { emplace_back(std::move(ns)); } - void Delete(const NamespaceImpl::Ptr &ns) noexcept { + void Delete(const NamespaceImpl::Ptr& ns) noexcept { for (auto it = begin(), e = end(); it != e; ++it) { if (it->ns.get() == ns.get()) { - if (!--(it->count)) erase(it); + if (!--(it->count)) { + erase(it); + } return; } } @@ -53,46 +55,48 @@ class RxSelector { } void Lock() { boost::sort::pdqsort_branchless( - begin(), end(), [](const NsLockerItem &lhs, const NsLockerItem &rhs) noexcept { return lhs.ns.get() < rhs.ns.get(); }); + begin(), end(), [](const NsLockerItem& lhs, const NsLockerItem& rhs) noexcept { return lhs.ns.get() < rhs.ns.get(); }); for (auto it = begin(), e = end(); it != e; ++it) { it->nsLck = it->ns->rLock(context_); } locked_ = true; } - NamespaceImpl::Ptr Get(const std::string &name) noexcept { + NamespaceImpl::Ptr Get(const std::string& name) noexcept { for (auto it = begin(), e = end(); it != e; ++it) { - if (iequals(it->ns->name_, name)) return it->ns; + if (iequals(it->ns->name_, name)) { + return it->ns; + } } return NamespaceImpl::Ptr(); } protected: bool locked_ = false; - const Context &context_; + const Context& context_; }; template - static void DoSelect(const Query &q, QueryResults &result, NsLocker &locks, SelectFunctionsHolder &func, const RdxContext &ctx, - QueryStatCalculator &queryStatCalculator); + static void DoSelect(const Query& q, QueryResults& result, NsLocker& locks, SelectFunctionsHolder& func, const RdxContext& ctx, + QueryStatCalculator& queryStatCalculator); private: struct QueryResultsContext; template - static JoinedSelectors prepareJoinedSelectors(const Query &q, QueryResults &result, NsLocker &locks, SelectFunctionsHolder &func, - std::vector &, const RdxContext &ctx); + static JoinedSelectors prepareJoinedSelectors(const Query& q, QueryResults& result, NsLocker& locks, SelectFunctionsHolder& func, + std::vector&, const RdxContext& ctx); template - [[nodiscard]] static std::vector preselectSubQueries(Query &mainQuery, std::vector &queryResultsHolder, - NsLocker &, SelectFunctionsHolder &, const RdxContext &); + [[nodiscard]] static std::vector preselectSubQueries(Query& mainQuery, std::vector& queryResultsHolder, + NsLocker&, SelectFunctionsHolder&, const RdxContext&); template - [[nodiscard]] static bool selectSubQuery(const Query &subQuery, const Query &mainQuery, NsLocker &, SelectFunctionsHolder &, - std::vector &, const RdxContext &); + [[nodiscard]] static bool selectSubQuery(const Query& subQuery, const Query& mainQuery, NsLocker&, SelectFunctionsHolder&, + std::vector&, const RdxContext&); template - [[nodiscard]] static VariantArray selectSubQuery(const Query &subQuery, const Query &mainQuery, NsLocker &, QueryResults &, - SelectFunctionsHolder &, std::variant fieldOrKeys, - std::vector &, const RdxContext &); - static StoredValuesOptimizationStatus isPreResultValuesModeOptimizationAvailable(const Query &jItemQ, const NamespaceImpl::Ptr &jns, - const Query &mainQ); + [[nodiscard]] static VariantArray selectSubQuery(const Query& subQuery, const Query& mainQuery, NsLocker&, QueryResults&, + SelectFunctionsHolder&, std::variant fieldOrKeys, + std::vector&, const RdxContext&); + static StoredValuesOptimizationStatus isPreResultValuesModeOptimizationAvailable(const Query& jItemQ, const NamespaceImpl::Ptr& jns, + const Query& mainQ); }; } // namespace reindexer diff --git a/cpp_src/core/rollback.h b/cpp_src/core/rollback.h index aa6d867df..2eb7eac93 100644 --- a/cpp_src/core/rollback.h +++ b/cpp_src/core/rollback.h @@ -8,10 +8,10 @@ class RollBackBase { protected: RollBackBase() noexcept = default; virtual ~RollBackBase() = default; - RollBackBase(RollBackBase &&other) noexcept : disabled_{other.disabled_} { other.Disable(); } - RollBackBase(const RollBackBase &) = delete; - RollBackBase &operator=(const RollBackBase &) = delete; - RollBackBase &operator=(RollBackBase &&) = delete; + RollBackBase(RollBackBase&& other) noexcept : disabled_{other.disabled_} { other.Disable(); } + RollBackBase(const RollBackBase&) = delete; + RollBackBase& operator=(const RollBackBase&) = delete; + RollBackBase& operator=(RollBackBase&&) = delete; virtual void Disable() noexcept { disabled_ = true; } [[nodiscard]] bool IsDisabled() const noexcept { return disabled_; } diff --git a/cpp_src/core/schema.cc b/cpp_src/core/schema.cc index 1ae0e2237..217c83d67 100644 --- a/cpp_src/core/schema.cc +++ b/cpp_src/core/schema.cc @@ -38,13 +38,17 @@ void SchemaFieldsTypes::AddField(KeyValueType type, bool isArray) { types_[tagsP bool SchemaFieldsTypes::NeedToEmbedType(const std::string& objectType) const noexcept { auto it = objectTypes_.find(objectType); - if (it == objectTypes_.end()) return false; + if (it == objectTypes_.end()) { + return false; + } return it->second < int(tagsPath_.size()); } KeyValueType SchemaFieldsTypes::GetField(const TagsPath& fieldPath, bool& isArray) const { auto it = types_.find(fieldPath); - if (it == types_.end()) return KeyValueType::Undefined{}; + if (it == types_.end()) { + return KeyValueType::Undefined{}; + } isArray = it->second.isArray_; return it->second.type_; } @@ -222,7 +226,9 @@ Error PrefixTree::buildProtobufSchema(ProtobufSchemaBuilder& builder, const Pref const std::unique_ptr& node = child.second; std::string path = basePath; - if (path.size() > 0) path += "."; + if (path.size() > 0) { + path += "."; + } path += name; int fieldNumber = tm.name2tag(name, true); diff --git a/cpp_src/core/selectfunc/ctx/ftctx.cc b/cpp_src/core/selectfunc/ctx/ftctx.cc index c185dc124..5964c81a0 100644 --- a/cpp_src/core/selectfunc/ctx/ftctx.cc +++ b/cpp_src/core/selectfunc/ctx/ftctx.cc @@ -2,16 +2,16 @@ namespace reindexer { -bool FtCtx::PrepareAreas(const RHashMap &fields, const std::string &name) { +bool FtCtx::PrepareAreas(const RHashMap& fields, const std::string& name) { assertrx_dbg(!NeedArea()); - auto &data = *data_; + auto& data = *data_; if (!fields.empty()) { data.isComposite_ = true; } bool needArea = false; if (data.isComposite_) { - for (auto &field : fields) { + for (auto& field : fields) { needArea = CheckFunction(field.first, {SelectFuncType::Snippet, SelectFuncType::SnippetN, SelectFuncType::Highlight}); if (needArea) { break; @@ -26,8 +26,8 @@ bool FtCtx::PrepareAreas(const RHashMap &fields, const std::st } template -void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, AreaHolder &&holder) { - auto &data = *data_; +void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, AreaHolder&& holder) { + auto& data = *data_; data.area_.emplace_back(std::move(holder)); for (; begin != end; ++begin) { data.proc_.emplace_back(proc); @@ -39,19 +39,21 @@ void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, AreaHolder template void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc) { - auto &data = *data_; + auto& data = *data_; for (; begin != end; ++begin) { data.proc_.emplace_back(proc); } } template -void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector &mask, AreaHolder &&holder) { - auto &data = *data_; +void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector& mask, AreaHolder&& holder) { + auto& data = *data_; data.area_.emplace_back(std::move(holder)); for (; begin != end; ++begin) { assertrx(static_cast(*begin) < mask.size()); - if (!mask[*begin]) continue; + if (!mask[*begin]) { + continue; + } data.proc_.emplace_back(proc); if (data.holders_.has_value()) { data.holders_->emplace(*begin, data.area_.size() - 1); @@ -60,21 +62,23 @@ void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, const std: } template -void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector &mask) { - auto &data = *data_; +void FtCtx::Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector& mask) { + auto& data = *data_; for (; begin != end; ++begin) { assertrx(static_cast(*begin) < mask.size()); - if (!mask[*begin]) continue; + if (!mask[*begin]) { + continue; + } data.proc_.emplace_back(proc); } } template void FtCtx::Add::iterator>(span::iterator begin, span::iterator end, int16_t proc, - AreaHolder &&holder); + AreaHolder&& holder); template void FtCtx::Add::iterator>(span::iterator begin, span::iterator end, int16_t proc, - const std::vector &, AreaHolder &&holder); + const std::vector&, AreaHolder&& holder); template void FtCtx::Add::iterator>(span::iterator begin, span::iterator end, int16_t proc); template void FtCtx::Add::iterator>(span::iterator begin, span::iterator end, int16_t proc, - const std::vector &); + const std::vector&); } // namespace reindexer diff --git a/cpp_src/core/selectfunc/ctx/ftctx.h b/cpp_src/core/selectfunc/ctx/ftctx.h index bc85c3218..2031cb8d5 100644 --- a/cpp_src/core/selectfunc/ctx/ftctx.h +++ b/cpp_src/core/selectfunc/ctx/ftctx.h @@ -31,22 +31,22 @@ class FtCtx : public BaseFunctionCtx { int16_t Proc(size_t pos) const noexcept { return (pos < data_->proc_.size()) ? data_->proc_[pos] : 0; } template - void Add(InputIterator begin, InputIterator end, int16_t proc, AreaHolder &&holder); + void Add(InputIterator begin, InputIterator end, int16_t proc, AreaHolder&& holder); template void Add(InputIterator begin, InputIterator end, int16_t proc); template - void Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector &mask, AreaHolder &&holder); + void Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector& mask, AreaHolder&& holder); template - void Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector &mask); + void Add(InputIterator begin, InputIterator end, int16_t proc, const std::vector& mask); void Reserve(size_t size) { data_->proc_.reserve(size); } size_t Size() const noexcept { return data_->proc_.size(); } bool NeedArea() const noexcept { return data_->NeedArea(); } - bool PrepareAreas(const RHashMap &fields, const std::string &name); + bool PrepareAreas(const RHashMap& fields, const std::string& name); void SetData(Data::Ptr data) noexcept { data_ = std::move(data); } - const Data::Ptr &GetData() const noexcept { return data_; } + const Data::Ptr& GetData() const noexcept { return data_; } private: Data::Ptr data_; diff --git a/cpp_src/core/selectfunc/functions/highlight.cc b/cpp_src/core/selectfunc/functions/highlight.cc index 508b51532..ecbad1e7d 100644 --- a/cpp_src/core/selectfunc/functions/highlight.cc +++ b/cpp_src/core/selectfunc/functions/highlight.cc @@ -7,13 +7,17 @@ namespace reindexer { -bool Highlight::Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStruct &func, std::vector &stringsHolder) { - if (func.funcArgs.size() < 2) throw Error(errParams, "Invalid highlight params need minimum 2 - have %d", func.funcArgs.size()); +bool Highlight::Process(ItemRef& res, PayloadType& pl_type, const SelectFuncStruct& func, std::vector& stringsHolder) { + if (func.funcArgs.size() < 2) { + throw Error(errParams, "Invalid highlight params need minimum 2 - have %d", func.funcArgs.size()); + } - if (!func.ctx || func.ctx->type != BaseFunctionCtx::kFtCtx) return false; + if (!func.ctx || func.ctx->type != BaseFunctionCtx::kFtCtx) { + return false; + } FtCtx::Ptr ftctx = reindexer::static_ctx_pointer_cast(func.ctx); - auto &dataFtCtx = *ftctx->GetData(); + auto& dataFtCtx = *ftctx->GetData(); if (!dataFtCtx.holders_.has_value()) { return false; } @@ -35,10 +39,12 @@ bool Highlight::Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStru throw Error(errLogic, "Unable to apply highlight function to the non-string field '%s'", func.field); } - const std::string *data = p_string(kr[0]).getCxxstr(); + const std::string* data = p_string(kr[0]).getCxxstr(); auto pva = dataFtCtx.area_[it->second].GetAreas(func.fieldNo); - if (!pva || pva->Empty()) return false; - auto &va = *pva; + if (!pva || pva->Empty()) { + return false; + } + auto& va = *pva; std::string result_string; result_string.reserve(data->size() + va.Size() * (func.funcArgs[0].size() + func.funcArgs[1].size())); diff --git a/cpp_src/core/selectfunc/functions/highlight.h b/cpp_src/core/selectfunc/functions/highlight.h index d82fc7ffe..32dc62137 100644 --- a/cpp_src/core/selectfunc/functions/highlight.h +++ b/cpp_src/core/selectfunc/functions/highlight.h @@ -8,7 +8,7 @@ struct SelectFuncStruct; class Highlight { public: - bool Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStruct &func, std::vector &stringsHolder); + bool Process(ItemRef& res, PayloadType& pl_type, const SelectFuncStruct& func, std::vector& stringsHolder); }; } // namespace reindexer diff --git a/cpp_src/core/selectfunc/functions/snippet.cc b/cpp_src/core/selectfunc/functions/snippet.cc index 0f3bc28db..a6affd5fc 100644 --- a/cpp_src/core/selectfunc/functions/snippet.cc +++ b/cpp_src/core/selectfunc/functions/snippet.cc @@ -36,16 +36,20 @@ class Utf8CharCalculator { unsigned long charCounter_ = 0; }; -void Snippet::init(const SelectFuncStruct &func) { - if (isInit_) return; - if (func.funcArgs.size() < 4) throw Error(errParams, "Invalid snippet params need minimum 4 - have %d", func.funcArgs.size()); +void Snippet::init(const SelectFuncStruct& func) { + if (isInit_) { + return; + } + if (func.funcArgs.size() < 4) { + throw Error(errParams, "Invalid snippet params need minimum 4 - have %d", func.funcArgs.size()); + } try { std::size_t pos; before_ = stoul(func.funcArgs[2], &pos); if (pos != func.funcArgs[2].size()) { throw Error(errParams, "Invalid snippet param before - %s is not a number", func.funcArgs[2]); } - } catch (std::exception &) { + } catch (std::exception&) { throw Error(errParams, "Invalid snippet param before - %s is not a number", func.funcArgs[2]); } @@ -55,7 +59,7 @@ void Snippet::init(const SelectFuncStruct &func) { if (pos != func.funcArgs[3].size()) { throw Error(errParams, "Invalid snippet param after - %s is not a number", func.funcArgs[3]); } - } catch (std::exception &) { + } catch (std::exception&) { throw Error(errParams, "Invalid snippet param after - %s is not a number", func.funcArgs[3]); } if (std::holds_alternative(func.func)) { @@ -95,8 +99,8 @@ void Snippet::init(const SelectFuncStruct &func) { isInit_ = true; } -void Snippet::addSnippet(std::string &resultString, const std::string &data, const Area &snippetAreaPrev, - const Area &snippetAreaPrevChar) const { +void Snippet::addSnippet(std::string& resultString, const std::string& data, const Area& snippetAreaPrev, + const Area& snippetAreaPrevChar) const { resultString.append(preDelim_); resultString += '['; @@ -119,7 +123,7 @@ void Snippet::addSnippet(std::string &resultString, const std::string &data, con } resultString.append(data.begin() + zonesList_[z - 1].end, data.begin() + snippetAreaPrev.end); resultString.append(postDelim_); -}; +} struct Areas { Area zoneArea; @@ -131,7 +135,7 @@ struct AreasEx : public Areas { }; template -A Snippet::RecalcZoneHelper::RecalcZoneToOffset(const Area &area) { +A Snippet::RecalcZoneHelper::RecalcZoneToOffset(const Area& area) { using PointType = std::conditional_t, WordPosition, WordPositionEx>; constexpr bool needChar = std::is_same_v; A outAreas; @@ -181,13 +185,13 @@ A Snippet::RecalcZoneHelper::RecalcZoneToOffset(const Area &area) { return outAreas; } -void Snippet::buildResult(RecalcZoneHelper &recalcZoneHelper, const AreaBuffer &pva, const std::string &data, std::string &resultString) { +void Snippet::buildResult(RecalcZoneHelper& recalcZoneHelper, const AreaBuffer& pva, const std::string& data, std::string& resultString) { // resultString =preDelim_+with_area_str+data_str_before+marker_before+zone_str+marker_after+data_strAfter+postDelim_ Area snippetAreaPrev; Area snippetAreaPrevChar; zonesList_.clear(); - for (const auto &area : pva.GetData()) { + for (const auto& area : pva.GetData()) { Areas a = recalcZoneHelper.RecalcZoneToOffset(area); if (snippetAreaPrev.start == 0 && snippetAreaPrev.end == 0) { @@ -224,14 +228,14 @@ void Snippet::buildResult(RecalcZoneHelper &recalcZoneHelper, const AreaBuffer & resultString.append(postDelim_); } -void Snippet::buildResultWithPrefix(RecalcZoneHelper &recalcZoneHelper, const AreaBuffer &pva, const std::string &data, - std::string &resultString) { +void Snippet::buildResultWithPrefix(RecalcZoneHelper& recalcZoneHelper, const AreaBuffer& pva, const std::string& data, + std::string& resultString) { // resultString =preDelim_+with_area_str+data_str_before+marker_before+zone_str+marker_after+data_strAfter+postDelim_ Area snippetAreaPrev; Area snippetAreaPrevChar; zonesList_.clear(); - for (const auto &area : pva.GetData()) { + for (const auto& area : pva.GetData()) { AreasEx a = recalcZoneHelper.RecalcZoneToOffset(area); if (snippetAreaPrev.start == 0 && snippetAreaPrev.end == 0) { snippetAreaPrev = a.snippetArea; @@ -253,12 +257,14 @@ void Snippet::buildResultWithPrefix(RecalcZoneHelper &recalcZoneHelper, const Ar addSnippet(resultString, data, snippetAreaPrev, snippetAreaPrevChar); } -bool Snippet::Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStruct &func, std::vector &stringsHolder) { - if (!func.ctx) return false; +bool Snippet::Process(ItemRef& res, PayloadType& pl_type, const SelectFuncStruct& func, std::vector& stringsHolder) { + if (!func.ctx) { + return false; + } init(func); FtCtx::Ptr ftctx = reindexer::static_ctx_pointer_cast(func.ctx); - auto &dataFtCtx = *ftctx->GetData(); + auto& dataFtCtx = *ftctx->GetData(); if (!dataFtCtx.isWordPositions_) { throw Error(errParams, "Snippet function does not work with ft_fuzzy index."); } @@ -280,9 +286,11 @@ bool Snippet::Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStruct throw Error(errLogic, "Unable to apply snippet function to the non-string field '%s'", func.field); } - const std::string *data = p_string(kr[0]).getCxxstr(); + const std::string* data = p_string(kr[0]).getCxxstr(); auto pva = dataFtCtx.area_[it->second].GetAreas(func.fieldNo); - if (!pva || pva->Empty()) return false; + if (!pva || pva->Empty()) { + return false; + } std::string resultString; resultString.reserve(data->size()); diff --git a/cpp_src/core/selectfunc/functions/snippet.h b/cpp_src/core/selectfunc/functions/snippet.h index 25c371b93..d1240c8a5 100644 --- a/cpp_src/core/selectfunc/functions/snippet.h +++ b/cpp_src/core/selectfunc/functions/snippet.h @@ -9,15 +9,15 @@ struct SelectFuncStruct; class Snippet { public: - bool Process(ItemRef &res, PayloadType &pl_type, const SelectFuncStruct &func, std::vector &stringsHolder); + bool Process(ItemRef& res, PayloadType& pl_type, const SelectFuncStruct& func, std::vector& stringsHolder); private: - void init(const SelectFuncStruct &func); - void addSnippet(std::string &resultString, const std::string &data, const Area &snippetAreaPrev, const Area &snippetAreaPrevChar) const; + void init(const SelectFuncStruct& func); + void addSnippet(std::string& resultString, const std::string& data, const Area& snippetAreaPrev, const Area& snippetAreaPrevChar) const; class RecalcZoneHelper { public: - RecalcZoneHelper(std::string_view data, const std::string &extra, unsigned int after, unsigned int before, + RecalcZoneHelper(std::string_view data, const std::string& extra, unsigned int after, unsigned int before, std::string_view leftBound, std::string_view rightBound) noexcept : str_(data), data_(data), @@ -27,7 +27,7 @@ class Snippet { leftBound_(leftBound), rightBound_(rightBound) {} template - A RecalcZoneToOffset(const Area &area); + A RecalcZoneToOffset(const Area& area); private: std::string_view str_; @@ -35,14 +35,14 @@ class Snippet { size_t wordCount_ = 0; int stringBeginOffsetByte_ = 0; int stringBeginOffsetChar_ = 0; - const std::string &extraWordSymbols_; + const std::string& extraWordSymbols_; unsigned int after_, before_; std::string_view leftBound_, rightBound_; }; - void buildResult(RecalcZoneHelper &recalcZoneHelper, const AreaBuffer &pva, const std::string &data, std::string &resultString); - void buildResultWithPrefix(RecalcZoneHelper &recalcZoneHelper, const AreaBuffer &pva, const std::string &data, - std::string &resultString); + void buildResult(RecalcZoneHelper& recalcZoneHelper, const AreaBuffer& pva, const std::string& data, std::string& resultString); + void buildResultWithPrefix(RecalcZoneHelper& recalcZoneHelper, const AreaBuffer& pva, const std::string& data, + std::string& resultString); bool isInit_ = false; bool needAreaStr_ = false; diff --git a/cpp_src/core/selectfunc/nsselectfuncinterface.cc b/cpp_src/core/selectfunc/nsselectfuncinterface.cc index e5e470865..d2ec3c81a 100644 --- a/cpp_src/core/selectfunc/nsselectfuncinterface.cc +++ b/cpp_src/core/selectfunc/nsselectfuncinterface.cc @@ -3,7 +3,7 @@ #include "core/namespace/namespaceimpl.h" namespace reindexer { -const std::string& NsSelectFuncInterface::GetName() const noexcept { return nm_.name_; }; +const std::string& NsSelectFuncInterface::GetName() const noexcept { return nm_.name_; } int NsSelectFuncInterface::getIndexByName(std::string_view index) const noexcept { return nm_.getIndexByName(index); } bool NsSelectFuncInterface::getIndexByName(std::string_view name, int& index) const noexcept { return nm_.tryGetIndexByName(name, index); } int NsSelectFuncInterface::getIndexesCount() const noexcept { return nm_.indexes_.size(); } diff --git a/cpp_src/core/selectfunc/selectfunc.cc b/cpp_src/core/selectfunc/selectfunc.cc index 2c4bc50f2..734936b24 100644 --- a/cpp_src/core/selectfunc/selectfunc.cc +++ b/cpp_src/core/selectfunc/selectfunc.cc @@ -8,22 +8,22 @@ namespace reindexer { -inline void ltrim(std::string &s) { +inline void ltrim(std::string& s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } // trim from end (in place) -inline void rtrim(std::string &s) { +inline void rtrim(std::string& s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } // trim from both ends (in place) -inline void trim(std::string &s) { +inline void trim(std::string& s) { ltrim(s); rtrim(s); } -SelectFunction::Ptr SelectFunctionsHolder::AddNamespace(const Query &q, const NamespaceImpl &nm, uint32_t nsid, bool force) { +SelectFunction::Ptr SelectFunctionsHolder::AddNamespace(const Query& q, const NamespaceImpl& nm, uint32_t nsid, bool force) { if (q.selectFunctions_.empty() && !force) { return nullptr; } else if (!q.selectFunctions_.empty()) { @@ -37,21 +37,25 @@ SelectFunction::Ptr SelectFunctionsHolder::AddNamespace(const Query &q, const Na return queries_[nsid]; } -SelectFunction::SelectFunction(const Query &q, NsSelectFuncInterface &&nm) : nm_(std::move(nm)), currCjsonFieldIdx_(nm_.getIndexesCount()) { - for (auto &func : q.selectFunctions_) { +SelectFunction::SelectFunction(const Query& q, NsSelectFuncInterface&& nm) : nm_(std::move(nm)), currCjsonFieldIdx_(nm_.getIndexesCount()) { + for (auto& func : q.selectFunctions_) { SelectFuncParser parser; - SelectFuncStruct &result = parser.Parse(func); - if (!result.isFunction) continue; + SelectFuncStruct& result = parser.Parse(func); + if (!result.isFunction) { + continue; + } createFunc(result); } } -void SelectFunction::createFunc(SelectFuncStruct &data) { +void SelectFunction::createFunc(SelectFuncStruct& data) { int indexNo = IndexValueType::NotSet; if (data.indexNo == IndexValueType::NotSet) { if (!nm_.getIndexByName(data.field, indexNo)) { trim(data.field); - if (!nm_.getIndexByName(data.field, indexNo)) return; + if (!nm_.getIndexByName(data.field, indexNo)) { + return; + } } } else { indexNo = data.indexNo; @@ -60,7 +64,7 @@ void SelectFunction::createFunc(SelectFuncStruct &data) { // if index is composite then create function for inner use only if (IsComposite(nm_.getIndexType(indexNo))) { int fieldNo = 0; - const FieldsSet &fields = nm_.getIndexFields(indexNo); + const FieldsSet& fields = nm_.getIndexFields(indexNo); int jsPathIdx = 0; for (auto field : fields) { @@ -92,7 +96,9 @@ BaseFunctionCtx::Ptr SelectFunction::createFuncForProc(int indexNo) { createFunc(data); if (IsComposite(nm_.getIndexType(indexNo))) { auto field = nm_.getIndexFields(indexNo)[0]; - if (field == IndexValueType::SetByJsonPath) field = lastCjsonIdx; + if (field == IndexValueType::SetByJsonPath) { + field = lastCjsonIdx; + } auto it = functions_.find(field); assertrx(it != functions_.end()); return createCtx(it->second, nullptr, nm_.getIndexType(indexNo)); @@ -104,7 +110,9 @@ BaseFunctionCtx::Ptr SelectFunction::createFuncForProc(int indexNo) { } bool SelectFunction::NeedArea(int indexNo) const { - if (functions_.empty()) return false; + if (functions_.empty()) { + return false; + } IndexType indexType = nm_.getIndexType(indexNo); auto checkField = [&](int field) -> bool { @@ -121,8 +129,12 @@ bool SelectFunction::NeedArea(int indexNo) const { if (IsComposite(indexType)) { int cjsonFieldIdx = nm_.getIndexesCount(); for (auto field : nm_.getIndexFields(indexNo)) { - if (field == IndexValueType::SetByJsonPath) field = cjsonFieldIdx++; - if (checkField(field)) return true; + if (field == IndexValueType::SetByJsonPath) { + field = cjsonFieldIdx++; + } + if (checkField(field)) { + return true; + } } } else { return checkField(indexNo); @@ -145,7 +157,9 @@ BaseFunctionCtx::Ptr SelectFunction::CreateCtx(int indexNo) { int fieldNo = 0; int cjsonFieldIdx = nm_.getIndexesCount(); for (auto field : nm_.getIndexFields(indexNo)) { - if (field == IndexValueType::SetByJsonPath) field = cjsonFieldIdx++; + if (field == IndexValueType::SetByJsonPath) { + field = cjsonFieldIdx++; + } auto it = functions_.find(field); if (it != functions_.end()) { it->second.fieldNo = fieldNo; @@ -165,48 +179,52 @@ BaseFunctionCtx::Ptr SelectFunction::CreateCtx(int indexNo) { } return ctx; } -void SelectFunctionsHolder::Process(QueryResults &res) { - if (queries_.empty() || force_only_) return; +void SelectFunctionsHolder::Process(QueryResults& res) { + if (queries_.empty() || force_only_) { + return; + } bool hasFuncs = false; - for (auto &q : queries_) { + for (auto& q : queries_) { if (q) { hasFuncs = true; break; } } - if (!hasFuncs) return; + if (!hasFuncs) { + return; + } bool changed = false; - for (auto &item : res.Items()) { + for (auto& item : res.Items()) { const auto nsid = item.Nsid(); if (queries_.size() <= nsid) { continue; } - if (auto &funcPtr = queries_[nsid]; funcPtr && funcPtr->ProcessItem(item, res.getPayloadType(nsid), res.stringsHolder_)) { + if (auto& funcPtr = queries_[nsid]; funcPtr && funcPtr->ProcessItem(item, res.getPayloadType(nsid), res.stringsHolder_)) { changed = true; } } res.nonCacheableData = changed; } -bool SelectFunction::ProcessItem(ItemRef &res, PayloadType &pl_type, std::vector &stringsHolder) { +bool SelectFunction::ProcessItem(ItemRef& res, PayloadType& pl_type, std::vector& stringsHolder) { bool changed = false; - for (auto &func : functions_) { + for (auto& func : functions_) { if (func.second.ctx && - std::visit([&](auto &f) -> bool { return f.Process(res, pl_type, func.second, stringsHolder); }, func.second.func)) { + std::visit([&](auto& f) -> bool { return f.Process(res, pl_type, func.second, stringsHolder); }, func.second.func)) { changed = true; } } return changed; } -BaseFunctionCtx::Ptr SelectFunction::createCtx(SelectFuncStruct &data, BaseFunctionCtx::Ptr ctx, IndexType index_type) { +BaseFunctionCtx::Ptr SelectFunction::createCtx(SelectFuncStruct& data, BaseFunctionCtx::Ptr ctx, IndexType index_type) { if (IsFullText(index_type)) { if (!ctx) { data.ctx = make_intrusive(); } else { data.ctx = std::move(ctx); } - const std::string &indexName = (data.indexNo >= nm_.getIndexesCount()) ? data.field : nm_.getIndexName(data.indexNo); + const std::string& indexName = (data.indexNo >= nm_.getIndexesCount()) ? data.field : nm_.getIndexName(data.indexNo); data.ctx->AddFunction(indexName, SelectFuncType(data.func.index())); } return data.ctx; diff --git a/cpp_src/core/selectfunc/selectfuncparser.cc b/cpp_src/core/selectfunc/selectfuncparser.cc index 265121e59..797d7e295 100644 --- a/cpp_src/core/selectfunc/selectfuncparser.cc +++ b/cpp_src/core/selectfunc/selectfuncparser.cc @@ -6,7 +6,7 @@ namespace reindexer { -SelectFuncStruct &SelectFuncParser::Parse(const std::string &query) { +SelectFuncStruct& SelectFuncParser::Parse(const std::string& query) { tokenizer parser(query); token tok = parser.next_token(tokenizer::flags::no_flags); @@ -41,7 +41,7 @@ SelectFuncStruct &SelectFuncParser::Parse(const std::string &query) { return selectFuncStruct_; } -void SelectFuncParser::parsePositionalAndNamedArgs(tokenizer &parser, const Args &args) { +void SelectFuncParser::parsePositionalAndNamedArgs(tokenizer& parser, const Args& args) { using namespace std::string_view_literals; token tok; tok = parser.next_token(tokenizer::flags::no_flags); @@ -176,7 +176,7 @@ void SelectFuncParser::parsePositionalAndNamedArgs(tokenizer &parser, const Args } } -SelectFuncStruct &SelectFuncParser::ParseFunction(tokenizer &parser, bool partOfExpression, token &tok) { +SelectFuncStruct& SelectFuncParser::ParseFunction(tokenizer& parser, bool partOfExpression, token& tok) { using namespace std::string_view_literals; if (tok.text().empty()) { tok = parser.next_token(); @@ -232,32 +232,56 @@ SelectFuncStruct &SelectFuncParser::ParseFunction(tokenizer &parser, bool partOf } bool SelectFuncParser::IsFunction(std::string_view val) noexcept { - if (val.length() < 3) return false; + if (val.length() < 3) { + return false; + } size_t i = 0; - if (!isalpha(val[i++])) return false; + if (!isalpha(val[i++])) { + return false; + } int openParenthesis = 0, closeParenthesis = 0; for (; i < val.length(); ++i) { char ch = val[i]; switch (ch) { case '(': - if (openParenthesis++ > 0) return false; - if (closeParenthesis > 0) return false; + if (openParenthesis++ > 0) { + return false; + } + if (closeParenthesis > 0) { + return false; + } break; case ')': - if (openParenthesis != 1) return false; - if (closeParenthesis++ > 0) return false; - if (i == val.length() - 1) return true; + if (openParenthesis != 1) { + return false; + } + if (closeParenthesis++ > 0) { + return false; + } + if (i == val.length() - 1) { + return true; + } break; case ',': - if (openParenthesis != 1) return false; - if (closeParenthesis != 0) return false; - if (i == val.length() - 1) return false; + if (openParenthesis != 1) { + return false; + } + if (closeParenthesis != 0) { + return false; + } + if (i == val.length() - 1) { + return false; + } break; default: - if (openParenthesis > 1) return false; - if (closeParenthesis > 0) return false; + if (openParenthesis > 1) { + return false; + } + if (closeParenthesis > 0) { + return false; + } break; } } @@ -265,9 +289,13 @@ bool SelectFuncParser::IsFunction(std::string_view val) noexcept { return false; } -bool SelectFuncParser::IsFunction(const VariantArray &val) noexcept { - if (val.size() != 1) return false; - if (!val.front().Type().Is()) return false; +bool SelectFuncParser::IsFunction(const VariantArray& val) noexcept { + if (val.size() != 1) { + return false; + } + if (!val.front().Type().Is()) { + return false; + } return IsFunction(static_cast(val.front())); } diff --git a/cpp_src/core/selectfunc/selectfuncparser.h b/cpp_src/core/selectfunc/selectfuncparser.h index 6e2427239..0d7894f9e 100644 --- a/cpp_src/core/selectfunc/selectfuncparser.h +++ b/cpp_src/core/selectfunc/selectfuncparser.h @@ -28,19 +28,19 @@ struct SelectFuncStruct { class SelectFuncParser { public: - SelectFuncStruct &Parse(const std::string &query); - SelectFuncStruct &ParseFunction(tokenizer &parser, bool partOfExpression, token &tok); + SelectFuncStruct& Parse(const std::string& query); + SelectFuncStruct& ParseFunction(tokenizer& parser, bool partOfExpression, token& tok); static bool IsFunction(std::string_view val) noexcept; - static bool IsFunction(const VariantArray &val) noexcept; + static bool IsFunction(const VariantArray& val) noexcept; protected: struct Args { - explicit Args(unsigned int p, std::unordered_set &&n) : posArgsCount(p), namedArgs(std::move(n)) {} + explicit Args(unsigned int p, std::unordered_set&& n) : posArgsCount(p), namedArgs(std::move(n)) {} unsigned int posArgsCount; std::unordered_set namedArgs; }; - void parsePositionalAndNamedArgs(tokenizer &parser, const Args &args); + void parsePositionalAndNamedArgs(tokenizer& parser, const Args& args); SelectFuncStruct selectFuncStruct_; }; diff --git a/cpp_src/core/selectkeyresult.h b/cpp_src/core/selectkeyresult.h index 665f1b8af..f45b67fc9 100644 --- a/cpp_src/core/selectkeyresult.h +++ b/cpp_src/core/selectkeyresult.h @@ -21,11 +21,11 @@ class SingleSelectKeyResult { public: SingleSelectKeyResult() noexcept {} - explicit SingleSelectKeyResult(IndexIterator::Ptr &&indexForwardIter) noexcept : indexForwardIter_(std::move(indexForwardIter)) { + explicit SingleSelectKeyResult(IndexIterator::Ptr&& indexForwardIter) noexcept : indexForwardIter_(std::move(indexForwardIter)) { assertrx(indexForwardIter_ != nullptr); } template - explicit SingleSelectKeyResult(const KeyEntryT &ids, SortType sortId) noexcept { + explicit SingleSelectKeyResult(const KeyEntryT& ids, SortType sortId) noexcept { if (ids.Unsorted().IsCommited()) { ids_ = ids.Sorted(sortId); } else { @@ -35,10 +35,10 @@ class SingleSelectKeyResult { useBtree_ = true; } } - explicit SingleSelectKeyResult(IdSet::Ptr &&ids) noexcept : tempIds_(std::move(ids)), ids_(*tempIds_) {} + explicit SingleSelectKeyResult(IdSet::Ptr&& ids) noexcept : tempIds_(std::move(ids)), ids_(*tempIds_) {} explicit SingleSelectKeyResult(IdSetCRef ids) noexcept : ids_(ids) {} explicit SingleSelectKeyResult(IdType rBegin, IdType rEnd) noexcept : rBegin_(rBegin), rEnd_(rEnd), isRange_(true) {} - SingleSelectKeyResult(const SingleSelectKeyResult &other) noexcept + SingleSelectKeyResult(const SingleSelectKeyResult& other) noexcept : tempIds_(other.tempIds_), ids_(other.ids_), set_(other.set_), @@ -65,7 +65,7 @@ class SingleSelectKeyResult { } } } - SingleSelectKeyResult &operator=(const SingleSelectKeyResult &other) noexcept { + SingleSelectKeyResult& operator=(const SingleSelectKeyResult& other) noexcept { if (&other != this) { tempIds_ = other.tempIds_; ids_ = other.ids_; @@ -100,7 +100,7 @@ class SingleSelectKeyResult { IdSetCRef ids_; protected: - const base_idsetset *set_ = nullptr; + const base_idsetset* set_ = nullptr; union { IdSetCRef::const_iterator begin_; @@ -175,7 +175,7 @@ class SelectKeyResult : public h_vector { /// @return amount of loops. size_t GetMaxIterations(size_t limitIters = std::numeric_limits::max()) const noexcept { size_t cnt = 0; - for (const SingleSelectKeyResult &r : *this) { + for (const SingleSelectKeyResult& r : *this) { if (r.indexForwardIter_) { cnt += r.indexForwardIter_->GetMaxIterations(limitIters); } else if (r.isRange_) { @@ -185,7 +185,9 @@ class SelectKeyResult : public h_vector { } else { cnt += r.ids_.size(); } - if (cnt > limitIters) break; + if (cnt > limitIters) { + break; + } } return cnt; } @@ -198,7 +200,7 @@ class SelectKeyResult : public h_vector { /// @param opts - merge customization options /// @return Pointer to a sorted IdSet object made /// from all the SingleSelectKeyResult inner objects. - IdSet::Ptr MergeIdsets(MergeOptions &&opts, size_t idsCount) { + IdSet::Ptr MergeIdsets(MergeOptions&& opts, size_t idsCount) { IdSet::Ptr mergedIds; if (opts.genericSort) { mergedIds = mergeGenericSort(idsCount); @@ -246,27 +248,27 @@ class SelectKeyResult : public h_vector { auto mergedIds = make_intrusive>(); mergedIds->reserve(idsCount); - auto firstSetIt = std::partition(begin(), end(), [](const SingleSelectKeyResult &v) noexcept { return !v.useBtree_; }); + auto firstSetIt = std::partition(begin(), end(), [](const SingleSelectKeyResult& v) noexcept { return !v.useBtree_; }); const auto vecsCnt = firstSetIt - begin(); - h_vector ptrsVec; + h_vector ptrsVec; ptrsVec.reserve(size()); - for (auto &v : *this) { + for (auto& v : *this) { if rx_unlikely (v.isRange_) { throw Error(errLogic, "Unable to merge 'range' idset ('merge sort mode')"); } ptrsVec.emplace_back(&v); } - span vecSpan(ptrsVec.data(), vecsCnt); - span setSpan(ptrsVec.data() + vecsCnt, size() - vecsCnt); + span vecSpan(ptrsVec.data(), vecsCnt); + span setSpan(ptrsVec.data() + vecsCnt, size() - vecsCnt); - for (auto &v : vecSpan) { + for (auto& v : vecSpan) { assertrx_dbg(!v->useBtree_); v->it_ = v->ids_.begin(); v->end_ = v->ids_.end(); } - for (auto &v : setSpan) { + for (auto& v : setSpan) { assertrx_dbg(v->useBtree_); v->itset_ = v->set_->begin(); v->setend_ = v->set_->end(); @@ -276,12 +278,12 @@ class SelectKeyResult : public h_vector { for (;;) { int curMin = INT_MAX; for (auto vsIt = vecSpan.begin(), vsItEnd = vecSpan.end(); vsIt != vsItEnd;) { - auto &itvec = (*vsIt)->it_; - auto &vecend = (*vsIt)->end_; + auto& itvec = (*vsIt)->it_; + auto& vecend = (*vsIt)->end_; for (;; ++itvec) { if (itvec == vecend) { std::swap(*vsIt, vecSpan.back()); - vecSpan = span(vecSpan.data(), vecSpan.size() - 1); + vecSpan = span(vecSpan.data(), vecSpan.size() - 1); --vsItEnd; break; } @@ -296,12 +298,12 @@ class SelectKeyResult : public h_vector { } } for (auto ssIt = setSpan.begin(), ssItEnd = setSpan.end(); ssIt != ssItEnd;) { - auto &itset = (*ssIt)->itset_; - auto &setend = (*ssIt)->setend_; + auto& itset = (*ssIt)->itset_; + auto& setend = (*ssIt)->setend_; for (;; ++itset) { if (itset == setend) { std::swap(*ssIt, setSpan.back()); - setSpan = span(setSpan.data(), setSpan.size() - 1); + setSpan = span(setSpan.data(), setSpan.size() - 1); --ssItEnd; break; } @@ -329,16 +331,16 @@ class SelectKeyResult : public h_vector { mergedIds->reserve(idsCount); struct IdSetGreater { - bool operator()(const value_type *l, const value_type *r) noexcept { + bool operator()(const value_type* l, const value_type* r) noexcept { const auto lval = l->useBtree_ ? *(l->itset_) : *(l->it_); const auto rval = r->useBtree_ ? *(r->itset_) : *(r->it_); return lval > rval; } }; - h_vector ptrsVec; + h_vector ptrsVec; ptrsVec.reserve(size()); - for (auto &v : *this) { + for (auto& v : *this) { if rx_unlikely (v.isRange_) { throw Error(errLogic, "Unable to merge 'range' idset ('merge sort mode')"); } @@ -357,10 +359,10 @@ class SelectKeyResult : public h_vector { } } } - span idsetsSpan(ptrsVec.data(), ptrsVec.size()); + span idsetsSpan(ptrsVec.data(), ptrsVec.size()); std::make_heap(idsetsSpan.begin(), idsetsSpan.end(), IdSetGreater{}); int min = INT_MIN; - auto handleMinValue = [&mergedIds, &idsetsSpan, &min](auto &it, auto end) noexcept { + auto handleMinValue = [&mergedIds, &idsetsSpan, &min](auto& it, auto end) noexcept { auto val = *it; if (val > min) { mergedIds->AddUnordered(val); @@ -369,20 +371,20 @@ class SelectKeyResult : public h_vector { do { if (++it == end) { std::swap(idsetsSpan.front(), idsetsSpan.back()); - idsetsSpan = span(idsetsSpan.begin(), idsetsSpan.size() - 1); + idsetsSpan = span(idsetsSpan.begin(), idsetsSpan.size() - 1); return; } } while (*it <= min); }; while (!idsetsSpan.empty()) { - auto &minV = *idsetsSpan.front(); + auto& minV = *idsetsSpan.front(); if (minV.useBtree_) { handleMinValue(minV.itset_, minV.setend_); } else { handleMinValue(minV.it_, minV.end_); } - heapifyRoot(idsetsSpan); + heapifyRoot(idsetsSpan); } return mergedIds; } @@ -390,14 +392,14 @@ class SelectKeyResult : public h_vector { template RX_ALWAYS_INLINE void heapifyRoot(span vec) noexcept { static_assert(std::is_pointer_v, "Expecting T being a pointer for the fast swaps"); - T *target = vec.begin(); - T *end = target + vec.size(); + T* target = vec.begin(); + T* end = target + vec.size(); CompareT c; for (size_t i = 0;;) { - T *cur = target; + T* cur = target; const auto lIdx = (i << 1) + 1; - T *left = vec.begin() + lIdx; - T *right = left + 1; + T* left = vec.begin() + lIdx; + T* right = left + 1; if (left < end && c(*target, *left)) { target = left; @@ -428,16 +430,16 @@ class SelectKeyResults : public std::variant - SelectKeyResults(ComparatorIndexed &&comp) noexcept : Base{std::move(comp)} {} - SelectKeyResults(ComparatorNotIndexed &&comp) noexcept : Base{std::move(comp)} {} + SelectKeyResults(ComparatorIndexed&& comp) noexcept : Base{std::move(comp)} {} + SelectKeyResults(ComparatorNotIndexed&& comp) noexcept : Base{std::move(comp)} {} void Clear() noexcept { std::get(*this).clear(); } - void EmplaceBack(SelectKeyResult &&sr) { std::get(*this).emplace_back(std::move(sr)); } - SelectKeyResult &&Front() && noexcept { return std::move(std::get(*this).front()); } - const Base &AsVariant() const & noexcept { return *this; } - Base &AsVariant() & noexcept { return *this; } - auto AsVariant() const && = delete; + void EmplaceBack(SelectKeyResult&& sr) { std::get(*this).emplace_back(std::move(sr)); } + SelectKeyResult&& Front() && noexcept { return std::move(std::get(*this).front()); } + const Base& AsVariant() const& noexcept { return *this; } + Base& AsVariant() & noexcept { return *this; } + auto AsVariant() const&& = delete; }; } // namespace reindexer diff --git a/cpp_src/core/sortingprioritiestable.cc b/cpp_src/core/sortingprioritiestable.cc index 8f86f59b1..c95a747a6 100644 --- a/cpp_src/core/sortingprioritiestable.cc +++ b/cpp_src/core/sortingprioritiestable.cc @@ -22,21 +22,26 @@ SortingPrioritiesTable::SortingPrioritiesTable(const std::string& sortOrderUTF8) for (int i = 0; i <= lastCharIdx; ++i) { auto ch(orderUtf16[i]); if (ch == '-') { - if ((i == 0) || (i == lastCharIdx)) + if ((i == 0) || (i == lastCharIdx)) { throw Error(errLogic, "Incorrect format of sort order string: '-' cannot be the first or the last character"); + } } else { if ((i != 0) && (orderUtf16[i - 1] == '-')) { - if (ch <= prevCh) throw Error(errLogic, "Incorrect format of sort order string: range should be ascending"); + if (ch <= prevCh) { + throw Error(errLogic, "Incorrect format of sort order string: range should be ascending"); + } for (auto it = prevCh; it <= ch; ++it) { - if (checkForRangeIntersection(ranges, it)) + if (checkForRangeIntersection(ranges, it)) { throw Error(errLogic, "There can't be 2 same formating characters in format string!"); + } sortOrder_->operator[](it) = priority++; } ranges.insert({prevCh, ch - prevCh + 1}); maxPriority = priority; } else if (((i + 1 <= lastCharIdx) && (orderUtf16[i + 1] != '-')) || (i == lastCharIdx)) { - if (checkForRangeIntersection(ranges, ch)) + if (checkForRangeIntersection(ranges, ch)) { throw Error(errLogic, "There can't be 2 same formating characters in format string!"); + } sortOrder_->operator[](ch) = priority++; ranges.insert({ch, 1}); maxPriority = priority; @@ -60,12 +65,18 @@ SortingPrioritiesTable::SortingPrioritiesTable(const std::string& sortOrderUTF8) } bool SortingPrioritiesTable::checkForRangeIntersection(std::map& ranges, wchar_t ch) { - if (ranges.empty()) return false; + if (ranges.empty()) { + return false; + } auto itLow = ranges.lower_bound(ch); - if (itLow == ranges.end()) itLow = ranges.begin(); + if (itLow == ranges.end()) { + itLow = ranges.begin(); + } auto itUp = ranges.upper_bound(ch); for (auto it = itLow; it != itUp; ++it) { - if ((ch >= it->first) && (ch < it->first + it->second)) return true; + if ((ch >= it->first) && (ch < it->first + it->second)) { + return true; + } } return false; } diff --git a/cpp_src/core/storage/leveldblogger.cc b/cpp_src/core/storage/leveldblogger.cc index eba6dc16c..8cc9b2bd0 100644 --- a/cpp_src/core/storage/leveldblogger.cc +++ b/cpp_src/core/storage/leveldblogger.cc @@ -11,7 +11,7 @@ namespace reindexer { namespace datastorage { class NoOpLogger : public leveldb::Logger { - void Logv(const char* /*format*/, va_list /*ap*/) override final {} + void Logv(const char* /*format*/, va_list /*ap*/) override final {} }; static NoOpLogger dummyLevelDBLogger; diff --git a/cpp_src/core/storage/leveldbstorage.cc b/cpp_src/core/storage/leveldbstorage.cc index 026a443d1..dae6241f4 100644 --- a/cpp_src/core/storage/leveldbstorage.cc +++ b/cpp_src/core/storage/leveldbstorage.cc @@ -26,63 +26,87 @@ static void toReadOptions(const StorageOpts& opts, leveldb::ReadOptions& ropts) LevelDbStorage::LevelDbStorage() = default; Error LevelDbStorage::Read(const StorageOpts& opts, std::string_view key, std::string& value) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } leveldb::ReadOptions options; toReadOptions(opts, options); leveldb::Status status = db_->Get(options, leveldb::Slice(key.data(), key.size()), &value); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error LevelDbStorage::Write(const StorageOpts& opts, std::string_view key, std::string_view value) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } leveldb::WriteOptions options; toWriteOptions(opts, options); leveldb::Status status = db_->Put(options, leveldb::Slice(key.data(), key.size()), leveldb::Slice(value.data(), value.size())); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error LevelDbStorage::Write(const StorageOpts& opts, UpdatesCollection& buffer) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } leveldb::WriteOptions options; toWriteOptions(opts, options); LevelDbBatchBuffer* batchBuffer = static_cast(&buffer); leveldb::Status status = db_->Write(options, &batchBuffer->batchWrite_); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error LevelDbStorage::Delete(const StorageOpts& opts, std::string_view key) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } leveldb::WriteOptions options; toWriteOptions(opts, options); leveldb::Status status = db_->Delete(options, leveldb::Slice(key.data(), key.size())); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(errLogic, status.ToString()); } Error LevelDbStorage::Repair(const std::string& path) { leveldb::Options options; auto status = leveldb::RepairDB(path, options); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(errLogic, status.ToString()); } Snapshot::Ptr LevelDbStorage::MakeSnapshot() { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } const leveldb::Snapshot* ldbSnapshot = db_->GetSnapshot(); assertrx(ldbSnapshot); return std::make_shared(ldbSnapshot); } void LevelDbStorage::ReleaseSnapshot(Snapshot::Ptr snapshot) { - if (!db_) throw Error(errParams, kStorageNotInitialized); - if (!snapshot) throw Error(errParams, "Storage pointer is null"); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } + if (!snapshot) { + throw Error(errParams, "Storage pointer is null"); + } const LevelDbSnapshot* levelDbSnpshot = static_cast(snapshot.get()); db_->ReleaseSnapshot(levelDbSnpshot->snapshot_); snapshot.reset(); @@ -110,7 +134,9 @@ Error LevelDbStorage::Reopen() { } Cursor* LevelDbStorage::GetCursor(StorageOpts& opts) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } leveldb::ReadOptions options; toReadOptions(opts, options); options.fill_cache = false; diff --git a/cpp_src/core/storage/rocksdbstorage.cc b/cpp_src/core/storage/rocksdbstorage.cc index 9535275b9..dc2dea9f1 100644 --- a/cpp_src/core/storage/rocksdbstorage.cc +++ b/cpp_src/core/storage/rocksdbstorage.cc @@ -25,63 +25,87 @@ static void toReadOptions(const StorageOpts& opts, rocksdb::ReadOptions& ropts) RocksDbStorage::RocksDbStorage() = default; Error RocksDbStorage::Read(const StorageOpts& opts, std::string_view key, std::string& value) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } rocksdb::ReadOptions options; toReadOptions(opts, options); rocksdb::Status status = db_->Get(options, rocksdb::Slice(key.data(), key.size()), &value); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error RocksDbStorage::Write(const StorageOpts& opts, std::string_view key, std::string_view value) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } rocksdb::WriteOptions options; toWriteOptions(opts, options); rocksdb::Status status = db_->Put(options, rocksdb::Slice(key.data(), key.size()), rocksdb::Slice(value.data(), value.size())); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error RocksDbStorage::Write(const StorageOpts& opts, UpdatesCollection& buffer) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } rocksdb::WriteOptions options; toWriteOptions(opts, options); RocksDbBatchBuffer* batchBuffer = static_cast(&buffer); rocksdb::Status status = db_->Write(options, &batchBuffer->batchWrite_); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(status.IsNotFound() ? errNotFound : errLogic, status.ToString()); } Error RocksDbStorage::Delete(const StorageOpts& opts, std::string_view key) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } rocksdb::WriteOptions options; toWriteOptions(opts, options); rocksdb::Status status = db_->Delete(options, rocksdb::Slice(key.data(), key.size())); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(errLogic, status.ToString()); } Error RocksDbStorage::Repair(const std::string& path) { rocksdb::Options options; auto status = rocksdb::RepairDB(path, options); - if (status.ok()) return Error(); + if (status.ok()) { + return Error(); + } return Error(errLogic, status.ToString()); } Snapshot::Ptr RocksDbStorage::MakeSnapshot() { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } const rocksdb::Snapshot* ldbSnapshot = db_->GetSnapshot(); assertrx(ldbSnapshot); return std::make_shared(ldbSnapshot); } void RocksDbStorage::ReleaseSnapshot(Snapshot::Ptr snapshot) { - if (!db_) throw Error(errParams, kStorageNotInitialized); - if (!snapshot) throw Error(errParams, "Storage pointer is null"); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } + if (!snapshot) { + throw Error(errParams, "Storage pointer is null"); + } const RocksDbSnapshot* levelDbSnpshot = static_cast(snapshot.get()); db_->ReleaseSnapshot(levelDbSnpshot->snapshot_); snapshot.reset(); @@ -109,7 +133,9 @@ Error RocksDbStorage::Reopen() { } Cursor* RocksDbStorage::GetCursor(StorageOpts& opts) { - if (!db_) throw Error(errParams, kStorageNotInitialized); + if (!db_) { + throw Error(errParams, kStorageNotInitialized); + } rocksdb::ReadOptions options; toReadOptions(opts, options); options.fill_cache = false; diff --git a/cpp_src/core/transaction.cc b/cpp_src/core/transaction.cc index 0bcb15282..1e63cd09f 100644 --- a/cpp_src/core/transaction.cc +++ b/cpp_src/core/transaction.cc @@ -2,65 +2,82 @@ #include "transactionimpl.h" namespace reindexer { -Transaction::Transaction(const std::string &nsName, const PayloadType &pt, const TagsMatcher &tm, const FieldsSet &pf, +Transaction::Transaction(const std::string& nsName, const PayloadType& pt, const TagsMatcher& tm, const FieldsSet& pf, std::shared_ptr schema) : impl_(new TransactionImpl(nsName, pt, tm, pf, std::move(schema))) {} -Transaction::Transaction(const Error &err) : status_(err) {} +Transaction::Transaction(const Error& err) : status_(err) {} Transaction::~Transaction() = default; -Transaction::Transaction(Transaction &&) noexcept = default; -Transaction &Transaction::operator=(Transaction &&) noexcept = default; +Transaction::Transaction(Transaction&&) noexcept = default; +Transaction& Transaction::operator=(Transaction&&) noexcept = default; -const std::string &Transaction::GetName() const { +const std::string& Transaction::GetName() const { static std::string empty; - if (impl_) + if (impl_) { return impl_->nsName_; - else + } else { return empty; + } } -void Transaction::Insert(Item &&item) { - if (impl_) impl_->Insert(std::move(item)); +void Transaction::Insert(Item&& item) { + if (impl_) { + impl_->Insert(std::move(item)); + } } -void Transaction::Update(Item &&item) { - if (impl_) impl_->Update(std::move(item)); +void Transaction::Update(Item&& item) { + if (impl_) { + impl_->Update(std::move(item)); + } } -void Transaction::Upsert(Item &&item) { - if (impl_) impl_->Upsert(std::move(item)); +void Transaction::Upsert(Item&& item) { + if (impl_) { + impl_->Upsert(std::move(item)); + } } -void Transaction::Delete(Item &&item) { - if (impl_) impl_->Delete(std::move(item)); +void Transaction::Delete(Item&& item) { + if (impl_) { + impl_->Delete(std::move(item)); + } } -void Transaction::Modify(Item &&item, ItemModifyMode mode) { - if (impl_) impl_->Modify(std::move(item), mode); +void Transaction::Modify(Item&& item, ItemModifyMode mode) { + if (impl_) { + impl_->Modify(std::move(item), mode); + } } -void Transaction::Modify(Query &&query) { - if (impl_) impl_->Modify(std::move(query)); +void Transaction::Modify(Query&& query) { + if (impl_) { + impl_->Modify(std::move(query)); + } } void Transaction::PutMeta(std::string_view key, std::string_view value) { - if (impl_) impl_->PutMeta(key, value); + if (impl_) { + impl_->PutMeta(key, value); + } } -void Transaction::MergeTagsMatcher(TagsMatcher &&tm) { - if (impl_) impl_->MergeTagsMatcher(std::move(tm)); +void Transaction::MergeTagsMatcher(TagsMatcher&& tm) { + if (impl_) { + impl_->MergeTagsMatcher(std::move(tm)); + } } Item Transaction::NewItem() { return impl_->NewItem(); } -std::vector &Transaction::GetSteps() { +std::vector& Transaction::GetSteps() { assertrx(impl_); return impl_->steps_; } -const std::vector &Transaction::GetSteps() const { +const std::vector& Transaction::GetSteps() const { assertrx(impl_); return impl_->steps_; } -Item Transaction::GetItem(TransactionStep &&st) { +Item Transaction::GetItem(TransactionStep&& st) { assertrx(impl_); return impl_->GetItem(std::move(st)); } @@ -75,8 +92,10 @@ Transaction::time_point Transaction::GetStartTime() const { return impl_->startTime_; } -void Transaction::ValidatePK(const FieldsSet &pkFields) { - if (impl_) impl_->ValidatePK(pkFields); +void Transaction::ValidatePK(const FieldsSet& pkFields) { + if (impl_) { + impl_->ValidatePK(pkFields); + } } } // namespace reindexer diff --git a/cpp_src/core/transaction.h b/cpp_src/core/transaction.h index 8e64e9886..8d0f92a48 100644 --- a/cpp_src/core/transaction.h +++ b/cpp_src/core/transaction.h @@ -15,36 +15,36 @@ class Transaction { public: using time_point = system_clock_w::time_point; - Transaction(const std::string &nsName, const PayloadType &pt, const TagsMatcher &tm, const FieldsSet &pf, + Transaction(const std::string& nsName, const PayloadType& pt, const TagsMatcher& tm, const FieldsSet& pf, std::shared_ptr schema); - Transaction(const Error &err); + Transaction(const Error& err); ~Transaction(); Transaction() = default; - Transaction(Transaction &&) noexcept; - Transaction &operator=(Transaction &&) noexcept; - - void Insert(Item &&item); - void Update(Item &&item); - void Upsert(Item &&item); - void Delete(Item &&item); - void Modify(Item &&item, ItemModifyMode mode); - void Modify(Query &&query); + Transaction(Transaction&&) noexcept; + Transaction& operator=(Transaction&&) noexcept; + + void Insert(Item&& item); + void Update(Item&& item); + void Upsert(Item&& item); + void Delete(Item&& item); + void Modify(Item&& item, ItemModifyMode mode); + void Modify(Query&& query); void PutMeta(std::string_view key, std::string_view value); - void MergeTagsMatcher(TagsMatcher &&tm); + void MergeTagsMatcher(TagsMatcher&& tm); bool IsFree() { return impl_ == nullptr; } Item NewItem(); - Item GetItem(TransactionStep &&st); + Item GetItem(TransactionStep&& st); Error Status() { return status_; } - const std::string &GetName() const; + const std::string& GetName() const; friend class ReindexerImpl; - std::vector &GetSteps(); - const std::vector &GetSteps() const; + std::vector& GetSteps(); + const std::vector& GetSteps() const; bool IsTagsUpdated() const; time_point GetStartTime() const; - void ValidatePK(const FieldsSet &pkFields); + void ValidatePK(const FieldsSet& pkFields); protected: std::unique_ptr impl_; diff --git a/cpp_src/core/transactionimpl.cc b/cpp_src/core/transactionimpl.cc index a9f33967a..f3380c9c2 100644 --- a/cpp_src/core/transactionimpl.cc +++ b/cpp_src/core/transactionimpl.cc @@ -4,9 +4,9 @@ namespace reindexer { -void TransactionImpl::checkTagsMatcher(Item &item) { +void TransactionImpl::checkTagsMatcher(Item& item) { if (item.IsTagsUpdated()) { - ItemImpl *ritem = item.impl_; + ItemImpl* ritem = item.impl_; if (ritem->Type().get() != payloadType_.get() || !tagsMatcher_.try_merge(ritem->tagsMatcher())) { std::string jsonSliceBuf(ritem->GetJSON()); @@ -15,10 +15,13 @@ void TransactionImpl::checkTagsMatcher(Item &item) { *ritem = std::move(tmpItem); auto err = ritem->FromJSON(jsonSliceBuf, nullptr); - if (!err.ok()) throw err; + if (!err.ok()) { + throw err; + } - if (ritem->tagsMatcher().isUpdated() && !tagsMatcher_.try_merge(ritem->tagsMatcher())) + if (ritem->tagsMatcher().isUpdated() && !tagsMatcher_.try_merge(ritem->tagsMatcher())) { throw Error(errLogic, "Could not insert item. TagsMatcher was not merged."); + } ritem->tagsMatcher() = tagsMatcher_; ritem->tagsMatcher().setUpdated(); } else { @@ -36,15 +39,15 @@ Item TransactionImpl::NewItem() { return item; } -Item TransactionImpl::GetItem(TransactionStep &&st) { +Item TransactionImpl::GetItem(TransactionStep&& st) { std::unique_lock lock(mtx_); - auto &data = std::get(st.data_); + auto& data = std::get(st.data_); auto item = Item(new ItemImpl(payloadType_, tagsMatcher_, pkFields_, schema_, std::move(data.data))); data.hadTmUpdate ? item.impl_->tagsMatcher().setUpdated() : item.impl_->tagsMatcher().clearUpdated(); return item; } -void TransactionImpl::ValidatePK(const FieldsSet &pkFields) { +void TransactionImpl::ValidatePK(const FieldsSet& pkFields) { std::lock_guard lck(mtx_); if (hasDeleteItemSteps_ && rx_unlikely(pkFields != pkFields_)) { throw Error( @@ -53,34 +56,34 @@ void TransactionImpl::ValidatePK(const FieldsSet &pkFields) { } } -void TransactionImpl::Insert(Item &&item) { +void TransactionImpl::Insert(Item&& item) { std::unique_lock lock(mtx_); checkTagsMatcher(item); steps_.emplace_back(std::move(item), ModeInsert); } -void TransactionImpl::Update(Item &&item) { +void TransactionImpl::Update(Item&& item) { std::unique_lock lock(mtx_); checkTagsMatcher(item); steps_.emplace_back(std::move(item), ModeUpdate); } -void TransactionImpl::Upsert(Item &&item) { +void TransactionImpl::Upsert(Item&& item) { std::unique_lock lock(mtx_); checkTagsMatcher(item); steps_.emplace_back(std::move(item), ModeUpsert); } -void TransactionImpl::Delete(Item &&item) { +void TransactionImpl::Delete(Item&& item) { std::unique_lock lock(mtx_); checkTagsMatcher(item); steps_.emplace_back(std::move(item), ModeDelete); } -void TransactionImpl::Modify(Item &&item, ItemModifyMode mode) { +void TransactionImpl::Modify(Item&& item, ItemModifyMode mode) { std::unique_lock lock(mtx_); checkTagsMatcher(item); hasDeleteItemSteps_ = hasDeleteItemSteps_ || (mode == ModeDelete); steps_.emplace_back(std::move(item), mode); } -void TransactionImpl::Modify(Query &&query) { +void TransactionImpl::Modify(Query&& query) { std::unique_lock lock(mtx_); steps_.emplace_back(std::move(query)); } @@ -94,7 +97,7 @@ void TransactionImpl::PutMeta(std::string_view key, std::string_view value) { steps_.emplace_back(key, value); } -void TransactionImpl::MergeTagsMatcher(TagsMatcher &&tm) { +void TransactionImpl::MergeTagsMatcher(TagsMatcher&& tm) { std::lock_guard lock(mtx_); if (!tagsMatcher_.try_merge(tm)) { throw Error(errParams, "Unable to merge incompatible TagsMatchers in transaction:\nCurrent:\n%s;\nNew:\n%s", tagsMatcher_.dump(), diff --git a/cpp_src/core/transactionimpl.h b/cpp_src/core/transactionimpl.h index 245ca6a6c..1ab14690b 100644 --- a/cpp_src/core/transactionimpl.h +++ b/cpp_src/core/transactionimpl.h @@ -28,20 +28,20 @@ class TransactionStep { public: enum class Type : uint8_t { Nop, ModifyItem, Query, PutMeta, DeleteMeta, SetTM }; - TransactionStep(Item &&item, ItemModifyMode modifyMode) + TransactionStep(Item&& item, ItemModifyMode modifyMode) : data_(TransactionItemStep{modifyMode, item.IsTagsUpdated(), std::move(*item.impl_)}), type_(Type::ModifyItem) { delete item.impl_; item.impl_ = nullptr; } - TransactionStep(TagsMatcher &&tm) : data_(TransactionTmStep{std::move(tm)}), type_(Type::SetTM) {} - TransactionStep(Query &&query) : data_(TransactionQueryStep{std::make_unique(std::move(query))}), type_(Type::Query) {} + TransactionStep(TagsMatcher&& tm) : data_(TransactionTmStep{std::move(tm)}), type_(Type::SetTM) {} + TransactionStep(Query&& query) : data_(TransactionQueryStep{std::make_unique(std::move(query))}), type_(Type::Query) {} TransactionStep(std::string_view key, std::string_view value) : data_(TransactionMetaStep{std::string(key), std::string(value)}), type_(Type::PutMeta) {} - TransactionStep(const TransactionStep &) = delete; - TransactionStep &operator=(const TransactionStep &) = delete; - TransactionStep(TransactionStep && /*rhs*/) = default; - TransactionStep &operator=(TransactionStep && /*rhs*/) = delete; + TransactionStep(const TransactionStep&) = delete; + TransactionStep& operator=(const TransactionStep&) = delete; + TransactionStep(TransactionStep&& /*rhs*/) = default; + TransactionStep& operator=(TransactionStep&& /*rhs*/) = delete; std::variant data_; Type type_; @@ -49,7 +49,7 @@ class TransactionStep { class TransactionImpl { public: - TransactionImpl(const std::string &nsName, const PayloadType &pt, const TagsMatcher &tm, const FieldsSet &pf, + TransactionImpl(const std::string& nsName, const PayloadType& pt, const TagsMatcher& tm, const FieldsSet& pf, std::shared_ptr schema) : payloadType_(pt), tagsMatcher_(tm), @@ -62,22 +62,22 @@ class TransactionImpl { tagsMatcher_.clearUpdated(); } - void Insert(Item &&item); - void Update(Item &&item); - void Upsert(Item &&item); - void Delete(Item &&item); - void Modify(Item &&item, ItemModifyMode mode); - void Modify(Query &&item); + void Insert(Item&& item); + void Update(Item&& item); + void Upsert(Item&& item); + void Delete(Item&& item); + void Modify(Item&& item, ItemModifyMode mode); + void Modify(Query&& item); void PutMeta(std::string_view key, std::string_view value); void MergeTagsMatcher(TagsMatcher&& tm); Item NewItem(); - Item GetItem(TransactionStep &&st); - void ValidatePK(const FieldsSet &pkFields); + Item GetItem(TransactionStep&& st); + void ValidatePK(const FieldsSet& pkFields); - const std::string &GetName() { return nsName_; } + const std::string& GetName() { return nsName_; } - void checkTagsMatcher(Item &item); + void checkTagsMatcher(Item& item); PayloadType payloadType_; TagsMatcher tagsMatcher_; diff --git a/cpp_src/core/type_consts_helpers.cc b/cpp_src/core/type_consts_helpers.cc index 92cad0c8f..1580971a3 100644 --- a/cpp_src/core/type_consts_helpers.cc +++ b/cpp_src/core/type_consts_helpers.cc @@ -26,7 +26,7 @@ namespace reindexer { case CondDWithin: break; } - throw Error(errForbidden, "Not invertible conditional operator '%s(%d)' in query", CondTypeToStr(cond), cond); + throw Error(errForbidden, "Not invertible conditional operator '%s(%s)' in query", CondTypeToStr(cond), CondTypeToStrShort(cond)); } [[nodiscard]] CondType InvertNotCondition(CondType cond) { @@ -49,7 +49,7 @@ namespace reindexer { case CondDWithin: break; } - throw Error(errForbidden, "Not invertible conditional operator '%s(%d)' in query", CondTypeToStr(cond), cond); + throw Error(errForbidden, "Not invertible conditional operator '%s(%s)' in query", CondTypeToStr(cond), CondTypeToStrShort(cond)); } [[nodiscard]] std::string_view CondTypeToStr(CondType t) { diff --git a/cpp_src/core/type_formats.h b/cpp_src/core/type_formats.h new file mode 100644 index 000000000..bf2c5737a --- /dev/null +++ b/cpp_src/core/type_formats.h @@ -0,0 +1,13 @@ +#pragma once + +#include "type_consts.h" + +inline constexpr int format_as(QueryItemType v) noexcept { return int(v); } +inline constexpr int format_as(IndexType v) noexcept { return int(v); } +inline constexpr int format_as(CondType v) noexcept { return int(v); } +inline constexpr int format_as(FieldModifyMode v) noexcept { return int(v); } +inline constexpr int format_as(AggType v) noexcept { return int(v); } +inline constexpr int format_as(OpType v) noexcept { return int(v); } +inline constexpr int format_as(QueryType v) noexcept { return int(v); } +inline constexpr int format_as(TagType v) noexcept { return int(v); } +inline constexpr int format_as(DataFormat v) noexcept { return int(v); } diff --git a/cpp_src/coroutine/channel.h b/cpp_src/coroutine/channel.h index d436afe72..bc426b873 100644 --- a/cpp_src/coroutine/channel.h +++ b/cpp_src/coroutine/channel.h @@ -19,10 +19,10 @@ class channel { throw std::logic_error("Empty channels are not allowed"); } } - channel(const channel &) = delete; - channel(channel &&) = delete; - channel &operator=(const channel &) = delete; - channel &operator=(channel &&) = delete; + channel(const channel&) = delete; + channel(channel&&) = delete; + channel& operator=(const channel&) = delete; + channel& operator=(channel&&) = delete; /// Push object to channel. /// If channel is full, current coroutine will suspend and wait for pop()-calls from other coroutines. @@ -30,7 +30,7 @@ class channel { /// If there are readers awaiting data, current coroutine will call resume() and switch to those readers. /// @param obj - Object to push template - void push(U &&obj) { + void push(U&& obj) { assertrx(current()); // For now channels should not be used from main routine dew to current resume/suspend logic bool await = false; while (full() || closed_) { @@ -127,13 +127,13 @@ class channel { return std::make_pair(T(), false); } template - void push_impl(U &&obj) { + void push_impl(U&& obj) { buf_[w_ptr_] = std::forward(obj); w_ptr_ = (w_ptr_ + 1) % buf_.size(); ++data_size_; assertrx(data_size_ <= buf_.size()); } - static void remove_waiter(waiters_container &waiters) { waiters.erase(std::find(waiters.begin(), waiters.end(), current())); } + static void remove_waiter(waiters_container& waiters) { waiters.erase(std::find(waiters.begin(), waiters.end(), current())); } h_vector buf_; size_t r_ptr_ = 0; diff --git a/cpp_src/coroutine/coroutine.cc b/cpp_src/coroutine/coroutine.cc index fc2aa749f..b5c62aa14 100644 --- a/cpp_src/coroutine/coroutine.cc +++ b/cpp_src/coroutine/coroutine.cc @@ -1,8 +1,8 @@ #include "coroutine.h" +#include #include #include #include -#include #include "tools/clock.h" namespace reindexer { @@ -10,7 +10,7 @@ namespace coroutine { static void static_entry() { ordinator::instance().entry(); } -ordinator &ordinator::instance() noexcept { +ordinator& ordinator::instance() noexcept { static thread_local ordinator ord; return ord; } @@ -18,12 +18,12 @@ ordinator &ordinator::instance() noexcept { void ordinator::entry() { const routine_t index = current_ - 1; { - routine ¤t_routine = routines_[index]; + routine& current_routine = routines_[index]; if (current_routine.func) { try { auto func = std::move(current_routine.func); func(); - } catch (std::exception &e) { + } catch (std::exception& e) { fprintf(stderr, "Unhandled exception in coroutine \"%u\": %s\n", index + 1, e.what()); } catch (...) { fprintf(stderr, "Unhandled exception in coroutine \"%u\": some custom exception\n", index + 1); @@ -31,7 +31,7 @@ void ordinator::entry() { } } - routine ¤t_routine = routines_[index]; + routine& current_routine = routines_[index]; remove_from_call_stack(index + 1); current_ = pop_from_call_stack(); current_routine.finalize(); @@ -66,13 +66,19 @@ int ordinator::resume(routine_t id) { assertrx(id <= routines_.size()); assertrx(id); // For now the main routine should not be resumed explicitly - if (id > routines_.size()) return -1; + if (id > routines_.size()) { + return -1; + } { - routine &routine = routines_[id - 1]; - if (routine.is_finalized()) return -2; + routine& routine = routines_[id - 1]; + if (routine.is_finalized()) { + return -2; + } - if (routine.is_empty()) routine.create_fiber(); + if (routine.is_empty()) { + routine.create_fiber(); + } push_to_call_stack(current_); current_ = id; @@ -80,7 +86,7 @@ int ordinator::resume(routine_t id) { routine.resume(); } - routine &routine = routines_[id - 1]; + routine& routine = routines_[id - 1]; if (routine.is_dead()) { clear_finalized(); } @@ -119,7 +125,9 @@ void ordinator::remove_from_call_stack(routine_t id) noexcept { } bool ordinator::set_loop_completion_callback(ordinator::cmpl_cb_t cb) noexcept { - if (loop_completion_callback_) return false; + if (loop_completion_callback_) { + return false; + } loop_completion_callback_ = std::move(cb); return true; } @@ -130,7 +138,7 @@ int64_t ordinator::add_completion_callback(ordinator::cmpl_cb_t cb) { for (;;) { id = steady_clock_w::now().time_since_epoch().count(); auto found = - std::find_if(completion_callbacks_.begin(), completion_callbacks_.end(), [id](cmpl_cb_data &data) { return data.id == id; }); + std::find_if(completion_callbacks_.begin(), completion_callbacks_.end(), [id](cmpl_cb_data& data) { return data.id == id; }); if (found == completion_callbacks_.end()) { break; } else if (++cnt == 3) { @@ -155,7 +163,7 @@ bool ordinator::remove_loop_completion_callback() noexcept { int ordinator::remove_completion_callback(int64_t id) noexcept { auto old_sz = completion_callbacks_.size(); completion_callbacks_.erase( - std::remove_if(completion_callbacks_.begin(), completion_callbacks_.end(), [id](cmpl_cb_data &data) { return data.id == id; }), + std::remove_if(completion_callbacks_.begin(), completion_callbacks_.end(), [id](cmpl_cb_data& data) { return data.id == id; }), completion_callbacks_.end()); auto diff = old_sz - completion_callbacks_.size(); if (diff == 0) { @@ -201,7 +209,7 @@ ordinator::routine::~routine() { } } -ordinator::routine::routine(ordinator::routine &&o) noexcept +ordinator::routine::routine(ordinator::routine&& o) noexcept : func(std::move(o.func)), fiber_(o.fiber_), stack_size_(o.stack_size_), is_empty_(o.is_empty_), finalized_(o.finalized_) { o.fiber_ = nullptr; } @@ -220,7 +228,7 @@ void ordinator::clear_finalized() { assertrx(!finalized_indexes_.empty()); auto index = finalized_indexes_.back(); - auto &routine = routines_[index]; + auto& routine = routines_[index]; assertrx(routine.is_finalized()); routine.clear(); if (loop_completion_callback_) { @@ -228,7 +236,7 @@ void ordinator::clear_finalized() { } auto callbacks = completion_callbacks_; - for (auto &callback : callbacks) { + for (auto& callback : callbacks) { callback.cb(index + 1); } } diff --git a/cpp_src/coroutine/coroutine.h b/cpp_src/coroutine/coroutine.h index 886732019..8bf9db2ba 100644 --- a/cpp_src/coroutine/coroutine.h +++ b/cpp_src/coroutine/coroutine.h @@ -19,12 +19,12 @@ class ordinator { public: using cmpl_cb_t = std::function; - ordinator(const ordinator &) = delete; - ordinator(ordinator &&) = delete; - ordinator &operator=(const ordinator &) = delete; - ordinator &operator=(ordinator &&) = delete; + ordinator(const ordinator&) = delete; + ordinator(ordinator&&) = delete; + ordinator& operator=(const ordinator&) = delete; + ordinator& operator=(ordinator&&) = delete; - static ordinator &instance() noexcept; + static ordinator& instance() noexcept; /// Create new coroutine in current thread /// @param function - Function, that will be executed in this coroutine @@ -69,15 +69,15 @@ class ordinator { public: routine() noexcept = default; ~routine(); - routine(const routine &) = delete; - routine(routine &&other) noexcept; - routine(std::function _func, koishi_coroutine_t *fiber, size_t stack_size) noexcept + routine(const routine&) = delete; + routine(routine&& other) noexcept; + routine(std::function _func, koishi_coroutine_t* fiber, size_t stack_size) noexcept : func(std::move(_func)), fiber_(fiber), stack_size_(stack_size), is_empty_(true) { assertrx(stack_size_); assertrx(fiber_); } - routine &operator=(const routine &) = delete; - routine &operator=(routine &&) = delete; + routine& operator=(const routine&) = delete; + routine& operator=(routine&&) = delete; /// Check if coroutine is already finished it's execution and ready to be cleared /// @returns true - if coroutine is finalized, false - if couroutine is still in progress @@ -104,7 +104,7 @@ class ordinator { std::function func; private: - koishi_coroutine_t *fiber_ = nullptr; + koishi_coroutine_t* fiber_ = nullptr; size_t stack_size_ = k_default_stack_limit; bool is_empty_ = true; bool finalized_ = false; diff --git a/cpp_src/debug/allocdebug.cc b/cpp_src/debug/allocdebug.cc index f5163e96a..a48fa0768 100644 --- a/cpp_src/debug/allocdebug.cc +++ b/cpp_src/debug/allocdebug.cc @@ -32,20 +32,28 @@ static bool ismt; #include "tools/alloc_ext/tc_malloc_extension.h" -static void traced_new_mt(const void *ptr, size_t size) { - if (ptr && size) tracer_mt.traced_new(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); +static void traced_new_mt(const void* ptr, size_t size) { + if (ptr && size) { + tracer_mt.traced_new(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); + } } -static void traced_delete_mt(const void *ptr) { - if (ptr) tracer_mt.traced_delete(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); +static void traced_delete_mt(const void* ptr) { + if (ptr) { + tracer_mt.traced_delete(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); + } } -static void traced_new(const void *ptr, size_t size) { - if (ptr && size) tracer.traced_new(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); +static void traced_new(const void* ptr, size_t size) { + if (ptr && size) { + tracer.traced_new(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); + } } -static void traced_delete(const void *ptr) { - if (ptr) tracer.traced_delete(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); +static void traced_delete(const void* ptr) { + if (ptr) { + tracer.traced_delete(reindexer::alloc_ext::instance()->GetAllocatedSize(const_cast(ptr))); + } } void allocdebug_init() { @@ -54,9 +62,8 @@ void allocdebug_init() { reindexer::alloc_ext::MallocHook_AddDeleteHook(traced_delete); ismt = false; } else { - reindexer::logPrintf( - LogWarning, - "Reindexer was compiled with GPerf tools, but tcmalloc was not successfully linked. Malloc new hook is unavailable"); + logPrintf(LogWarning, + "Reindexer was compiled with GPerf tools, but tcmalloc was not successfully linked. Malloc new hook is unavailable"); } } @@ -66,9 +73,8 @@ void allocdebug_init_mt() { reindexer::alloc_ext::MallocHook_AddDeleteHook(traced_delete_mt); ismt = true; } else { - reindexer::logPrintf( - LogWarning, - "Reindexer was compiled with GPerf tools, but tcmalloc was not successfully linked. Malloc delete hook is unavailable"); + logPrintf(LogWarning, + "Reindexer was compiled with GPerf tools, but tcmalloc was not successfully linked. Malloc delete hook is unavailable"); } } @@ -83,6 +89,6 @@ size_t get_alloc_size_total() { return ismt ? tracer_mt.alloced_sz_total.load() size_t get_alloc_cnt_total() { return ismt ? tracer_mt.alloced_cnt_total.load() : tracer.alloced_cnt_total; } void allocdebug_show() { - reindexer::logPrintf(LogInfo, "meminfo (alloced %dM, %d total allocs, %d remain)", get_alloc_size() / (1024 * 1024), - get_alloc_cnt_total(), get_alloc_cnt()); + logPrintf(LogInfo, "meminfo (alloced %dM, %d total allocs, %d remain)", get_alloc_size() / (1024 * 1024), get_alloc_cnt_total(), + get_alloc_cnt()); } diff --git a/cpp_src/debug/backtrace.cc b/cpp_src/debug/backtrace.cc index 92f1454d0..f4ba8dd4d 100644 --- a/cpp_src/debug/backtrace.cc +++ b/cpp_src/debug/backtrace.cc @@ -1,4 +1,5 @@ #include "backtrace.h" +#include #include #include #include @@ -9,16 +10,16 @@ namespace reindexer { namespace debug { static std::recursive_mutex g_mutex; -static crash_query_reporter_t g_crash_query_reporter = [](std::ostream &sout) { sout << "" << std::endl; }; +static crash_query_reporter_t g_crash_query_reporter = [](std::ostream& sout) { sout << "" << std::endl; }; static backtrace_writer_t g_writer = [](std::string_view sv) { std::cerr << sv; }; static std::string g_assertion_message(""); -void backtrace_set_assertion_message(std::string &&msg) noexcept { +void backtrace_set_assertion_message(std::string&& msg) noexcept { std::lock_guard lck(g_mutex); g_assertion_message = std::move(msg); } -static void print_assertion_message(std::ostream &sout) { +static void print_assertion_message(std::ostream& sout) { std::string msg(""); { std::lock_guard lck(g_mutex); @@ -67,7 +68,7 @@ extern "C" void abort() { } } -extern "C" void __assert_fail(const char *expr, const char *file, int line, const char *func) { +extern "C" void __assert_fail(const char* expr, const char* file, int line, const char* func) { fprintf(stderr, "Assertion failed: %s (%s: %s: %d)\n", expr, file, func, line); fflush(NULL); abort(); @@ -80,7 +81,7 @@ namespace debug { #if REINDEX_WITH_UNWIND class Unwinder { public: - size_t operator()(span trace) { + size_t operator()(span trace) { trace_ = trace; index_ = -1; _Unwind_Backtrace(&this->backtrace_trampoline, this); @@ -88,12 +89,14 @@ class Unwinder { } private: - static _Unwind_Reason_Code backtrace_trampoline(_Unwind_Context *ctx, void *self) { - return (static_cast(self))->backtrace(ctx); + static _Unwind_Reason_Code backtrace_trampoline(_Unwind_Context* ctx, void* self) { + return (static_cast(self))->backtrace(ctx); } - _Unwind_Reason_Code backtrace(_Unwind_Context *ctx) { - if (index_ >= 0 && size_t(index_) >= trace_.size()) return _URC_END_OF_STACK; + _Unwind_Reason_Code backtrace(_Unwind_Context* ctx) { + if (index_ >= 0 && size_t(index_) >= trace_.size()) { + return _URC_END_OF_STACK; + } int ip_before_instruction = 0; uintptr_t ip = _Unwind_GetIPInfo(ctx, &ip_before_instruction); @@ -107,17 +110,17 @@ class Unwinder { } if (index_ >= 0) { - trace_[index_] = reinterpret_cast(ip); + trace_[index_] = reinterpret_cast(ip); } index_++; return _URC_NO_REASON; } ssize_t index_; - span trace_; + span trace_; }; #endif -int backtrace_internal(void **addrlist, size_t size, void *ctx, std::string_view &method) { +int backtrace_internal(void** addrlist, size_t size, void* ctx, std::string_view& method) { using namespace std::string_view_literals; (void)ctx; size_t addrlen = 0; @@ -135,20 +138,20 @@ int backtrace_internal(void **addrlist, size_t size, void *ctx, std::string_view ctx = &uc; } - unw_init_local(&cursor, reinterpret_cast(ctx)); + unw_init_local(&cursor, reinterpret_cast(ctx)); addrlen = 1; do { unw_word_t ip; unw_get_reg(&cursor, UNW_REG_IP, &ip); - addrlist[addrlen++] = reinterpret_cast(ip); + addrlist[addrlen++] = reinterpret_cast(ip); } while (unw_step(&cursor) && addrlen < size); #endif #if REINDEX_WITH_UNWIND Unwinder unw; if (addrlen < 3) { // -V547 method = "unwind"sv; - addrlen = unw(span(addrlist, size)); + addrlen = unw(span(addrlist, size)); } #endif #if REINDEX_WITH_EXECINFO @@ -160,16 +163,18 @@ int backtrace_internal(void **addrlist, size_t size, void *ctx, std::string_view return addrlen; } -void print_backtrace(std::ostream &sout, void *ctx, int sig) { +void print_backtrace(std::ostream& sout, void* ctx, int sig) { #if !REINDEX_WITH_EXECINFO && !REINDEX_WITH_UNWIND && !REINDEX_WITH_LIBUNWIND sout << "Sorry, reindexer has been compiled without any backtrace methods." << std::endl; #else - void *addrlist[64] = {}; + void* addrlist[64] = {}; auto resolver = TraceResolver::New(); std::string_view method; int addrlen = backtrace_internal(addrlist, sizeof(addrlist) / sizeof(addrlist[0]), ctx, method); - if (sig >= 0) sout << "Signal " << sig << " "; + if (sig >= 0) { + sout << "Signal " << sig << " "; + } sout << "backtrace (" << method << "):" << std::endl; for (int i = 1; i < addrlen; i++) { auto te = TraceEntry(uintptr_t(addrlist[i])); @@ -179,7 +184,7 @@ void print_backtrace(std::ostream &sout, void *ctx, int sig) { #endif } -void print_crash_query(std::ostream &sout) { +void print_crash_query(std::ostream& sout) { auto crash_query_reporter = backtrace_get_crash_query_reporter(); if (crash_query_reporter) { crash_query_reporter(sout); @@ -188,7 +193,7 @@ void print_crash_query(std::ostream &sout) { } } -static void sighandler(int sig, siginfo_t *, void *ctx) { +static void sighandler(int sig, siginfo_t*, void* ctx) { const auto writer = backtrace_get_writer(); std::ostringstream sout; sout << "*** Backtrace on signal: " << sig << " ***" << std::endl; @@ -219,7 +224,7 @@ void backtrace_init() noexcept { sigaction(SIGBUS, &sa, nullptr); } -void set_minidump_path(const std::string &) { assert(false); } +void set_minidump_path(const std::string&) { assert(false); } void backtrace_set_writer(backtrace_writer_t writer) { std::lock_guard lck(g_mutex); @@ -249,6 +254,7 @@ crash_query_reporter_t backtrace_get_crash_query_reporter() { #undef min #undef max #include +#include #include "cpptrace/cpptrace.hpp" #include "tools/clock.h" @@ -256,7 +262,7 @@ namespace reindexer { namespace debug { static std::string g_pathMiniDump; -void outputDebugInfo(const backtrace_writer_t &writer, EXCEPTION_POINTERS *ExceptionInfo) { +void outputDebugInfo(const backtrace_writer_t& writer, EXCEPTION_POINTERS* ExceptionInfo) { std::ostringstream sout; print_crash_query(sout); writer(sout.str()); @@ -313,13 +319,13 @@ void backtrace_init() noexcept { SetUnhandledExceptionFilter(exceptionHandler); } -void set_minidump_path(const std::string &p) { g_pathMiniDump = p; } +void set_minidump_path(const std::string& p) { g_pathMiniDump = p; } void backtrace_set_writer(backtrace_writer_t writer) { std::lock_guard lck(g_mutex); g_writer = std::move(writer); } -int backtrace_internal(void **, size_t, void *, std::string_view &) { return 0; } +int backtrace_internal(void**, size_t, void*, std::string_view&) { return 0; } void backtrace_set_crash_query_reporter(crash_query_reporter_t reporter) { std::lock_guard lck(g_mutex); g_crash_query_reporter = std::move(reporter); @@ -332,10 +338,12 @@ crash_query_reporter_t backtrace_get_crash_query_reporter() { std::lock_guard lck(g_mutex); return g_crash_query_reporter; } -void print_backtrace(std::ostream &sout, void *, int) { cpptrace::generate_trace().print(sout, false); } -void print_crash_query(std::ostream &sout) { +void print_backtrace(std::ostream& sout, void*, int) { cpptrace::generate_trace().print(sout, false); } +void print_crash_query(std::ostream& sout) { auto reporter = backtrace_get_crash_query_reporter(); - if (reporter) reporter(sout); + if (reporter) { + reporter(sout); + } } } // namespace debug @@ -344,13 +352,13 @@ void print_crash_query(std::ostream &sout) { namespace reindexer { namespace debug { static std::recursive_mutex g_mutex; -static crash_query_reporter_t g_crash_query_reporter = [](std::ostream &) {}; +static crash_query_reporter_t g_crash_query_reporter = [](std::ostream&) {}; static backtrace_writer_t g_writer = [](std::string_view sv) { std::cerr << sv; }; void backtrace_init() noexcept {} -void set_minidump_path(const std::string &) { assert(false); } +void set_minidump_path(const std::string&) { assert(false); } void backtrace_set_writer(backtrace_writer_t) {} -int backtrace_internal(void **, size_t, void *, std::string_view &) { return 0; } +int backtrace_internal(void**, size_t, void*, std::string_view&) { return 0; } void backtrace_set_crash_query_reporter(crash_query_reporter_t reporter) { std::lock_guard lck(g_mutex); g_crash_query_reporter = std::move(reporter); @@ -363,10 +371,12 @@ crash_query_reporter_t backtrace_get_crash_query_reporter() { std::lock_guard lck(g_mutex); return g_crash_query_reporter; } -void print_backtrace(std::ostream &, void *, int) {} -void print_crash_query(std::ostream &sout) { +void print_backtrace(std::ostream&, void*, int) {} +void print_crash_query(std::ostream& sout) { auto reporter = backtrace_get_crash_query_reporter(); - if (reporter) reporter(sout); + if (reporter) { + reporter(sout); + } } } // namespace debug diff --git a/cpp_src/debug/backtrace.h b/cpp_src/debug/backtrace.h index 2339f3503..6d367a6ab 100644 --- a/cpp_src/debug/backtrace.h +++ b/cpp_src/debug/backtrace.h @@ -7,17 +7,17 @@ namespace reindexer { namespace debug { using backtrace_writer_t = std::function; -using crash_query_reporter_t = std::function; +using crash_query_reporter_t = std::function; void backtrace_init() noexcept; -void set_minidump_path(const std::string &p); +void set_minidump_path(const std::string& p); void backtrace_set_writer(backtrace_writer_t); void backtrace_set_crash_query_reporter(crash_query_reporter_t); backtrace_writer_t backtrace_get_writer(); crash_query_reporter_t backtrace_get_crash_query_reporter(); -int backtrace_internal(void **addrlist, size_t size, void *ctx, std::string_view &method); -void backtrace_set_assertion_message(std::string &&msg) noexcept; -void print_backtrace(std::ostream &sout, void *ctx, int sig); -void print_crash_query(std::ostream &sout); +int backtrace_internal(void** addrlist, size_t size, void* ctx, std::string_view& method); +void backtrace_set_assertion_message(std::string&& msg) noexcept; +void print_backtrace(std::ostream& sout, void* ctx, int sig); +void print_crash_query(std::ostream& sout); } // namespace debug } // namespace reindexer diff --git a/cpp_src/debug/crashqueryreporter.cc b/cpp_src/debug/crashqueryreporter.cc index b9d913d71..2ff28287f 100644 --- a/cpp_src/debug/crashqueryreporter.cc +++ b/cpp_src/debug/crashqueryreporter.cc @@ -8,7 +8,7 @@ namespace reindexer { struct QueryDebugContext { bool HasTrackedQuery() const noexcept { return mainQuery || externQuery || parentQuery || !externSql.empty(); } - std::string_view GetMainSQL(std::string &storage) const noexcept { + std::string_view GetMainSQL(std::string& storage) const noexcept { try { storage.clear(); if (mainQuery) { @@ -23,7 +23,7 @@ struct QueryDebugContext { return ""; } } - std::string_view GetParentSQL(std::string &storage) const noexcept { + std::string_view GetParentSQL(std::string& storage) const noexcept { try { storage.clear(); if (parentQuery) { @@ -39,22 +39,22 @@ struct QueryDebugContext { externSql = std::string_view(); } - const Query *mainQuery = nullptr; - const Query *externQuery = nullptr; + const Query* mainQuery = nullptr; + const Query* externQuery = nullptr; std::string_view externSql; - const Query *parentQuery = nullptr; - std::atomic *nsOptimizationState = nullptr; - ExplainCalc *explainCalc = nullptr; - std::atomic_bool *nsLockerState = nullptr; - StringsHolder *nsStrHolder = nullptr; + const Query* parentQuery = nullptr; + std::atomic* nsOptimizationState = nullptr; + ExplainCalc* explainCalc = nullptr; + std::atomic_bool* nsLockerState = nullptr; + StringsHolder* nsStrHolder = nullptr; QueryType realQueryType = QuerySelect; QueryType externRealQueryType = QuerySelect; }; thread_local QueryDebugContext g_queryDebugCtx; -ActiveQueryScope::ActiveQueryScope(SelectCtx &ctx, std::atomic &nsOptimizationState, ExplainCalc &explainCalc, - std::atomic_bool &nsLockerState, StringsHolder *strHolder) noexcept +ActiveQueryScope::ActiveQueryScope(SelectCtx& ctx, std::atomic& nsOptimizationState, ExplainCalc& explainCalc, + std::atomic_bool& nsLockerState, StringsHolder* strHolder) noexcept : type_(ctx.requiresCrashTracking ? Type::CoreQueryTracker : Type::NoTracking) { if (ctx.requiresCrashTracking) { g_queryDebugCtx.mainQuery = &ctx.query; @@ -67,8 +67,8 @@ ActiveQueryScope::ActiveQueryScope(SelectCtx &ctx, std::atomic &nsOptimizat } } -ActiveQueryScope::ActiveQueryScope(const Query &q, QueryType realQueryType, std::atomic &nsOptimizationState, - StringsHolder *strHolder) noexcept +ActiveQueryScope::ActiveQueryScope(const Query& q, QueryType realQueryType, std::atomic& nsOptimizationState, + StringsHolder* strHolder) noexcept : type_(Type::CoreQueryTracker) { g_queryDebugCtx.mainQuery = &q; g_queryDebugCtx.parentQuery = nullptr; @@ -79,7 +79,7 @@ ActiveQueryScope::ActiveQueryScope(const Query &q, QueryType realQueryType, std: g_queryDebugCtx.realQueryType = realQueryType; } -ActiveQueryScope::ActiveQueryScope(const Query &q, QueryType realQueryType) noexcept : type_(Type::ExternalQueryTracker) { +ActiveQueryScope::ActiveQueryScope(const Query& q, QueryType realQueryType) noexcept : type_(Type::ExternalQueryTracker) { g_queryDebugCtx.externQuery = &q; g_queryDebugCtx.externRealQueryType = realQueryType; } @@ -134,7 +134,7 @@ static std::string_view nsOptimizationStateName(int state) { } } -void PrintCrashedQuery(std::ostream &out) { +void PrintCrashedQuery(std::ostream& out) { if (!g_queryDebugCtx.HasTrackedQuery()) { out << "*** No additional info from crash query tracker ***" << std::endl; return; @@ -163,11 +163,13 @@ void PrintCrashedQuery(std::ostream &out) { out << " memstat = " << g_queryDebugCtx.nsStrHolder->MemStat() << std::endl; out << " holds indexes = " << std::boolalpha << g_queryDebugCtx.nsStrHolder->HoldsIndexes() << std::endl; if (g_queryDebugCtx.nsStrHolder->HoldsIndexes()) { - const auto &indexes = g_queryDebugCtx.nsStrHolder->Indexes(); + const auto& indexes = g_queryDebugCtx.nsStrHolder->Indexes(); out << " indexes.size = " << indexes.size() << std::endl; out << " indexes = ["; for (size_t i = 0; i < indexes.size(); ++i) { - if (i) out << " "; + if (i) { + out << " "; + } out << indexes[i]->Name(); } out << "]" << std::endl; diff --git a/cpp_src/debug/crashqueryreporter.h b/cpp_src/debug/crashqueryreporter.h index cf4472292..5d6746766 100644 --- a/cpp_src/debug/crashqueryreporter.h +++ b/cpp_src/debug/crashqueryreporter.h @@ -14,11 +14,11 @@ class Query; class ActiveQueryScope { public: // Core query scope - ActiveQueryScope(SelectCtx &ctx, std::atomic &nsOptimizationState, ExplainCalc &explainCalc, std::atomic_bool &nsLockerState, - StringsHolder *strHolder) noexcept; - ActiveQueryScope(const Query &q, QueryType realQueryType, std::atomic &nsOptimizationState, StringsHolder *strHolder) noexcept; + ActiveQueryScope(SelectCtx& ctx, std::atomic& nsOptimizationState, ExplainCalc& explainCalc, std::atomic_bool& nsLockerState, + StringsHolder* strHolder) noexcept; + ActiveQueryScope(const Query& q, QueryType realQueryType, std::atomic& nsOptimizationState, StringsHolder* strHolder) noexcept; // External query scope - ActiveQueryScope(const Query &q, QueryType realQueryType) noexcept; + ActiveQueryScope(const Query& q, QueryType realQueryType) noexcept; explicit ActiveQueryScope(std::string_view sql) noexcept; ~ActiveQueryScope(); @@ -28,6 +28,6 @@ class ActiveQueryScope { Type type_ = Type::NoTracking; }; -void PrintCrashedQuery(std::ostream &sout); +void PrintCrashedQuery(std::ostream& sout); } // namespace reindexer diff --git a/cpp_src/debug/resolver.cc b/cpp_src/debug/resolver.cc index ee2de5787..f6e5bd4c6 100644 --- a/cpp_src/debug/resolver.cc +++ b/cpp_src/debug/resolver.cc @@ -36,7 +36,7 @@ namespace debug { using namespace std::string_view_literals; -TraceEntry::TraceEntry(TraceEntry &&other) noexcept +TraceEntry::TraceEntry(TraceEntry&& other) noexcept : funcName_(other.funcName_), objFile_(other.objFile_), srcFile_(other.srcFile_), @@ -48,7 +48,7 @@ TraceEntry::TraceEntry(TraceEntry &&other) noexcept other.holder_ = nullptr; } -TraceEntry &TraceEntry::operator=(TraceEntry &&other) noexcept { +TraceEntry& TraceEntry::operator=(TraceEntry&& other) noexcept { if (this != &other) { funcName_ = other.funcName_; objFile_ = other.objFile_; @@ -73,7 +73,9 @@ TraceEntry::TraceEntry(uintptr_t addr) { #if REINDEX_WITH_LIBDL Dl_info dl_info; - if (!dladdr(reinterpret_cast(addr), &dl_info)) return; + if (!dladdr(reinterpret_cast(addr), &dl_info)) { + return; + } objFile_ = dl_info.dli_fname; ofs_ = uintptr_t(addr) - uintptr_t(dl_info.dli_saddr); @@ -90,7 +92,7 @@ TraceEntry::TraceEntry(uintptr_t addr) { #endif } -std::ostream &TraceEntry::Dump(std::ostream &os) const { +std::ostream& TraceEntry::Dump(std::ostream& os) const { os << "0x" << std::hex << std::setfill('0') << std::setw(14) << addr_ << " " << funcName_ << std::dec; if (srcLine_) { // pretty print file path: @@ -101,14 +103,17 @@ std::ostream &TraceEntry::Dump(std::ostream &os) const { std::string srcFile(srcFile_); if (fs::Stat(srcFile) != fs::StatFile) { auto pos = srcFile.find("cpp_src/"); - if (pos != std::string::npos) srcFile = srcFile.substr(pos); + if (pos != std::string::npos) { + srcFile = srcFile.substr(pos); + } } else { srcFile = fs::GetRelativePath(srcFile, 2); } os << " (" << srcFile << ":" << srcLine_ << ")"; - } else + } else { os << " + " << ofs_; + } return os; } @@ -117,7 +122,7 @@ class TraceResolverLibbacktrace : public TraceResolver { public: TraceResolverLibbacktrace() { init(); } - bool Resolve(TraceEntry &te) override final { + bool Resolve(TraceEntry& te) override final { backtrace_pcinfo(state_, te.addr_, callback, errorCallback, &te); return true; } @@ -127,12 +132,12 @@ class TraceResolverLibbacktrace : public TraceResolver { state_ = backtrace_create_state("/proc/self/exe", 1, errorCallback, NULL); return true; } - static void errorCallback(void * /*data*/, const char *msg, int errnum) { + static void errorCallback(void* /*data*/, const char* msg, int errnum) { std::cerr << "libbacktarce error:" << msg << " " << errnum << std::endl; } - static int callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char * /*function*/) { - TraceEntry *te = reinterpret_cast(data); + static int callback(void* data, uintptr_t /*pc*/, const char* filename, int lineno, const char* /*function*/) { + TraceEntry* te = reinterpret_cast(data); if (filename) { te->srcFile_ = filename; te->srcLine_ = lineno; @@ -144,7 +149,7 @@ class TraceResolverLibbacktrace : public TraceResolver { } protected: - backtrace_state *state_ = nullptr; + backtrace_state* state_ = nullptr; }; std::unique_ptr TraceResolver::New() { return std::unique_ptr(new TraceResolverLibbacktrace()); } @@ -156,15 +161,19 @@ class TraceResolverApple : public TraceResolver { TraceResolverApple() { init(); } ~TraceResolverApple() { CSRelease(cs_); } - bool Resolve(TraceEntry &te) { + bool Resolve(TraceEntry& te) { bool ret = false; - if (!cs_.csCppData || !cs_.csCppObj) return false; + if (!cs_.csCppData || !cs_.csCppObj) { + return false; + } auto info = CSSymbolicatorGetSourceInfoWithAddressAtTime(cs_, te.addr_, CS_NOW); auto sym = (info.csCppData && info.csCppObj) ? CSSourceInfoGetSymbol(info) : CSSymbolicatorGetSymbolWithAddressAtTime(cs_, te.addr_, CS_NOW); - if (!sym.csCppData || !sym.csCppObj) return false; + if (!sym.csCppData || !sym.csCppObj) { + return false; + } auto owner = CSSymbolGetSymbolOwner(sym); if (owner.csCppData && owner.csCppObj) { @@ -181,7 +190,9 @@ class TraceResolverApple : public TraceResolver { protected: bool init() { auto hlib = dlopen("/System/Library/PrivateFrameworks/CoreSymbolication.framework/Versions/A/CoreSymbolication", RTLD_NOW); - if (!hlib) return false; + if (!hlib) { + return false; + } CSSymbolicatorCreateWithPid = reinterpret_cast(dlsym(hlib, "CSSymbolicatorCreateWithPid")); CSRelease = reinterpret_cast(dlsym(hlib, "CSRelease")); @@ -197,13 +208,15 @@ class TraceResolverApple : public TraceResolver { bool ok = CSSymbolicatorCreateWithPid && CSRelease && CSSymbolicatorGetSymbolWithAddressAtTime && CSSymbolicatorGetSourceInfoWithAddressAtTime && CSSourceInfoGetLineNumber && CSSourceInfoGetPath && CSSourceInfoGetSymbol && CSSymbolGetSymbolOwner; - if (ok) cs_ = CSSymbolicatorCreateWithPid(getpid()); + if (ok) { + cs_ = CSSymbolicatorCreateWithPid(getpid()); + } return ok; } struct CSTypeRef { - void *csCppData; - void *csCppObj; + void* csCppData; + void* csCppObj; }; static uint64_t constexpr CS_NOW = 0x80000000; @@ -217,7 +230,7 @@ class TraceResolverApple : public TraceResolver { typedef CSSymbolRef (*pCSSymbolicatorGetSymbolWithAddressAtTime)(CSSymbolicatorRef cs, vm_address_t addr, uint64_t time); typedef CSSourceInfoRef (*pCSSymbolicatorGetSourceInfoWithAddressAtTime)(CSSymbolicatorRef cs, vm_address_t addr, uint64_t time); typedef int (*pCSSourceInfoGetLineNumber)(CSSourceInfoRef info); - typedef const char *(*pCSSourceInfoGetPath)(CSSourceInfoRef info); + typedef const char* (*pCSSourceInfoGetPath)(CSSourceInfoRef info); typedef CSSymbolRef (*pCSSourceInfoGetSymbol)(CSSourceInfoRef info); typedef CSSymbolOwnerRef (*pCSSymbolGetSymbolOwner)(CSSymbolRef sym); diff --git a/cpp_src/debug/resolver.h b/cpp_src/debug/resolver.h index 9d052af1f..f6ba3a281 100644 --- a/cpp_src/debug/resolver.h +++ b/cpp_src/debug/resolver.h @@ -15,11 +15,11 @@ class TraceEntry { TraceEntry(uintptr_t addr); TraceEntry() = default; ~TraceEntry(); - TraceEntry(TraceEntry &&other) noexcept; - TraceEntry &operator=(TraceEntry &&) noexcept; - TraceEntry(const TraceEntry &) = delete; - TraceEntry &operator=(const TraceEntry &) = delete; - std::ostream &Dump(std::ostream &os) const; + TraceEntry(TraceEntry&& other) noexcept; + TraceEntry& operator=(TraceEntry&&) noexcept; + TraceEntry(const TraceEntry&) = delete; + TraceEntry& operator=(const TraceEntry&) = delete; + std::ostream& Dump(std::ostream& os) const; std::string_view FuncName() { return funcName_; } // protected: @@ -38,16 +38,16 @@ class TraceEntry { /// Base address of object uintptr_t baseAddr_ = 0; /// Holder of temporary data - char *holder_ = nullptr; + char* holder_ = nullptr; }; -static inline std::ostream &operator<<(std::ostream &os, const TraceEntry &e) { return e.Dump(os); } +static inline std::ostream& operator<<(std::ostream& os, const TraceEntry& e) { return e.Dump(os); } class TraceResolver { public: static std::unique_ptr New(); virtual ~TraceResolver() = default; - virtual bool Resolve(TraceEntry &) { return false; } + virtual bool Resolve(TraceEntry&) { return false; } }; } // namespace debug diff --git a/cpp_src/debug/terminate_handler.cpp b/cpp_src/debug/terminate_handler.cpp index 4ed5ddb71..e69791d04 100644 --- a/cpp_src/debug/terminate_handler.cpp +++ b/cpp_src/debug/terminate_handler.cpp @@ -15,18 +15,18 @@ static void terminate_handler() { std::exception_ptr exptr = std::current_exception(); if (exptr) { #ifndef _WIN32 - const char *type = abi::__cxa_current_exception_type()->name(); + const char* type = abi::__cxa_current_exception_type()->name(); int status; - const char *demangled = abi::__cxa_demangle(type, NULL, NULL, &status); + const char* demangled = abi::__cxa_demangle(type, NULL, NULL, &status); sout << "*** Terminating with uncaught exception of type " << (demangled ? demangled : type); #else sout << "*** Terminating with uncaught exception "; #endif try { std::rethrow_exception(exptr); - } catch (std::exception &ex) { + } catch (std::exception& ex) { sout << ": " << ex.what(); - } catch (Error &err) { + } catch (Error& err) { sout << ": " << err.what(); } catch (...) { sout << ": "; diff --git a/cpp_src/estl/atomic_unique_ptr.h b/cpp_src/estl/atomic_unique_ptr.h index 53b916433..ef8c26912 100644 --- a/cpp_src/estl/atomic_unique_ptr.h +++ b/cpp_src/estl/atomic_unique_ptr.h @@ -25,7 +25,9 @@ class atomic_unique_ptr { void reset(pointer p = pointer(), std::memory_order order = std::memory_order_seq_cst) { auto old = ptr.exchange(p, order); - if (old) delete old; + if (old) { + delete old; + } } operator pointer() const { return ptr; } pointer operator->() const { return ptr; } @@ -60,7 +62,9 @@ class atomic_unique_ptr // for array types void reset(pointer p = pointer(), std::memory_order order = std::memory_order_seq_cst) { auto old = ptr.exchange(p, order); - if (old) delete[] old; + if (old) { + delete[] old; + } } operator pointer() const { return ptr; } pointer operator->() const { return ptr; } diff --git a/cpp_src/estl/cbuf.h b/cpp_src/estl/cbuf.h index db34f89b7..1b235ebe5 100644 --- a/cpp_src/estl/cbuf.h +++ b/cpp_src/estl/cbuf.h @@ -17,14 +17,14 @@ class cbuf { full_ = false; buf_size_ = bufsize; } - cbuf(cbuf &&other) noexcept + cbuf(cbuf&& other) noexcept : head_(other.head_), tail_(other.tail_), full_(other.full_), buf_size_(other.buf_size_), buf_(std::move(other.buf_)) { other.head_ = 0; other.tail_ = 0; other.full_ = false; other.buf_size_ = 0; } - cbuf &operator=(cbuf &&other) noexcept { + cbuf& operator=(cbuf&& other) noexcept { if (this != &other) { buf_ = std::move(other.buf_); head_ = other.head_; @@ -38,46 +38,64 @@ class cbuf { } return *this; } - cbuf(const cbuf &) = delete; - cbuf &operator=(const cbuf &) = delete; + cbuf(const cbuf&) = delete; + cbuf& operator=(const cbuf&) = delete; - size_t write(const T *p_ins, size_t s_ins) { - if (s_ins > available()) grow(std::max(s_ins - available(), buf_size_)); + size_t write(const T* p_ins, size_t s_ins) { + if (s_ins > available()) { + grow(std::max(s_ins - available(), buf_size_)); + } - if (!s_ins) return 0; + if (!s_ins) { + return 0; + } size_t lSize = buf_size_ - head_; std::copy(p_ins, p_ins + std::min(s_ins, lSize), &buf_[head_]); - if (s_ins > lSize) std::copy(p_ins + lSize, p_ins + s_ins, &buf_[0]); + if (s_ins > lSize) { + std::copy(p_ins + lSize, p_ins + s_ins, &buf_[0]); + } head_ = (head_ + s_ins) % buf_size_; full_ = (head_ == tail_); return s_ins; } - size_t read(T *p_ins, size_t s_ins) { - if (s_ins > size()) s_ins = size(); + size_t read(T* p_ins, size_t s_ins) { + if (s_ins > size()) { + s_ins = size(); + } - if (!s_ins) return 0; + if (!s_ins) { + return 0; + } size_t lSize = buf_size_ - tail_; std::copy(&buf_[tail_], &buf_[tail_ + std::min(s_ins, lSize)], p_ins); - if (s_ins > lSize) std::copy(&buf_[0], &buf_[s_ins - lSize], p_ins + lSize); + if (s_ins > lSize) { + std::copy(&buf_[0], &buf_[s_ins - lSize], p_ins + lSize); + } tail_ = (tail_ + s_ins) % buf_size_; full_ = false; return s_ins; } - size_t peek(T *p_ins, size_t s_ins) { - if (s_ins > size()) s_ins = size(); + size_t peek(T* p_ins, size_t s_ins) { + if (s_ins > size()) { + s_ins = size(); + } - if (!s_ins) return 0; + if (!s_ins) { + return 0; + } size_t lSize = buf_size_ - tail_; std::copy(&buf_[tail_], &buf_[tail_ + std::min(s_ins, lSize)], p_ins); - if (s_ins > lSize) std::copy(&buf_[0], &buf_[s_ins - lSize], p_ins + lSize); + if (s_ins > lSize) { + std::copy(&buf_[0], &buf_[s_ins - lSize], p_ins + lSize); + } return s_ins; } @@ -98,7 +116,9 @@ class cbuf { size_t size() noexcept { std::ptrdiff_t D = head_ - tail_; - if (D < 0 || (D == 0 && full_)) D += buf_size_; + if (D < 0 || (D == 0 && full_)) { + D += buf_size_; + } return D; } @@ -124,7 +144,9 @@ class cbuf { void unroll() { grow(0); } size_t available() noexcept { return (buf_size_ - size()); } void reserve(size_t sz) { - if (sz > capacity()) grow(sz - capacity()); + if (sz > capacity()) { + grow(sz - capacity()); + } } protected: @@ -135,7 +157,9 @@ class cbuf { std::unique_ptr new_buf(new T[new_size]); std::copy(&buf_[tail_], &buf_[tail_ + std::min(sz, lSize)], &new_buf[0]); - if (sz > lSize) std::copy(&buf_[0], &buf_[head_], &new_buf[lSize]); + if (sz > lSize) { + std::copy(&buf_[0], &buf_[head_], &new_buf[lSize]); + } tail_ = 0; head_ = sz % new_size; diff --git a/cpp_src/estl/chunk.h b/cpp_src/estl/chunk.h index 6c8db6b1d..0dff3802c 100644 --- a/cpp_src/estl/chunk.h +++ b/cpp_src/estl/chunk.h @@ -10,11 +10,11 @@ namespace reindexer { class chunk { public: chunk() noexcept : data_(nullptr), len_(0), offset_(0), cap_(0) {} - chunk(uint8_t *data, size_t len, size_t cap, size_t offset = 0) noexcept : data_(data), len_(len), offset_(offset), cap_(cap) {} + chunk(uint8_t* data, size_t len, size_t cap, size_t offset = 0) noexcept : data_(data), len_(len), offset_(offset), cap_(cap) {} ~chunk() { delete[] data_; } - chunk(const chunk &) = delete; - chunk &operator=(const chunk &) = delete; - chunk(chunk &&other) noexcept { + chunk(const chunk&) = delete; + chunk& operator=(const chunk&) = delete; + chunk(chunk&& other) noexcept { data_ = other.data_; len_ = other.len_; offset_ = other.offset_; @@ -24,7 +24,7 @@ class chunk { other.cap_ = 0; other.offset_ = 0; } - chunk &operator=(chunk &&other) noexcept { + chunk& operator=(chunk&& other) noexcept { if (this != &other) { delete[] data_; data_ = other.data_; @@ -42,7 +42,7 @@ class chunk { void append_strict(std::string_view data) { append_impl(data, len_ + data.size()); } size_t size() const noexcept { return len_ - offset_; } - uint8_t *data() const noexcept { return data_ + offset_; } + uint8_t* data() const noexcept { return data_ + offset_; } size_t capacity() const noexcept { return cap_; } size_t len() const noexcept { return len_; } size_t offset() const noexcept { return offset_; } @@ -52,7 +52,7 @@ class chunk { offset_ = 0; } void shift(size_t offset) noexcept { offset_ += offset; } - uint8_t *release() noexcept { + uint8_t* release() noexcept { auto res = data_; data_ = nullptr; return res; @@ -64,7 +64,7 @@ class chunk { } cap_ = k * size(); - uint8_t *newdata = new uint8_t[cap_]; + uint8_t* newdata = new uint8_t[cap_]; if (data_) { memcpy(newdata, data(), size()); len_ = size(); @@ -78,7 +78,7 @@ class chunk { void append_impl(std::string_view data, size_t newCapacity) { if (!data_ || len_ + data.size() > cap_) { cap_ = newCapacity; - uint8_t *newdata = new uint8_t[cap_]; + uint8_t* newdata = new uint8_t[cap_]; if (data_) { memcpy(newdata, data_, len_); } @@ -89,7 +89,7 @@ class chunk { len_ += data.size(); } - uint8_t *data_; + uint8_t* data_; size_t len_; size_t offset_; size_t cap_; diff --git a/cpp_src/estl/chunk_buf.h b/cpp_src/estl/chunk_buf.h index daed5c466..83c80de4d 100644 --- a/cpp_src/estl/chunk_buf.h +++ b/cpp_src/estl/chunk_buf.h @@ -15,7 +15,7 @@ template class chain_buf { public: chain_buf(size_t cap) : ring_(cap) {} - void write(chunk &&ch) { + void write(chunk&& ch) { if (ch.size()) { std::lock_guard lck(mtx_); const auto new_head = (head_ + 1) % ring_.size(); @@ -43,17 +43,18 @@ class chain_buf { data_size_ -= nread; while (nread) { assertrx(head_ != tail_); - chunk &cur = ring_[tail_]; + chunk& cur = ring_[tail_]; if (cur.size() > nread) { cur.shift(nread); break; } nread -= cur.size(); cur.clear(); - if (free_.size() < ring_.size() && cur.capacity() < 0x10000) + if (free_.size() < ring_.size() && cur.capacity() < 0x10000) { free_.push_back(std::move(cur)); - else + } else { cur = chunk(); + } tail_ = (tail_ + 1) % ring_.size(); } } diff --git a/cpp_src/estl/contexted_locks.h b/cpp_src/estl/contexted_locks.h index e633c95f1..f15d46333 100644 --- a/cpp_src/estl/contexted_locks.h +++ b/cpp_src/estl/contexted_locks.h @@ -40,14 +40,18 @@ class [[nodiscard]] contexted_unique_lock { lck._M_context = nullptr; } ~contexted_unique_lock() { - if (_M_owns) _M_mtx->unlock(); + if (_M_owns) { + _M_mtx->unlock(); + } } contexted_unique_lock(const contexted_unique_lock&) = delete; contexted_unique_lock& operator=(const contexted_unique_lock&) = delete; contexted_unique_lock& operator=(contexted_unique_lock&& lck) noexcept { if (this != &lck) { - if (_M_owns) unlock(); + if (_M_owns) { + unlock(); + } _M_mtx = lck._M_mtx; _M_owns = lck._M_owns; _M_context = lck._M_context; @@ -98,8 +102,12 @@ class [[nodiscard]] contexted_unique_lock { private: void _M_lockable() const noexcept { - if (_M_mtx == nullptr) assertrx(0); - if (_M_owns) assertrx(0); + if (_M_mtx == nullptr) { + assertrx(0); + } + if (_M_owns) { + assertrx(0); + } } MutexType* _M_mtx; @@ -130,14 +138,18 @@ class [[nodiscard]] contexted_shared_lock { lck._M_context = nullptr; } ~contexted_shared_lock() { - if (_M_owns) _M_mtx->unlock_shared(); + if (_M_owns) { + _M_mtx->unlock_shared(); + } } contexted_shared_lock(const contexted_shared_lock&) = delete; contexted_shared_lock& operator=(const contexted_shared_lock&) = delete; contexted_shared_lock& operator=(contexted_shared_lock&& lck) noexcept { if (this != &lck) { - if (_M_owns) unlock(); + if (_M_owns) { + unlock(); + } _M_mtx = lck._M_mtx; _M_owns = lck._M_owns; _M_context = lck._M_context; @@ -170,7 +182,9 @@ class [[nodiscard]] contexted_shared_lock { } void unlock() { - if (!_M_owns) assertrx(0); + if (!_M_owns) { + assertrx(0); + } _M_mtx->unlock_shared(); _M_owns = false; } @@ -188,8 +202,12 @@ class [[nodiscard]] contexted_shared_lock { private: void _M_lockable() const noexcept { - if (_M_mtx == nullptr) assertrx(0); - if (_M_owns) assertrx(0); + if (_M_mtx == nullptr) { + assertrx(0); + } + if (_M_owns) { + assertrx(0); + } } MutexType* _M_mtx; diff --git a/cpp_src/estl/cow.h b/cpp_src/estl/cow.h index b29eab677..8d545dfef 100644 --- a/cpp_src/estl/cow.h +++ b/cpp_src/estl/cow.h @@ -10,24 +10,26 @@ namespace reindexer { template class shared_cow_ptr { public: - explicit shared_cow_ptr(intrusive_ptr> &&ptr) noexcept : payload_(std::move(ptr)) {} + explicit shared_cow_ptr(intrusive_ptr>&& ptr) noexcept : payload_(std::move(ptr)) {} shared_cow_ptr() noexcept = default; ~shared_cow_ptr() = default; - const T *operator->() const noexcept { return payload_.get(); } + const T* operator->() const noexcept { return payload_.get(); } - const T *get() const noexcept { return payload_.get(); } - T *clone() { + const T* get() const noexcept { return payload_.get(); } + T* clone() { copy_if_not_owner(); return payload_.get(); } operator bool() const noexcept { return bool(payload_); } - const T &operator*() const noexcept { return *payload_; } + const T& operator*() const noexcept { return *payload_; } private: // If we are not the owner of the payload object, make a private copy of it void copy_if_not_owner() { - if (!payload_.unique()) payload_ = make_intrusive>(*payload_); + if (!payload_.unique()) { + payload_ = make_intrusive>(*payload_); + } } private: diff --git a/cpp_src/estl/fast_hash_traits.h b/cpp_src/estl/fast_hash_traits.h index 2cf5332f5..d2d9da975 100644 --- a/cpp_src/estl/fast_hash_traits.h +++ b/cpp_src/estl/fast_hash_traits.h @@ -1,28 +1,28 @@ #pragma once -#include #include +#include namespace reindexer { template struct is_recommends_sc_hash_map { - constexpr static bool value = false; + constexpr static bool value = false; }; template <> struct is_recommends_sc_hash_map { - constexpr static bool value = true; + constexpr static bool value = true; }; template inline constexpr bool is_recommends_sc_hash_map_v = is_recommends_sc_hash_map::value; template struct is_using_sc_version { - constexpr static bool value = is_recommends_sc_hash_map_v || - (std::is_trivially_copy_assignable_v && std::is_trivially_copy_constructible_v) || - !std::is_nothrow_move_assignable_v || !std::is_nothrow_move_constructible_v; + constexpr static bool value = is_recommends_sc_hash_map_v || + (std::is_trivially_copy_assignable_v && std::is_trivially_copy_constructible_v) || + !std::is_nothrow_move_assignable_v || !std::is_nothrow_move_constructible_v; }; template inline constexpr bool is_using_sc_version_v = is_using_sc_version::value; -} +} // namespace reindexer diff --git a/cpp_src/estl/flat_str_map.h b/cpp_src/estl/flat_str_map.h index 8824add5a..942488fdc 100644 --- a/cpp_src/estl/flat_str_map.h +++ b/cpp_src/estl/flat_str_map.h @@ -17,15 +17,15 @@ class flat_str_map { class holder_t : public base_holder_t { public: string_view_t get(size_t pos) const { - auto ptr = reinterpret_cast(base_holder_t::data() + pos); + auto ptr = reinterpret_cast(base_holder_t::data() + pos); auto l = scan_varint(10, ptr); size_t len = parse_uint32(l, ptr); - return std::string_view(reinterpret_cast(ptr + l), len); + return std::string_view(reinterpret_cast(ptr + l), len); } size_t put(string_view_t str) { size_t pos = base_holder_t::size(); base_holder_t::resize(str.size() + 8 + pos); - size_t l = string_pack(str.data(), str.size(), reinterpret_cast(base_holder_t::data()) + pos); + size_t l = string_pack(str.data(), str.size(), reinterpret_cast(base_holder_t::data()) + pos); base_holder_t::resize(pos + l); return pos; } @@ -33,23 +33,23 @@ class flat_str_map { struct equal_flat_str_map { using is_transparent = void; - equal_flat_str_map(const holder_t *buf) noexcept : buf_(buf) {} + equal_flat_str_map(const holder_t* buf) noexcept : buf_(buf) {} bool operator()(size_t lhs, size_t rhs) const { return buf_->get(lhs) == buf_->get(rhs); } bool operator()(string_view_t lhs, size_t rhs) const { return lhs == buf_->get(rhs); } bool operator()(size_t lhs, string_view_t rhs) const { return rhs == buf_->get(lhs); } private: - const holder_t *buf_; + const holder_t* buf_; }; struct hash_flat_str_map { using is_transparent = void; - hash_flat_str_map(const holder_t *buf) noexcept : buf_(buf) {} + hash_flat_str_map(const holder_t* buf) noexcept : buf_(buf) {} size_t operator()(string_view_t hs) const noexcept { return _Hash_bytes(hs.data(), hs.length()); } size_t operator()(size_t hs) const { return operator()(buf_->get(hs)); } private: - const holder_t *buf_; + const holder_t* buf_; }; using hash_map = tsl::hopscotch_map>, 30, false, @@ -59,17 +59,17 @@ class flat_str_map { flat_str_map() : holder_(std::make_unique()), map_(std::make_unique(16, hash_flat_str_map(holder_.get()), equal_flat_str_map(holder_.get()))) {} - flat_str_map(const flat_str_map &other) = delete; - flat_str_map &operator=(const flat_str_map &other) = delete; - flat_str_map(flat_str_map &&rhs) noexcept = default; - flat_str_map &operator=(flat_str_map &&rhs) noexcept = default; + flat_str_map(const flat_str_map& other) = delete; + flat_str_map& operator=(const flat_str_map& other) = delete; + flat_str_map(flat_str_map&& rhs) noexcept = default; + flat_str_map& operator=(flat_str_map&& rhs) noexcept = default; template class value_type : public std::pair { public: value_type(string_view_t k, VV v) : std::pair(k, v) {} - const value_type *operator->() const { return this; } - value_type *operator->() { return this; } + const value_type* operator->() const { return this; } + value_type* operator->() { return this; } }; template @@ -77,12 +77,12 @@ class flat_str_map { friend class flat_str_map; public: - base_iterator(map_iterator it, map_type *m, int multi_idx) noexcept : it_(it), m_(m), multi_idx_(multi_idx) {} - base_iterator(map_iterator it, map_type *m) noexcept + base_iterator(map_iterator it, map_type* m, int multi_idx) noexcept : it_(it), m_(m), multi_idx_(multi_idx) {} + base_iterator(map_iterator it, map_type* m) noexcept : it_(it), m_(m), multi_idx_((Multi && it_ != m_->map_->end() && it_->second.IsMultiValue()) ? it_->second.GetWordID() : -1) {} - base_iterator(const base_iterator &other) : it_(other.it_), m_(other.m_), multi_idx_(other.multi_idx_) {} + base_iterator(const base_iterator& other) : it_(other.it_), m_(other.m_), multi_idx_(other.multi_idx_) {} // NOLINTNEXTLINE(bugprone-unhandled-self-assignment) - base_iterator &operator=(const base_iterator &other) noexcept { + base_iterator& operator=(const base_iterator& other) noexcept { it_ = other.it_; m_ = other.m_; multi_idx_ = other.multi_idx_; @@ -109,11 +109,13 @@ class flat_str_map { return value_type(m_->holder_->get(it_->first), it_->second); } - base_iterator &operator++() noexcept { + base_iterator& operator++() noexcept { if constexpr (Multi) { if (multi_idx_ != -1) { multi_idx_ = m_->multi_[multi_idx_].next; - if (multi_idx_ != -1) return *this; + if (multi_idx_ != -1) { + return *this; + } } } ++it_; @@ -124,7 +126,7 @@ class flat_str_map { } return *this; } - base_iterator &operator--() noexcept { + base_iterator& operator--() noexcept { static_assert(Multi, "Sorry, flat_std_multimap::iterator::operator-- () is not implemented"); --it_; return *this; @@ -140,22 +142,22 @@ class flat_str_map { return ret; } template - bool operator!=(const it2 &rhs) const noexcept { + bool operator!=(const it2& rhs) const noexcept { return it_ != rhs.it_ || multi_idx_ != rhs.multi_idx_; } template - bool operator==(const it2 &rhs) const noexcept { + bool operator==(const it2& rhs) const noexcept { return it_ == rhs.it_ && multi_idx_ == rhs.multi_idx_; } protected: map_iterator it_; - map_type *m_; + map_type* m_; int multi_idx_; }; - using iterator = base_iterator>; - using const_iterator = base_iterator>; + using iterator = base_iterator>; + using const_iterator = base_iterator>; iterator begin() noexcept { return iterator(map_->begin(), this); } iterator end() noexcept { return iterator(map_->end(), this); } @@ -168,18 +170,22 @@ class flat_str_map { std::pair equal_range(string_view_t str) noexcept { auto it = map_->find(str); auto it2 = it; - if (it2 != map_->end()) ++it2; + if (it2 != map_->end()) { + ++it2; + } return {iterator(it, this), iterator(it2, this)}; } std::pair equal_range(string_view_t str) const noexcept { auto it = map_->find(str); auto it2 = it; - if (it2 != map_->end()) ++it2; + if (it2 != map_->end()) { + ++it2; + } return {const_iterator(it, this), const_iterator(it2, this)}; } - std::pair insert(string_view_t str, const V &v) { + std::pair insert(string_view_t str, const V& v) { size_t pos = holder_->put(str); const auto h = hash_flat_str_map(holder_.get())(str); auto res = map_->try_emplace_prehashed(h, pos, v); @@ -209,7 +215,7 @@ class flat_str_map { } } - std::pair emplace(string_view_t str, const V &v) { return insert(str, v); } + std::pair emplace(string_view_t str, const V& v) { return insert(str, v); } void reserve(size_t map_sz, size_t str_sz) { map_->reserve(map_sz); @@ -237,8 +243,8 @@ class flat_str_map { // Underlying map container std::unique_ptr map_; struct multi_node { - multi_node(const V &v, int n) : val(v), next(n) {} - multi_node(V &&v, int n) noexcept : val(std::move(v)), next(n) {} + multi_node(const V& v, int n) : val(v), next(n) {} + multi_node(V&& v, int n) noexcept : val(std::move(v)), next(n) {} V val; int next; diff --git a/cpp_src/estl/h_vector.h b/cpp_src/estl/h_vector.h index 8bf47715a..90d10a04f 100644 --- a/cpp_src/estl/h_vector.h +++ b/cpp_src/estl/h_vector.h @@ -69,7 +69,7 @@ class h_vector { } size_ = other.size_; } - h_vector(h_vector&& other) noexcept : size_(0), is_hdata_(1) { + h_vector(h_vector&& other) noexcept : e_{0, 0}, size_(0), is_hdata_(1) { if (other.is_hdata()) { const pointer p = reinterpret_cast(hdata_); const pointer op = reinterpret_cast(other.hdata_); @@ -104,7 +104,9 @@ class h_vector { } if constexpr (!std::is_trivially_destructible_v) { const auto old_sz = size(); - for (; i < old_sz; i++) p[i].~T(); + for (; i < old_sz; i++) { + p[i].~T(); + } } size_ = other.size_; } @@ -139,9 +141,13 @@ class h_vector { bool operator==(const h_vector& other) const noexcept(noexcept(std::declval() == std::declval())) { if (&other != this) { const size_type sz = size_; - if (sz != other.size()) return false; + if (sz != other.size()) { + return false; + } for (size_t i = 0; i < sz; ++i) { - if (!(operator[](i) == other[i])) return false; + if (!(operator[](i) == other[i])) { + return false; + } } return true; } @@ -161,7 +167,9 @@ class h_vector { } else if constexpr (!std::is_trivially_destructible_v) { const pointer p = ptr(); const size_type sz = size_; - for (size_type i = 0; i < sz; ++i) p[i].~T(); + for (size_type i = 0; i < sz; ++i) { + p[i].~T(); + } } size_ = 0; } @@ -223,12 +231,16 @@ class h_vector { if constexpr (!reindexer::is_trivially_default_constructible::value) { const pointer p = ptr(); const size_type old_sz = size_; - for (size_type i = old_sz; i < sz; ++i) new (p + i) T(); + for (size_type i = old_sz; i < sz; ++i) { + new (p + i) T(); + } } if constexpr (!std::is_trivially_destructible_v) { const pointer p = ptr(); const size_type old_sz = size_; - for (size_type i = sz; i < old_sz; ++i) p[i].~T(); + for (size_type i = sz; i < old_sz; ++i) { + p[i].~T(); + } } size_ = sz; } @@ -267,7 +279,9 @@ class h_vector { } ++old_data; } - if (!is_hdata()) operator delete(oold_data); + if (!is_hdata()) { + operator delete(oold_data); + } e_.data_ = new_data; e_.cap_ = sz; is_hdata_ = 0; @@ -342,7 +356,9 @@ class h_vector { return begin() + i; } iterator insert(const_iterator pos, difference_type count, const T& v) { - if (count == 0) return const_cast(pos); + if (count == 0) { + return const_cast(pos); + } difference_type i = pos - begin(); rx_debug_check_subscript_le(i); const int64_t sz = size_; @@ -400,7 +416,9 @@ class h_vector { iterator insert(const_iterator pos, InputIt first, InputIt last) { rx_debug_check_valid_range(first, last); const difference_type cnt = last - first; - if (cnt == 0) return const_cast(pos); + if (cnt == 0) { + return const_cast(pos); + } const difference_type i = pos - begin(); rx_debug_check_subscript_le(i); const int64_t sz = size_; @@ -455,14 +473,18 @@ class h_vector { std::move(std::make_move_iterator(firstPtr + cnt), std::make_move_iterator(p + sz), firstPtr); const auto newSize = sz - cnt; if constexpr (!std::is_trivially_destructible_v) { - for (size_type j = newSize; j < sz; ++j) p[j].~T(); + for (size_type j = newSize; j < sz; ++j) { + p[j].~T(); + } } size_ = newSize; return firstPtr; } void shrink_to_fit() { const auto sz = size(); - if (is_hdata() || sz == capacity()) return; + if (is_hdata() || sz == capacity()) { + return; + } h_vector tmp; tmp.reserve(sz); @@ -480,12 +502,16 @@ class h_vector { if (is_hdata()) { if constexpr (!std::is_trivially_destructible_v) { const size_type sz = size_; - for (size_type i = 0; i < sz; ++i) reinterpret_cast(hdata_)[i].~T(); + for (size_type i = 0; i < sz; ++i) { + reinterpret_cast(hdata_)[i].~T(); + } } } else { if constexpr (!std::is_trivially_destructible_v) { const size_type sz = size_; - for (size_type i = 0; i < sz; ++i) e_.data_[i].~T(); + for (size_type i = 0; i < sz; ++i) { + e_.data_[i].~T(); + } } operator delete(e_.data_); } @@ -511,7 +537,9 @@ template inline static std::ostream& operator<<(std::ostream& o, const reindexer::h_vector& vec) { o << "["; for (unsigned i = 0; i < vec.size(); i++) { - if (i != 0) o << ","; + if (i != 0) { + o << ","; + } o << vec[i] << " "; } o << "]"; diff --git a/cpp_src/estl/intrusive_ptr.h b/cpp_src/estl/intrusive_ptr.h index 7aaca5230..6c5a0bb38 100644 --- a/cpp_src/estl/intrusive_ptr.h +++ b/cpp_src/estl/intrusive_ptr.h @@ -17,49 +17,57 @@ class intrusive_ptr { constexpr intrusive_ptr() noexcept = default; constexpr intrusive_ptr(std::nullptr_t) noexcept {} - intrusive_ptr(T *p, bool add_ref = true) noexcept : px(p) { - if (px != 0 && add_ref) intrusive_ptr_add_ref(px); + intrusive_ptr(T* p, bool add_ref = true) noexcept : px(p) { + if (px != 0 && add_ref) { + intrusive_ptr_add_ref(px); + } } template - intrusive_ptr(intrusive_ptr const &rhs) noexcept : px(rhs.get()) { - if (px != 0) intrusive_ptr_add_ref(px); + intrusive_ptr(const intrusive_ptr& rhs) noexcept : px(rhs.get()) { + if (px != 0) { + intrusive_ptr_add_ref(px); + } } - intrusive_ptr(intrusive_ptr const &rhs) noexcept : px(rhs.px) { - if (px != 0) intrusive_ptr_add_ref(px); + intrusive_ptr(const intrusive_ptr& rhs) noexcept : px(rhs.px) { + if (px != 0) { + intrusive_ptr_add_ref(px); + } } ~intrusive_ptr() { - if (px != 0) intrusive_ptr_release(px); + if (px != 0) { + intrusive_ptr_release(px); + } } template - intrusive_ptr &operator=(intrusive_ptr const &rhs) noexcept { + intrusive_ptr& operator=(const intrusive_ptr& rhs) noexcept { this_type(rhs).swap(*this); return *this; } - intrusive_ptr(intrusive_ptr &&rhs) noexcept : px(rhs.px) { rhs.px = 0; } + intrusive_ptr(intrusive_ptr&& rhs) noexcept : px(rhs.px) { rhs.px = 0; } - intrusive_ptr &operator=(intrusive_ptr &&rhs) noexcept { - this_type(static_cast(rhs)).swap(*this); + intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept { + this_type(static_cast(rhs)).swap(*this); return *this; } // NOLINTNEXTLINE(bugprone-unhandled-self-assignment) - intrusive_ptr &operator=(intrusive_ptr const &rhs) noexcept { + intrusive_ptr& operator=(const intrusive_ptr& rhs) noexcept { this_type(rhs).swap(*this); return *this; } - intrusive_ptr &operator=(T *rhs) noexcept { + intrusive_ptr& operator=(T* rhs) noexcept { this_type(rhs).swap(*this); return *this; } void reset() noexcept { this_type().swap(*this); } - void reset(T *rhs) noexcept { this_type(rhs).swap(*this); } + void reset(T* rhs) noexcept { this_type(rhs).swap(*this); } bool unique() const noexcept { if (px == 0) { return true; @@ -67,111 +75,111 @@ class intrusive_ptr { return intrusive_ptr_is_unique(px); } - T *get() const noexcept { return px; } + T* get() const noexcept { return px; } - T &operator*() const noexcept { + T& operator*() const noexcept { assertrx(px != 0); return *px; } - T *operator->() const noexcept { + T* operator->() const noexcept { assertrx(px != 0); return px; } - typedef T *this_type::*unspecified_bool_type; + typedef T* this_type::*unspecified_bool_type; operator unspecified_bool_type() const noexcept { return px == 0 ? 0 : &this_type::px; } - void swap(intrusive_ptr &rhs) noexcept { - T *tmp = px; + void swap(intrusive_ptr& rhs) noexcept { + T* tmp = px; px = rhs.px; rhs.px = tmp; } private: - T *px{nullptr}; + T* px{nullptr}; }; template -inline bool operator==(intrusive_ptr const &a, intrusive_ptr const &b) noexcept { +inline bool operator==(const intrusive_ptr& a, const intrusive_ptr& b) noexcept { return a.get() == b.get(); } template -inline bool operator!=(intrusive_ptr const &a, intrusive_ptr const &b) noexcept { +inline bool operator!=(const intrusive_ptr& a, const intrusive_ptr& b) noexcept { return a.get() != b.get(); } template -inline bool operator==(intrusive_ptr const &a, U *b) noexcept { +inline bool operator==(const intrusive_ptr& a, U* b) noexcept { return a.get() == b; } template -inline bool operator!=(intrusive_ptr const &a, U *b) noexcept { +inline bool operator!=(const intrusive_ptr& a, U* b) noexcept { return a.get() != b; } template -inline bool operator==(T *a, intrusive_ptr const &b) noexcept { +inline bool operator==(T* a, const intrusive_ptr& b) noexcept { return a == b.get(); } template -inline bool operator!=(T *a, intrusive_ptr const &b) noexcept { +inline bool operator!=(T* a, const intrusive_ptr& b) noexcept { return a != b.get(); } template -inline bool operator<(intrusive_ptr const &a, intrusive_ptr const &b) noexcept { - return std::less()(a.get(), b.get()); +inline bool operator<(const intrusive_ptr& a, const intrusive_ptr& b) noexcept { + return std::less()(a.get(), b.get()); } template -void swap(intrusive_ptr &lhs, intrusive_ptr &rhs) noexcept { +void swap(intrusive_ptr& lhs, intrusive_ptr& rhs) noexcept { lhs.swap(rhs); } template -T *get_pointer(intrusive_ptr const &p) noexcept { +T* get_pointer(const intrusive_ptr& p) noexcept { return p.get(); } template -intrusive_ptr static_pointer_cast(intrusive_ptr const &p) noexcept { - return static_cast(p.get()); +intrusive_ptr static_pointer_cast(const intrusive_ptr& p) noexcept { + return static_cast(p.get()); } template -intrusive_ptr const_pointer_cast(intrusive_ptr const &p) noexcept { - return const_cast(p.get()); +intrusive_ptr const_pointer_cast(const intrusive_ptr& p) noexcept { + return const_cast(p.get()); } template -intrusive_ptr dynamic_pointer_cast(intrusive_ptr const &p) noexcept { - return dynamic_cast(p.get()); +intrusive_ptr dynamic_pointer_cast(const intrusive_ptr& p) noexcept { + return dynamic_cast(p.get()); } template class intrusive_atomic_rc_wrapper; template -inline void intrusive_ptr_add_ref(intrusive_atomic_rc_wrapper *x) noexcept { +inline void intrusive_ptr_add_ref(intrusive_atomic_rc_wrapper* x) noexcept { if (x) { x->refcount.fetch_add(1, std::memory_order_relaxed); } } template -inline void intrusive_ptr_release(intrusive_atomic_rc_wrapper *x) noexcept { +inline void intrusive_ptr_release(intrusive_atomic_rc_wrapper* x) noexcept { if (x && x->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete x; } } template -inline bool intrusive_ptr_is_unique(intrusive_atomic_rc_wrapper *x) noexcept { +inline bool intrusive_ptr_is_unique(intrusive_atomic_rc_wrapper* x) noexcept { // std::memory_order_acquire - is essential for COW constructions based on intrusive_ptr return !x || (x->refcount.load(std::memory_order_acquire) == 1); } @@ -180,36 +188,36 @@ template class intrusive_atomic_rc_wrapper : public T { public: template - intrusive_atomic_rc_wrapper(Args &&...args) : T(std::forward(args)...), refcount(0) {} - intrusive_atomic_rc_wrapper &operator=(const intrusive_atomic_rc_wrapper &) = delete; + intrusive_atomic_rc_wrapper(Args&&... args) : T(std::forward(args)...), refcount(0) {} + intrusive_atomic_rc_wrapper& operator=(const intrusive_atomic_rc_wrapper&) = delete; protected: std::atomic refcount; - friend void intrusive_ptr_add_ref<>(intrusive_atomic_rc_wrapper *x) noexcept; - friend void intrusive_ptr_release<>(intrusive_atomic_rc_wrapper *x) noexcept; - friend bool intrusive_ptr_is_unique<>(intrusive_atomic_rc_wrapper *x) noexcept; + friend void intrusive_ptr_add_ref<>(intrusive_atomic_rc_wrapper* x) noexcept; + friend void intrusive_ptr_release<>(intrusive_atomic_rc_wrapper* x) noexcept; + friend bool intrusive_ptr_is_unique<>(intrusive_atomic_rc_wrapper* x) noexcept; }; template class intrusive_rc_wrapper; template -inline void intrusive_ptr_add_ref(intrusive_rc_wrapper *x) noexcept { +inline void intrusive_ptr_add_ref(intrusive_rc_wrapper* x) noexcept { if (x) { ++x->refcount; } } template -inline void intrusive_ptr_release(intrusive_rc_wrapper *x) noexcept { +inline void intrusive_ptr_release(intrusive_rc_wrapper* x) noexcept { if (x && --x->refcount == 0) { delete x; } } template -inline bool intrusive_ptr_is_unique(intrusive_rc_wrapper *x) noexcept { +inline bool intrusive_ptr_is_unique(intrusive_rc_wrapper* x) noexcept { return !x || (x->refcount == 1); } @@ -217,50 +225,50 @@ template class intrusive_rc_wrapper : public T { public: template - intrusive_rc_wrapper(Args &&...args) : T(std::forward(args)...), refcount(0) {} - intrusive_rc_wrapper &operator=(const intrusive_rc_wrapper &) = delete; + intrusive_rc_wrapper(Args&&... args) : T(std::forward(args)...), refcount(0) {} + intrusive_rc_wrapper& operator=(const intrusive_rc_wrapper&) = delete; protected: int refcount; - friend void intrusive_ptr_add_ref<>(intrusive_rc_wrapper *x) noexcept; - friend void intrusive_ptr_release<>(intrusive_rc_wrapper *x) noexcept; - friend bool intrusive_ptr_is_unique<>(intrusive_rc_wrapper *x) noexcept; + friend void intrusive_ptr_add_ref<>(intrusive_rc_wrapper* x) noexcept; + friend void intrusive_ptr_release<>(intrusive_rc_wrapper* x) noexcept; + friend bool intrusive_ptr_is_unique<>(intrusive_rc_wrapper* x) noexcept; }; class intrusive_atomic_rc_base { public: intrusive_atomic_rc_base() noexcept : refcount(0) {} - intrusive_atomic_rc_base &operator=(const intrusive_atomic_rc_base &) = delete; + intrusive_atomic_rc_base& operator=(const intrusive_atomic_rc_base&) = delete; virtual ~intrusive_atomic_rc_base() = default; protected: std::atomic refcount; - friend void intrusive_ptr_add_ref(intrusive_atomic_rc_base *x) noexcept; - friend void intrusive_ptr_release(intrusive_atomic_rc_base *x) noexcept; - friend bool intrusive_ptr_is_unique(intrusive_atomic_rc_base *x) noexcept; + friend void intrusive_ptr_add_ref(intrusive_atomic_rc_base* x) noexcept; + friend void intrusive_ptr_release(intrusive_atomic_rc_base* x) noexcept; + friend bool intrusive_ptr_is_unique(intrusive_atomic_rc_base* x) noexcept; }; -inline void intrusive_ptr_add_ref(intrusive_atomic_rc_base *x) noexcept { +inline void intrusive_ptr_add_ref(intrusive_atomic_rc_base* x) noexcept { if (x) { x->refcount.fetch_add(1, std::memory_order_relaxed); } } -inline void intrusive_ptr_release(intrusive_atomic_rc_base *x) noexcept { +inline void intrusive_ptr_release(intrusive_atomic_rc_base* x) noexcept { if (x && x->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) { delete x; } } -inline bool intrusive_ptr_is_unique(intrusive_atomic_rc_base *x) noexcept { +inline bool intrusive_ptr_is_unique(intrusive_atomic_rc_base* x) noexcept { // std::memory_order_acquire - is essential for COW constructions based on intrusive_ptr return !x || (x->refcount.load(std::memory_order_acquire) == 1); } template -intrusive_ptr make_intrusive(Args &&...args) { +intrusive_ptr make_intrusive(Args&&... args) { return intrusive_ptr(new T(std::forward(args)...)); } @@ -271,13 +279,13 @@ namespace std { template struct hash> { public: - size_t operator()(const reindexer::intrusive_atomic_rc_wrapper &obj) const { return hash()(obj); } + size_t operator()(const reindexer::intrusive_atomic_rc_wrapper& obj) const { return hash()(obj); } }; template struct hash> { public: - size_t operator()(const reindexer::intrusive_ptr &obj) const { return hash()(*obj); } + size_t operator()(const reindexer::intrusive_ptr& obj) const { return hash()(*obj); } }; } // namespace std diff --git a/cpp_src/estl/multihash_set.h b/cpp_src/estl/multihash_set.h index 047ee53de..50c2d2f97 100644 --- a/cpp_src/estl/multihash_set.h +++ b/cpp_src/estl/multihash_set.h @@ -79,7 +79,9 @@ class MultiHashSetImpl { } } for (size_t i = 0; i < N; ++i) { - if (i == firstIdx) continue; + if (i == firstIdx) { + continue; + } size_t hash; try { hash = H::hash(i, k) % capacity_; diff --git a/cpp_src/estl/mutex.h b/cpp_src/estl/mutex.h index 616f267d3..decea44e9 100644 --- a/cpp_src/estl/mutex.h +++ b/cpp_src/estl/mutex.h @@ -51,8 +51,11 @@ class spinlock { ~spinlock() = default; void lock() { - for (unsigned int i = 1; !try_lock(); ++i) - if ((i & 0xff) == 0) std::this_thread::yield(); + for (unsigned int i = 1; !try_lock(); ++i) { + if ((i & 0xff) == 0) { + std::this_thread::yield(); + } + } } bool try_lock() { return !_M_lock.test_and_set(std::memory_order_acq_rel); } void unlock() { _M_lock.clear(std::memory_order_release); } diff --git a/cpp_src/estl/packed_vector.h b/cpp_src/estl/packed_vector.h index 4bbacb266..fb0f410a6 100644 --- a/cpp_src/estl/packed_vector.h +++ b/cpp_src/estl/packed_vector.h @@ -60,7 +60,9 @@ class packed_vector { } void erase_back(size_type pos) { - for (auto it = iterator(this, data_.begin() + pos); it != end(); ++it) size_--; + for (auto it = iterator(this, data_.begin() + pos); it != end(); ++it) { + size_--; + } data_.resize(pos); } @@ -76,7 +78,9 @@ class packed_vector { for (auto it = from; it != to; it++, i++) { if (!(i % 100)) { size_type sz = 0, j = 0; - for (auto iit = it; j < 100 && iit != to; iit++, j++) sz += iit->maxpackedsize(); + for (auto iit = it; j < 100 && iit != to; iit++, j++) { + sz += iit->maxpackedsize(); + } data_.resize(p + sz); } p += it->pack(&*(data_.begin() + p)); diff --git a/cpp_src/estl/protobufparser.h b/cpp_src/estl/protobufparser.h index d66ed3382..ac1c231af 100644 --- a/cpp_src/estl/protobufparser.h +++ b/cpp_src/estl/protobufparser.h @@ -24,7 +24,9 @@ struct ProtobufValue { throw reindexer::Error(errParseMsgPack, "Impossible to convert type [%s] to number", value.Type().Name()); }); - if (v < minv || v > maxv) throw reindexer::Error(errParams, "Value is out of bounds: [%d,%d]", minv, maxv); + if (v < minv || v > maxv) { + throw reindexer::Error(errParams, "Value is out of bounds: [%d,%d]", minv, maxv); + } return v; } diff --git a/cpp_src/estl/shared_mutex.h b/cpp_src/estl/shared_mutex.h index 609f87ba9..79315711c 100644 --- a/cpp_src/estl/shared_mutex.h +++ b/cpp_src/estl/shared_mutex.h @@ -63,7 +63,9 @@ class __shared_mutex_pthread { bool try_lock() noexcept { int __ret = pthread_rwlock_trywrlock(&_M_rwlock); - if (__ret == EBUSY) return false; + if (__ret == EBUSY) { + return false; + } assertrx(__ret == 0); return true; } @@ -76,14 +78,17 @@ class __shared_mutex_pthread { void lock_shared() noexcept { int __ret; - do __ret = pthread_rwlock_rdlock(&_M_rwlock); - while (__ret == EAGAIN || __ret == EBUSY); + do { + __ret = pthread_rwlock_rdlock(&_M_rwlock); + } while (__ret == EAGAIN || __ret == EBUSY); assertrx(__ret == 0); } bool try_lock_shared() noexcept { int __ret = pthread_rwlock_tryrdlock(&_M_rwlock); - if (__ret == EBUSY || __ret == EAGAIN) return false; + if (__ret == EBUSY || __ret == EAGAIN) { + return false; + } assertrx(__ret == 0); return true; } @@ -103,11 +108,13 @@ class shared_lock { explicit shared_lock(mutex_type& __m) noexcept : _M_pm(&__m), _M_owns(true) { __m.lock_shared(); } ~shared_lock() { - if (_M_owns) _M_pm->unlock_shared(); + if (_M_owns) { + _M_pm->unlock_shared(); + } } - shared_lock(shared_lock const&) = delete; - shared_lock& operator=(shared_lock const&) = delete; + shared_lock(const shared_lock&) = delete; + shared_lock& operator=(const shared_lock&) = delete; shared_lock(shared_lock&& __sl) noexcept : shared_lock() { swap(__sl); } diff --git a/cpp_src/estl/smart_lock.h b/cpp_src/estl/smart_lock.h index 5d9ff02a3..c781e2705 100644 --- a/cpp_src/estl/smart_lock.h +++ b/cpp_src/estl/smart_lock.h @@ -12,10 +12,11 @@ class smart_lock { smart_lock() noexcept : mtx_(nullptr), unique_(false), locked_(false) {} smart_lock(Mutex& mtx, bool unique = false) : mtx_(&mtx), unique_(unique), locked_(true) { - if (unique_) + if (unique_) { mtx_->lock(); - else + } else { mtx_->lock_shared(); + } } template smart_lock(Mutex& mtx, Context& context, bool unique = false, milliseconds chkTimeout = kDefaultCondChkTime) diff --git a/cpp_src/estl/span.h b/cpp_src/estl/span.h index 3896d3aed..b95a9fdad 100644 --- a/cpp_src/estl/span.h +++ b/cpp_src/estl/span.h @@ -86,9 +86,13 @@ class span { } bool operator==(const span& other) const noexcept { if (&other != this) { - if (size() != other.size()) return false; + if (size() != other.size()) { + return false; + } for (size_t i = 0; i < size(); ++i) { - if (!(at(i) == other.at(i))) return false; + if (!(at(i) == other.at(i))) { + return false; + } } return true; } diff --git a/cpp_src/estl/suffix_map.h b/cpp_src/estl/suffix_map.h index 57b46c276..d303b6b4e 100644 --- a/cpp_src/estl/suffix_map.h +++ b/cpp_src/estl/suffix_map.h @@ -11,40 +11,40 @@ class suffix_map { typedef size_t size_type; typedef unsigned char char_type; - class value_type : public std::pair { + class value_type : public std::pair { public: - value_type(std::pair &&v) noexcept : std::pair(std::move(v)) {} - value_type(const std::pair &v) : std::pair(v) {} - const value_type *operator->() const noexcept { return this; } + value_type(std::pair&& v) noexcept : std::pair(std::move(v)) {} + value_type(const std::pair& v) : std::pair(v) {} + const value_type* operator->() const noexcept { return this; } }; class iterator { friend class suffix_map; public: - iterator(size_type idx, const suffix_map *m) noexcept : idx_(idx), m_(m) {} - iterator(const iterator &other) noexcept : idx_(other.idx_), m_(other.m_) {} + iterator(size_type idx, const suffix_map* m) noexcept : idx_(idx), m_(m) {} + iterator(const iterator& other) noexcept : idx_(other.idx_), m_(other.m_) {} // NOLINTNEXTLINE(bugprone-unhandled-self-assignment) - iterator &operator=(const iterator &other) noexcept { + iterator& operator=(const iterator& other) noexcept { idx_ = other.idx; m_ = other.m_; return *this; } value_type operator->() { - auto *p = &m_->text_[m_->sa_[idx_]]; + auto* p = &m_->text_[m_->sa_[idx_]]; return value_type(std::make_pair(p, m_->mapped_[m_->sa_[idx_]])); } const value_type operator->() const { - auto *p = &m_->text_[m_->sa_[idx_]]; + auto* p = &m_->text_[m_->sa_[idx_]]; return value_type(std::make_pair(p, m_->mapped_[m_->sa_[idx_]])); } - iterator &operator++() noexcept { + iterator& operator++() noexcept { ++idx_; return *this; } - iterator &operator--() noexcept { + iterator& operator--() noexcept { --idx_; return *this; } @@ -59,28 +59,32 @@ class suffix_map { return ret; } int lcp() noexcept { return m_->lcp_[idx_]; } - bool operator!=(const iterator &rhs) const noexcept { return idx_ != rhs.idx_; } - bool operator==(const iterator &rhs) const noexcept { return idx_ == rhs.idx_; } + bool operator!=(const iterator& rhs) const noexcept { return idx_ != rhs.idx_; } + bool operator==(const iterator& rhs) const noexcept { return idx_ == rhs.idx_; } protected: size_type idx_; - const suffix_map *m_; + const suffix_map* m_; }; public: suffix_map() = default; - suffix_map(const suffix_map & /*other*/) = delete; - suffix_map &operator=(const suffix_map & /*other*/) = default; - suffix_map(suffix_map && /*rhs*/) noexcept = default; + suffix_map(const suffix_map& /*other*/) = delete; + suffix_map& operator=(const suffix_map& /*other*/) = default; + suffix_map(suffix_map&& /*rhs*/) noexcept = default; iterator begin() const noexcept { return iterator(0, this); } iterator end() const noexcept { return iterator(sa_.size(), this); } std::pair match_range(std::string_view str) const { iterator start = lower_bound(str); - if (start == end()) return {end(), end()}; + if (start == end()) { + return {end(), end()}; + } int idx_ = start.idx_ + 1; - while (idx_ < int(sa_.size()) && lcp_[idx_ - 1] >= int(str.length())) idx_++; + while (idx_ < int(sa_.size()) && lcp_[idx_ - 1] >= int(str.length())) { + idx_++; + } return {start, iterator(idx_, this)}; } @@ -91,13 +95,15 @@ class suffix_map { size_type lo = 0, hi = sa_.size(), mid; int lcp_lo = 0, lcp_hi = 0; - auto P = reinterpret_cast(str.data()); - auto T = reinterpret_cast(text_.data()); + auto P = reinterpret_cast(str.data()); + auto T = reinterpret_cast(text_.data()); while (lo <= hi) { mid = (lo + hi) / 2; int i = std::min(lcp_hi, lcp_lo); bool plt = true; - if (mid >= sa_.size()) return end(); + if (mid >= sa_.size()) { + return end(); + } while (i < int(str.length()) && sa_[mid] + i < int(text_.size())) { if (P[i] < T[sa_[mid] + i]) { break; @@ -109,15 +115,18 @@ class suffix_map { } if (plt) { if (mid == lo + 1) { - if (strncmp(str.data(), &text_[sa_[mid]], std::min(str.length(), strlen(&text_[sa_[mid]]))) != 0) return end(); + if (strncmp(str.data(), &text_[sa_[mid]], std::min(str.length(), strlen(&text_[sa_[mid]]))) != 0) { + return end(); + } return iterator(mid, this); } lcp_hi = i; hi = mid; } else { if (mid == hi - 1) { - if (hi >= sa_.size() || strncmp(str.data(), &text_[sa_[hi]], std::min(str.length(), strlen(&text_[sa_[hi]]))) != 0) + if (hi >= sa_.size() || strncmp(str.data(), &text_[sa_[hi]], std::min(str.length(), strlen(&text_[sa_[hi]]))) != 0) { return end(); + } return iterator(hi, this); } lcp_lo = i; @@ -127,8 +136,10 @@ class suffix_map { return end(); } - int insert(std::string_view word, const V &val, int virtual_len = -1) { - if (virtual_len == -1) virtual_len = word.length(); + int insert(std::string_view word, const V& val, int virtual_len = -1) { + if (virtual_len == -1) { + virtual_len = word.length(); + } int wpos = text_.size(); size_t real_len = word.length(); text_.insert(text_.end(), word.begin(), word.end()); @@ -140,16 +151,20 @@ class suffix_map { return wpos; } - const CharT *word_at(int idx) const noexcept { return &text_[words_[idx]]; } + const CharT* word_at(int idx) const noexcept { return &text_[words_[idx]]; } int16_t word_len_at(int idx) const noexcept { return words_len_[idx].first; } int16_t virtual_word_len(int idx) const noexcept { return words_len_[idx].second; } void build() { - if (built_) return; + if (built_) { + return; + } text_.shrink_to_fit(); sa_.resize(text_.size()); - if (!sa_.empty()) ::divsufsort(reinterpret_cast(text_.data()), &sa_[0], text_.size()); + if (!sa_.empty()) { + ::divsufsort(reinterpret_cast(text_.data()), &sa_[0], text_.size()); + } build_lcp(); built_ = true; } @@ -172,7 +187,7 @@ class suffix_map { size_type size() const noexcept { return sa_.size(); } size_type word_size() const noexcept { return words_.size(); } - const std::vector &text() const noexcept { return text_; } + const std::vector& text() const noexcept { return text_; } size_t heap_size() noexcept { return (sa_.capacity() + words_.capacity()) * sizeof(int) + // (lcp_.capacity() + words_len_.capacity()) * sizeof(int16_t) + // @@ -186,7 +201,9 @@ class suffix_map { lcp_.resize(sa_.size()); int k = 0, n = size(); - for (int i = 0; i < n; i++) rank_[sa_[i]] = i; + for (int i = 0; i < n; i++) { + rank_[sa_[i]] = i; + } for (int i = 0; i < n; i++, k ? k-- : 0) { auto r = rank_[i]; if (r == n - 1) { @@ -194,7 +211,9 @@ class suffix_map { continue; } int j = sa_[r + 1]; - while (i + k < n && j + k < n && text_[i + k] == text_[j + k]) k++; + while (i + k < n && j + k < n && text_[i + k] == text_[j + k]) { + k++; + } lcp_[r] = k; } } diff --git a/cpp_src/estl/tokenizer.cc b/cpp_src/estl/tokenizer.cc index bcf8a5ea7..b6946ef58 100644 --- a/cpp_src/estl/tokenizer.cc +++ b/cpp_src/estl/tokenizer.cc @@ -25,7 +25,9 @@ void tokenizer::skip_space() noexcept { token tokenizer::next_token(flags flgs) { skip_space(); - if (cur_ == q_.end()) return token(TokenEnd); + if (cur_ == q_.end()) { + return token(TokenEnd); + } token res(TokenSymbol); @@ -33,7 +35,9 @@ token tokenizer::next_token(flags flgs) { res.type = TokenName; int openBrackets{0}; do { - if (*cur_ == '*' && *(cur_ - 1) != '[') break; + if (*cur_ == '*' && *(cur_ - 1) != '[') { + break; + } res.text_.push_back(flgs.has_to_lower() ? tolower(*cur_++) : *cur_++); ++pos_; } while (cur_ != q_.end() && (isalpha(*cur_) || isdigit(*cur_) || *cur_ == '_' || *cur_ == '#' || *cur_ == '.' || *cur_ == '*' || @@ -94,7 +98,9 @@ token tokenizer::next_token(flags flgs) { auto c = *cur_; if (c == '\\') { ++pos_; - if (++cur_ == q_.end()) break; + if (++cur_ == q_.end()) { + break; + } c = *cur_; switch (c) { case 'n': @@ -163,8 +169,9 @@ std::string tokenizer::where() const { if (*pos == '\n') { line++; col = 0; - } else + } else { col++; + } } return std::string() .append("line: ") diff --git a/cpp_src/estl/tokenizer.h b/cpp_src/estl/tokenizer.h index 4ed8d193c..5382e93d3 100644 --- a/cpp_src/estl/tokenizer.h +++ b/cpp_src/estl/tokenizer.h @@ -11,14 +11,14 @@ enum token_type { TokenEnd, TokenName, TokenNumber, TokenString, TokenOp, TokenS class token { public: explicit token(token_type t = TokenSymbol) noexcept : type(t) {} - token(const token &) = delete; - token &operator=(const token &) = delete; - token(token &&) noexcept = default; - token &operator=(token &&) noexcept = default; + token(const token&) = delete; + token& operator=(const token&) = delete; + token(token&&) noexcept = default; + token& operator=(token&&) noexcept = default; [[nodiscard]] RX_ALWAYS_INLINE std::string_view text() const noexcept { return std::string_view(text_.data(), text_.size()); } void to_lower() noexcept { - for (auto &c : text_) { + for (auto& c : text_) { c = tolower(c); } } @@ -78,7 +78,7 @@ class tokenizer { } [[nodiscard]] std::string where() const; [[nodiscard]] size_t length() const noexcept { return q_.length(); } - [[nodiscard]] const char *begin() const noexcept { return q_.data(); } + [[nodiscard]] const char* begin() const noexcept { return q_.data(); } private: std::string_view q_; @@ -86,6 +86,8 @@ class tokenizer { size_t pos_ = 0; }; -Variant token2kv(const token &currTok, tokenizer &parser, bool allowComposite); +enum class CompositeAllowed : bool { No = false, Yes = true }; +enum class FieldAllowed : bool { No = false, Yes = true }; +Variant token2kv(const token& currTok, tokenizer& parser, CompositeAllowed allowComposite, FieldAllowed allowField); } // namespace reindexer diff --git a/cpp_src/estl/trivial_reverse_iterator.h b/cpp_src/estl/trivial_reverse_iterator.h index ccf1aa514..779614e7f 100644 --- a/cpp_src/estl/trivial_reverse_iterator.h +++ b/cpp_src/estl/trivial_reverse_iterator.h @@ -66,14 +66,18 @@ class trivial_reverse_iterator { // Assign operator overloading from const std::reverse_iterator template trivial_reverse_iterator& operator=(const std::reverse_iterator& u) noexcept { - if (current_ != u.base()) current_ = u.base(); + if (current_ != u.base()) { + current_ = u.base(); + } return *this; } // Assign operator overloading from non-const std::reverse_iterator template trivial_reverse_iterator& operator=(std::reverse_iterator& u) noexcept { - if (current_ != u.base()) current_ = u.base(); + if (current_ != u.base()) { + current_ = u.base(); + } return *this; } diff --git a/cpp_src/gtests/bench/fixtures/aggregation.cc b/cpp_src/gtests/bench/fixtures/aggregation.cc index 6523df608..6cffbfa1b 100644 --- a/cpp_src/gtests/bench/fixtures/aggregation.cc +++ b/cpp_src/gtests/bench/fixtures/aggregation.cc @@ -8,15 +8,21 @@ void Aggregation::Insert(State& state) { for (auto _ : state) { // NOLINT(*deadcode.DeadStores) for (size_t i = 0; i < N; ++i) { auto item = MakeItem(state); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } auto err = db_->Insert(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } auto err = db_->Commit(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void Aggregation::RegisterAllCases() { @@ -31,7 +37,9 @@ void Aggregation::RegisterAllCases() { reindexer::Error Aggregation::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } return {}; } @@ -53,7 +61,9 @@ reindexer::Item Aggregation::MakeItem(benchmark::State& state) { arr.End(); bld.End(); const auto err = item.FromJSON(wrSer_.Slice()); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } return item; } @@ -64,7 +74,9 @@ void Aggregation::Facet(benchmark::State& state) { q.Aggregate(AggFacet, {"int_data"}); reindexer::QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -75,7 +87,9 @@ void Aggregation::MultiFacet(benchmark::State& state) { q.Aggregate(AggFacet, {"int_data", "str_data"}); reindexer::QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -86,6 +100,8 @@ void Aggregation::ArrayFacet(benchmark::State& state) { q.Aggregate(AggFacet, {"int_array_data"}); reindexer::QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_encdec.cc b/cpp_src/gtests/bench/fixtures/api_encdec.cc index 710262027..337c5e628 100644 --- a/cpp_src/gtests/bench/fixtures/api_encdec.cc +++ b/cpp_src/gtests/bench/fixtures/api_encdec.cc @@ -65,11 +65,15 @@ reindexer::Error ApiEncDec::prepareBenchData() { .AddIndex("string_hash_array_index", "hash", "string", IndexOpts().Array()) .AddIndex("string_tree_array_index", "tree", "string", IndexOpts().Array()); auto err = db_->AddNamespace(nsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } fieldsToExtract_.clear(); itemForCjsonBench_ = std::make_unique(db_->NewItem(nsName_)); - if (!itemForCjsonBench_->Status().ok()) return itemForCjsonBench_->Status(); + if (!itemForCjsonBench_->Status().ok()) { + return itemForCjsonBench_->Status(); + } reindexer::WrSerializer wser; reindexer::JsonBuilder bld(wser); constexpr size_t len = 10; @@ -146,10 +150,16 @@ reindexer::Error ApiEncDec::prepareBenchData() { } bld.End(); err = itemForCjsonBench_->FromJSON(wser.Slice()); - if (!err.ok()) return err; - if (!itemForCjsonBench_->Status().ok()) return itemForCjsonBench_->Status(); + if (!err.ok()) { + return err; + } + if (!itemForCjsonBench_->Status().ok()) { + return itemForCjsonBench_->Status(); + } err = db_->Insert(nsName_, *itemForCjsonBench_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } itemCJSON_ = itemForCjsonBench_->GetCJSON(); itemJSON_ = itemForCjsonBench_->GetJSON(); wser.Reset(); @@ -164,8 +174,12 @@ void ApiEncDec::FromCJSON(benchmark::State& state) { AllocsTracker allocsTracker(state); for (auto _ : state) { // NOLINT(*deadcode.DeadStores) const auto err = item.FromCJSON(itemCJSON_); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } } } @@ -175,8 +189,12 @@ void ApiEncDec::FromCJSONPKOnly(benchmark::State& state) { AllocsTracker allocsTracker(state); for (auto _ : state) { // NOLINT(*deadcode.DeadStores) const auto err = item.FromCJSON(itemCJSON_, true); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } } } assertrx(item["id"].Get() == kCjsonBenchItemID); @@ -198,7 +216,9 @@ void ApiEncDec::ExtractField(benchmark::State& state) { for (auto _ : state) { // NOLINT(*deadcode.DeadStores) const auto& fieldName = fieldsToExtract_[rand() % fieldsToExtract_.size()]; const auto va = VariantArray((*itemForCjsonBench_)[fieldName]); - if (va.size() != 1) state.SkipWithError(fmt::sprintf("Unexpected result size: %d", va.size()).c_str()); + if (va.size() != 1) { + state.SkipWithError(fmt::sprintf("Unexpected result size: %d", va.size()).c_str()); + } } } @@ -207,8 +227,12 @@ void ApiEncDec::FromJSON(benchmark::State& state) { AllocsTracker allocsTracker(state); for (auto _ : state) { // NOLINT(*deadcode.DeadStores) const auto err = item.FromJSON(itemJSON_); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } } } @@ -226,8 +250,12 @@ void ApiEncDec::FromPrettyJSON(benchmark::State& state) { AllocsTracker allocsTracker(state); for (auto _ : state) { // NOLINT(*deadcode.DeadStores) const auto err = item.FromJSON(itemPrettyJSON_); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } } } @@ -248,8 +276,12 @@ void ApiEncDec::FromMsgPack(benchmark::State& state) { for (auto _ : state) { // NOLINT(*deadcode.DeadStores) size_t offset = 0; const auto err = item.FromMsgPack(itemMsgPack_, offset); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_tv_composite.cc b/cpp_src/gtests/bench/fixtures/api_tv_composite.cc index dc131e080..0c365d7cb 100644 --- a/cpp_src/gtests/bench/fixtures/api_tv_composite.cc +++ b/cpp_src/gtests/bench/fixtures/api_tv_composite.cc @@ -11,7 +11,9 @@ using reindexer::Variant; reindexer::Error ApiTvComposite::Initialize() { auto err = BaseFixture::Initialize(); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } names_ = {"ox", "ant", "ape", "asp", "bat", "bee", "boa", "bug", "cat", "cod", "cow", "cub", "doe", "dog", "eel", "eft", "elf", "elk", "emu", "ewe", "fly", "fox", "gar", "gnu", "hen", "hog", "imp", "jay", @@ -127,9 +129,13 @@ void ApiTvComposite::GetByCompositePK(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -144,7 +150,9 @@ void ApiTvComposite::RangeTreeInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -157,7 +165,9 @@ void ApiTvComposite::RangeTreeStrCollateNumeric(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -172,9 +182,13 @@ void ApiTvComposite::RangeTreeDouble(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("empty qres"); + if (!qres.Count()) { + state.SkipWithError("empty qres"); + } } } @@ -192,7 +206,9 @@ void ApiTvComposite::RangeTreeCompositeIntInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -211,7 +227,9 @@ void ApiTvComposite::RangeTreeCompositeIntStr(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -225,7 +243,9 @@ void ApiTvComposite::RangeHashInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -240,7 +260,9 @@ void ApiTvComposite::RangeHashStringCollateASCII(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -256,7 +278,9 @@ void ApiTvComposite::RangeHashStringCollateUTF8(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -275,7 +299,9 @@ void ApiTvComposite::RangeHashCompositeIntInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -294,7 +320,9 @@ void ApiTvComposite::RangeHashCompositeIntStr(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -310,7 +338,9 @@ void ApiTvComposite::RangeTreeIntSortByHashInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -326,7 +356,9 @@ void ApiTvComposite::RangeTreeIntSortByTreeInt(State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -342,7 +374,9 @@ void ApiTvComposite::RangeTreeStrSortByHashInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -358,7 +392,9 @@ void ApiTvComposite::RangeTreeStrSortByTreeInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -375,7 +411,9 @@ void ApiTvComposite::RangeTreeDoubleSortByTreeInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -392,7 +430,9 @@ void ApiTvComposite::RangeTreeDoubleSortByHashInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -408,7 +448,9 @@ void ApiTvComposite::RangeTreeStrSortByHashStrCollateASCII(benchmark::State& sta QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -424,7 +466,9 @@ void ApiTvComposite::RangeTreeStrSortByHashStrCollateUTF8(benchmark::State& stat QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -438,7 +482,9 @@ void ApiTvComposite::SortByHashInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -452,7 +498,9 @@ void ApiTvComposite::ForcedSortByHashInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -466,7 +514,9 @@ void ApiTvComposite::ForcedSortWithSecondCondition(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -480,7 +530,9 @@ void ApiTvComposite::Query2CondIdSetComposite(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -494,7 +546,9 @@ void ApiTvComposite::SortByHashStrCollateASCII(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -508,7 +562,9 @@ void ApiTvComposite::SortByHashStrCollateUTF8(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -522,7 +578,9 @@ void ApiTvComposite::SortByHashCompositeIntInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -536,7 +594,9 @@ void ApiTvComposite::SortByHashCompositeIntStr(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -550,7 +610,9 @@ void ApiTvComposite::SortByTreeCompositeIntInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -564,6 +626,8 @@ void ApiTvComposite::SortByTreeCompositeIntStrCollateUTF8(benchmark::State& stat QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_tv_simple.cc b/cpp_src/gtests/bench/fixtures/api_tv_simple.cc index 032714d56..ad5219a47 100644 --- a/cpp_src/gtests/bench/fixtures/api_tv_simple.cc +++ b/cpp_src/gtests/bench/fixtures/api_tv_simple.cc @@ -105,7 +105,9 @@ reindexer::Error ApiTvSimple::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } countries_ = {"Portugal", "Afghanistan", @@ -175,31 +177,45 @@ reindexer::Error ApiTvSimple::Initialize() { .AddIndex("str_fuzzy_coll_num", "fuzzytext", "string", IndexOpts(0, CollateNumeric)); err = db_->AddNamespace(strNsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (size_t i = 0; i < kTotalItemsStringSelectNs; ++i) { auto item = MakeStrItem(); - if (!item.Status().ok()) return item.Status(); + if (!item.Status().ok()) { + return item.Status(); + } err = db_->Insert(stringSelectNs_, item); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } err = db_->Commit(stringSelectNs_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } NamespaceDef mainNsDef{mainNs_}; mainNsDef.AddIndex("id", "hash", "int", IndexOpts().PK()).AddIndex("field", "hash", "int", IndexOpts()); err = db_->AddNamespace(mainNsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } NamespaceDef rightNsDef{rightNs_}; rightNsDef.AddIndex("id", "hash", "int", IndexOpts().PK()) .AddIndex("field", "hash", "int", IndexOpts()) .AddIndex("id_tree", "tree", "int", IndexOpts()); err = db_->AddNamespace(rightNsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (size_t i = 0; i < kTotalItemsMainJoinNs; ++i) { reindexer::Item mItem = db_->NewItem(mainNsDef.name); - if (!mItem.Status().ok()) return mItem.Status(); + if (!mItem.Status().ok()) { + return mItem.Status(); + } mItem.Unsafe(); wrSer_.Reset(); reindexer::JsonBuilder bld(wrSer_); @@ -207,12 +223,18 @@ reindexer::Error ApiTvSimple::Initialize() { bld.Put("field", i); bld.End(); err = mItem.FromJSON(wrSer_.Slice()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } err = db_->Insert(mainNsDef.name, mItem); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } reindexer::Item rItem = db_->NewItem(rightNsDef.name); - if (!rItem.Status().ok()) return rItem.Status(); + if (!rItem.Status().ok()) { + return rItem.Status(); + } rItem.Unsafe(); wrSer_.Reset(); reindexer::JsonBuilder bld2(wrSer_); @@ -221,9 +243,13 @@ reindexer::Error ApiTvSimple::Initialize() { bld2.Put("id_tree", i); bld2.End(); err = rItem.FromJSON(wrSer_.Slice()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } err = db_->Insert(rightNsDef.name, rItem); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } return {}; } @@ -257,7 +283,9 @@ reindexer::Item ApiTvSimple::MakeStrItem() { bld.Put("field_str", "value_" + idStr); bld.End(); const auto err = item.FromJSON(wrSer_.Slice()); - if (!err.ok()) assert(!item.Status().ok()); + if (!err.ok()) { + assert(!item.Status().ok()); + } } return item; } @@ -299,7 +327,9 @@ void ApiTvSimple::WarmUpIndexes(State& state) { Query q(nsdef_.name); q.Where("packages", CondSet, packages_.at(i % packages_.size())).Limit(20).Sort("start_time", false); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } for (size_t i = 0; i < packages_.size() * 2; ++i) { @@ -307,7 +337,9 @@ void ApiTvSimple::WarmUpIndexes(State& state) { Query q(nsdef_.name); q.Where("packages", CondSet, packages_.at(i % packages_.size())).Limit(20).Sort("year", false); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } for (size_t i = 0; i < priceIDs_.size() * 3; ++i) { @@ -315,7 +347,9 @@ void ApiTvSimple::WarmUpIndexes(State& state) { Query q(kJoinNamespace); q.Where("id", CondSet, priceIDs_.at(i % priceIDs_.size())).Limit(20); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } } @@ -327,8 +361,12 @@ void ApiTvSimple::StringsSelect(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -340,9 +378,13 @@ void ApiTvSimple::GetByID(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -354,9 +396,13 @@ void ApiTvSimple::GetByIDInBrackets(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -368,9 +414,13 @@ void ApiTvSimple::GetEqInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -383,9 +433,13 @@ void ApiTvSimple::GetUuid(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -398,9 +452,13 @@ void ApiTvSimple::GetUuidStr(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -412,9 +470,13 @@ void ApiTvSimple::GetEqArrayInt(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -426,9 +488,13 @@ void ApiTvSimple::GetEqString(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -440,9 +506,13 @@ void ApiTvSimple::GetLikeString(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -456,9 +526,13 @@ void ApiTvSimple::GetByRangeIDAndSortByHash(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -472,9 +546,13 @@ void ApiTvSimple::GetByRangeIDAndSortByTree(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -486,7 +564,9 @@ void ApiTvSimple::Query1Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -498,7 +578,9 @@ void ApiTvSimple::Query1CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -510,7 +592,9 @@ void ApiTvSimple::Query1CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -528,7 +612,9 @@ void ApiTvSimple::Query2Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -540,7 +626,9 @@ void ApiTvSimple::Query2CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -552,7 +640,9 @@ void ApiTvSimple::Query2CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -572,7 +662,9 @@ void ApiTvSimple::Query2CondLeftJoin2Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -593,7 +685,9 @@ void ApiTvSimple::Query2CondLeftJoin2CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -614,7 +708,9 @@ void ApiTvSimple::Query2CondLeftJoin2CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -634,7 +730,9 @@ void ApiTvSimple::Query2CondLeftJoin3Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -655,7 +753,9 @@ void ApiTvSimple::Query2CondLeftJoin3CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -676,7 +776,9 @@ void ApiTvSimple::Query2CondLeftJoin3CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -700,7 +802,9 @@ void ApiTvSimple::Query0CondInnerJoinUnlimit(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } ++num; } } @@ -716,7 +820,9 @@ void ApiTvSimple::Query0CondInnerJoinUnlimitLowSelectivity(benchmark::State& sta QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -729,7 +835,9 @@ void ApiTvSimple::SubQueryEq(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -743,7 +851,9 @@ void ApiTvSimple::SubQuerySet(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -759,7 +869,9 @@ void ApiTvSimple::SubQueryAggregate(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -779,7 +891,9 @@ void ApiTvSimple::Query2CondInnerJoin2Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -799,7 +913,9 @@ void ApiTvSimple::Query2CondInnerJoin3Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -816,7 +932,9 @@ void ApiTvSimple::InnerJoinInjectConditionFromMain(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -830,7 +948,9 @@ void ApiTvSimple::InnerJoinRejectInjection(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -838,19 +958,25 @@ void ApiTvSimple::Query0CondInnerJoinPreResultStoreValues(benchmark::State& stat using reindexer::JoinedSelector; static const std::string rightNs = "rightNs"; static const std::vector leftNs = {"leftNs1", "leftNs2", "leftNs3", "leftNs4"}; - static constexpr char const* id = "id"; - static constexpr char const* data = "data"; + static constexpr const char* id = "id"; + static constexpr const char* data = "data"; static constexpr int maxDataValue = 10; static constexpr int maxRightNsRowCount = maxDataValue * (JoinedSelector::MaxIterationsForPreResultStoreValuesOptimization() - 1); static constexpr int maxLeftNsRowCount = 10000; const auto createNs = [this, &state](const std::string& ns) { reindexer::Error err = db_->OpenNamespace(ns); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } err = db_->AddIndex(ns, {id, "hash", "int", IndexOpts().PK()}); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } err = db_->AddIndex(ns, {data, "hash", "int", IndexOpts()}); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } }; const auto fill = [this, &state](const std::string& ns, int startId, int endId) { reindexer::Error err; @@ -859,10 +985,14 @@ void ApiTvSimple::Query0CondInnerJoinPreResultStoreValues(benchmark::State& stat item[id] = i; item[data] = i % maxDataValue; err = db_->Upsert(ns, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } err = db_->Commit(ns); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } }; createNs(rightNs); @@ -882,10 +1012,14 @@ void ApiTvSimple::Query0CondInnerJoinPreResultStoreValues(benchmark::State& stat QueryResults qres; reindexer::Error err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } }); } - for (auto& th : threads) th.join(); + for (auto& th : threads) { + th.join(); + } } } @@ -906,7 +1040,9 @@ void ApiTvSimple::Query2CondInnerJoin2CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -927,7 +1063,9 @@ void ApiTvSimple::Query2CondInnerJoin3CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -948,7 +1086,9 @@ void ApiTvSimple::Query2CondInnerJoin2CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -969,7 +1109,9 @@ void ApiTvSimple::Query2CondInnerJoin3CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -987,7 +1129,9 @@ void ApiTvSimple::Query3Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1006,7 +1150,9 @@ void ApiTvSimple::Query3CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1025,7 +1171,9 @@ void ApiTvSimple::Query3CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1041,7 +1189,9 @@ void ApiTvSimple::Query3CondKillIdsCache(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1059,7 +1209,9 @@ void ApiTvSimple::Query3CondRestoreIdsCache(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1078,7 +1230,9 @@ void ApiTvSimple::Query4Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1098,7 +1252,9 @@ void ApiTvSimple::Query4CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1118,7 +1274,9 @@ void ApiTvSimple::Query4CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1138,7 +1296,9 @@ void ApiTvSimple::Query4CondRange(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1159,7 +1319,9 @@ void ApiTvSimple::Query4CondRangeTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1180,7 +1342,9 @@ void ApiTvSimple::Query4CondRangeCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1202,7 +1366,9 @@ void ApiTvSimple::Query4CondRangeDropCache(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1225,7 +1391,9 @@ void ApiTvSimple::Query4CondRangeDropCacheTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1248,7 +1416,9 @@ void ApiTvSimple::Query4CondRangeDropCacheCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1261,6 +1431,8 @@ void ApiTvSimple::query2CondIdSet(benchmark::State& state, const std::vectorSelect(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_tv_simple_comparators.cc b/cpp_src/gtests/bench/fixtures/api_tv_simple_comparators.cc index 459ad9f17..f7da0f1b7 100644 --- a/cpp_src/gtests/bench/fixtures/api_tv_simple_comparators.cc +++ b/cpp_src/gtests/bench/fixtures/api_tv_simple_comparators.cc @@ -49,7 +49,9 @@ reindexer::Error ApiTvSimpleComparators::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } countries_ = {"Portugal", "Afghanistan", @@ -71,12 +73,18 @@ reindexer::Error ApiTvSimpleComparators::Initialize() { uuids_.emplace_back(randStrUuid()); } - for (int i = 0; i < 10; i++) packages_.emplace_back(randomNumArray(20, 10000, 10)); + for (int i = 0; i < 10; i++) { + packages_.emplace_back(randomNumArray(20, 10000, 10)); + } - for (int i = 0; i < 20; i++) priceIDs_.emplace_back(randomNumArray(10, 7000, 50)); + for (int i = 0; i < 20; i++) { + priceIDs_.emplace_back(randomNumArray(10, 7000, 50)); + } start_times_.resize(20); - for (int i = 0; i < 20; i++) start_times_[i] = random(0, 50000); + for (int i = 0; i < 20; i++) { + start_times_[i] = random(0, 50000); + } NamespaceDef strNsDef{stringSelectNs_}; strNsDef.AddIndex("id", "hash", "int", IndexOpts().PK()) @@ -86,13 +94,19 @@ reindexer::Error ApiTvSimpleComparators::Initialize() { .AddIndex("str_hash_coll_num", "-", "string", IndexOpts(0, CollateNumeric)); err = db_->AddNamespace(strNsDef); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (size_t i = 0; i < kTotalItemsStringSelectNs; ++i) { auto item = MakeStrItem(); - if (!item.Status().ok()) return item.Status(); + if (!item.Status().ok()) { + return item.Status(); + } err = db_->Insert(stringSelectNs_, item); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } err = db_->Commit(stringSelectNs_); return err; @@ -115,7 +129,9 @@ reindexer::Item ApiTvSimpleComparators::MakeStrItem() { bld.Put("field_str", "value_" + idStr); bld.End(); const auto err = item.FromJSON(wrSer_.Slice()); - if (!err.ok()) assert(!item.Status().ok()); + if (!err.ok()) { + assert(!item.Status().ok()); + } } return item; } @@ -160,8 +176,12 @@ void ApiTvSimpleComparators::StringsSelect(benchmark::State& state) { Query q(stringSelectNs_); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -172,8 +192,12 @@ void ApiTvSimpleComparators::GetEqInt(benchmark::State& state) { q.Where("start_time", CondEq, start_times_.at(random(0, start_times_.size() - 1))); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -184,8 +208,12 @@ void ApiTvSimpleComparators::GetEqArrayInt(benchmark::State& state) { q.Where("price_id", CondEq, priceIDs_[random(0, priceIDs_.size() - 1)]); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -196,8 +224,12 @@ void ApiTvSimpleComparators::GetEqString(benchmark::State& state) { q.Where("countries", CondEq, countries_[random(0, countries_.size() - 1)]); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -210,9 +242,13 @@ void ApiTvSimpleComparators::GetByRangeIDAndSort(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -224,8 +260,12 @@ void ApiTvSimpleComparators::GetUuidStr(benchmark::State& state) { q.Where("uuid_str", CondEq, uuid); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -237,7 +277,9 @@ void ApiTvSimpleComparators::Query1Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -249,7 +291,9 @@ void ApiTvSimpleComparators::Query1CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -261,7 +305,9 @@ void ApiTvSimpleComparators::Query1CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -273,7 +319,9 @@ void ApiTvSimpleComparators::Query2Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -285,7 +333,9 @@ void ApiTvSimpleComparators::Query2CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -297,7 +347,9 @@ void ApiTvSimpleComparators::Query2CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -314,7 +366,9 @@ void ApiTvSimpleComparators::Query3Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -332,7 +386,9 @@ void ApiTvSimpleComparators::Query3CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -350,7 +406,9 @@ void ApiTvSimpleComparators::Query3CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -366,7 +424,9 @@ void ApiTvSimpleComparators::Query3CondKillIdsCache(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -383,7 +443,9 @@ void ApiTvSimpleComparators::Query3CondRestoreIdsCache(benchmark::State& state) QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -401,7 +463,9 @@ void ApiTvSimpleComparators::Query4Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -420,7 +484,9 @@ void ApiTvSimpleComparators::Query4CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -439,7 +505,9 @@ void ApiTvSimpleComparators::Query4CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -458,7 +526,9 @@ void ApiTvSimpleComparators::Query4CondRange(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -478,7 +548,9 @@ void ApiTvSimpleComparators::Query4CondRangeTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -498,6 +570,8 @@ void ApiTvSimpleComparators::Query4CondRangeCachedTotal(benchmark::State& state) QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.cc b/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.cc index 404badf23..ae8a85533 100644 --- a/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.cc +++ b/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.cc @@ -55,7 +55,9 @@ reindexer::Error ApiTvSimpleSparse::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } countries_ = {"Portugal", "Afghanistan", @@ -139,7 +141,9 @@ void ApiTvSimpleSparse::WarmUpIndexes(State& state) { Query q(nsdef_.name); q.Where("packages", CondSet, packages_.at(i % packages_.size())).Limit(20).Sort("uuid", false); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } for (size_t i = 0; i < packages_.size() * 2; ++i) { @@ -147,7 +151,9 @@ void ApiTvSimpleSparse::WarmUpIndexes(State& state) { Query q(nsdef_.name); q.Where("packages", CondSet, packages_.at(i % packages_.size())).Limit(20).Sort("countries", false); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } for (size_t i = 0; i < priceIDs_.size() * 3; ++i) { @@ -155,7 +161,9 @@ void ApiTvSimpleSparse::WarmUpIndexes(State& state) { Query q(kJoinNamespace); q.Where("id", CondSet, priceIDs_.at(i % priceIDs_.size())).Limit(20); err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } } @@ -170,9 +178,13 @@ void ApiTvSimpleSparse::GetByRangeIDAndSortByHash(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -186,9 +198,13 @@ void ApiTvSimpleSparse::GetByRangeIDAndSortByTree(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } - if (!qres.Count()) state.SkipWithError("Results does not contain any value"); + if (!qres.Count()) { + state.SkipWithError("Results does not contain any value"); + } } } @@ -200,7 +216,9 @@ void ApiTvSimpleSparse::Query1Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -212,7 +230,9 @@ void ApiTvSimpleSparse::Query1CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -224,7 +244,9 @@ void ApiTvSimpleSparse::Query1CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -236,7 +258,9 @@ void ApiTvSimpleSparse::Query2Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -248,7 +272,9 @@ void ApiTvSimpleSparse::Query2CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -260,7 +286,9 @@ void ApiTvSimpleSparse::Query2CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -278,7 +306,9 @@ void ApiTvSimpleSparse::Query3Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -297,7 +327,9 @@ void ApiTvSimpleSparse::Query3CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -316,7 +348,9 @@ void ApiTvSimpleSparse::Query3CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -335,7 +369,9 @@ void ApiTvSimpleSparse::Query4Cond(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -355,7 +391,9 @@ void ApiTvSimpleSparse::Query4CondTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -375,7 +413,9 @@ void ApiTvSimpleSparse::Query4CondCachedTotal(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -394,7 +434,9 @@ void ApiTvSimpleSparse::QueryInnerJoinPreselectByValues(benchmark::State& state) QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -413,7 +455,9 @@ void ApiTvSimpleSparse::QueryInnerJoinNoPreselect(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -439,6 +483,8 @@ void ApiTvSimpleSparse::query4CondParameterizable(benchmark::State& state, std:: QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.h b/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.h index 05ebd9711..c4b9d2f36 100644 --- a/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.h +++ b/cpp_src/gtests/bench/fixtures/api_tv_simple_sparse.h @@ -20,7 +20,7 @@ class ApiTvSimpleSparse : private BaseFixture { .AddIndex("location", "hash", "string", IndexOpts().Sparse()) .AddIndex("end_time", "hash", "int", IndexOpts().Sparse()) .AddIndex("start_time", "tree", "int", IndexOpts().Sparse()) - .AddIndex("uuid", "hash", "uuid", IndexOpts()) // can't be sparse + .AddIndex("uuid", "hash", "uuid", IndexOpts()) // can't be sparse .AddIndex("uuid_str", "hash", "string", IndexOpts().Sparse()) .AddIndex("data10", "hash", "int", IndexOpts().Sparse()) .AddIndex("data33", "hash", "int", IndexOpts().Sparse()) diff --git a/cpp_src/gtests/bench/fixtures/base_fixture.cc b/cpp_src/gtests/bench/fixtures/base_fixture.cc index 303a6367e..a6d446f04 100644 --- a/cpp_src/gtests/bench/fixtures/base_fixture.cc +++ b/cpp_src/gtests/bench/fixtures/base_fixture.cc @@ -36,16 +36,22 @@ void BaseFixture::Insert(State& state) { for (auto _ : state) { // NOLINT(*deadcode.DeadStores) for (int i = 0; i < id_seq_->Count(); ++i) { auto item = MakeItem(state); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } auto err = db_->Insert(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } state.SetItemsProcessed(state.items_processed() + 1); } } auto err = db_->Commit(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void BaseFixture::Update(benchmark::State& state) { @@ -53,10 +59,14 @@ void BaseFixture::Update(benchmark::State& state) { id_seq_->Reset(); for (auto _ : state) { // NOLINT(*deadcode.DeadStores) auto item = MakeItem(state); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } auto err = db_->Update(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } if (item.GetID() < 0) { auto e = reindexer::Error(errConflict, "Item not exists [id = '%d']", item["id"].As()); @@ -65,7 +75,9 @@ void BaseFixture::Update(benchmark::State& state) { state.SetItemsProcessed(state.items_processed() + 1); } auto err = db_->Commit(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void BaseFixture::WaitForOptimization() { diff --git a/cpp_src/gtests/bench/fixtures/ft_fixture.cc b/cpp_src/gtests/bench/fixtures/ft_fixture.cc index 305d2ef94..4a14fdb14 100644 --- a/cpp_src/gtests/bench/fixtures/ft_fixture.cc +++ b/cpp_src/gtests/bench/fixtures/ft_fixture.cc @@ -58,19 +58,27 @@ void FullText::UpdateIndex(State& state) { q.Where(kFastIndexTextName_, CondEq, "lskfj"); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } reindexer::Error FullText::Initialize() { auto err = BaseFixture::Initialize(); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } err = db_->AddNamespace(lowWordsDiversityNsDef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } words_.reserve(140000); err = readDictFile(RX_BENCH_DICT_PATH, words_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } words2_ = {"стол", "столом", "столы", "cnjk", "stol", "бежит", "бегут", "бежали", ",tu", "beg", "дом", "доме", "ljv", "ракета", "ракетой", "ракеты", "hfrtn", "raketa", "летит", "летает", @@ -202,7 +210,9 @@ reindexer::Item FullText::MakeLowDiversityItem(int id) { for (size_t i = 0; i < wordCnt; i++) { r << words2_.at(randomGenerator_(randomEngine_, std::uniform_int_distribution::param_type{0, int(words2_.size() - 1)})); - if (i < wordCnt - 1) r << " "; + if (i < wordCnt - 1) { + r << " "; + } } return std::string(r.Slice()); }; @@ -221,7 +231,9 @@ reindexer::Item FullText::MakeItem(benchmark::State&) { auto phrase = CreatePhrase(); auto countries = GetRandomCountries(); raw_data_sz_ += phrase.size(); - for (auto& c : countries) raw_data_sz_ += c.size(); + for (auto& c : countries) { + raw_data_sz_ += c.size(); + } item["id"] = id_seq_->Next(); item["description"] = phrase; @@ -301,11 +313,15 @@ void FullText::Insert(State& state) { } auto err = db_->Insert(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } auto err = db_->Commit(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void FullText::BuildCommonIndexes(benchmark::State& state) { @@ -318,7 +334,9 @@ void FullText::BuildCommonIndexes(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -334,7 +352,9 @@ void FullText::BuildInsertLowDiversityNs(State& state) { } auto err = db_->Insert(lowWordsDiversityNsDef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } idCounter++; } @@ -342,7 +362,9 @@ void FullText::BuildInsertLowDiversityNs(State& state) { q.Where(kLowDiversityIndexName_, CondEq, words2_.at(0)).Limit(1); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void FullText::Fast3PhraseLowDiversity(State& state) { @@ -364,7 +386,9 @@ void FullText::Fast3PhraseLowDiversity(State& state) { auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -390,7 +414,9 @@ void FullText::Fast3WordsLowDiversity(State& state) { auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -414,7 +440,9 @@ void FullText::Fast2PhraseLowDiversity(State& state) { auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -438,7 +466,9 @@ void FullText::Fast2AndWordLowDiversity(State& state) { auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -465,7 +495,9 @@ void FullText::Fast3PhraseWithAreasLowDiversity(State& state) { q.AddFunction(hilightStr); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -484,7 +516,9 @@ void FullText::Fast1WordWithAreaHighDiversity(State& state) { q.AddFunction(hilightStr); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -510,7 +544,9 @@ void FullText::Fast3WordsWithAreasLowDiversity(State& state) { q.AddFunction(hilightStr); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -532,7 +568,9 @@ void FullText::BuildFastTextIndex(benchmark::State& state) { auto err = db_->Select(q, qres); mem = get_alloc_size() - mem; - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } double ratio = mem / double(raw_data_sz_); state.SetLabel("Commit ratio: " + std::to_string(ratio)); @@ -553,7 +591,9 @@ void FullText::BuildFuzzyTextIndex(benchmark::State& state) { auto err = db_->Select(q, qres); mem = get_alloc_size() - mem; - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } double ratio = mem / double(raw_data_sz_); state.SetLabel("Commit ratio: " + std::to_string(ratio)); @@ -574,7 +614,9 @@ void FullText::Fast1WordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -594,7 +636,9 @@ void FullText::Fast2WordsMatch(benchmark::State& state) { q.Where(kFastIndexTextName_, CondEq, std::move(words)); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } @@ -612,7 +656,9 @@ void FullText::Fuzzy1WordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -631,7 +677,9 @@ void FullText::Fuzzy2WordsMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -648,7 +696,9 @@ void FullText::Fast1PrefixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -665,7 +715,9 @@ void FullText::Fast2PrefixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -680,7 +732,9 @@ void FullText::Fuzzy1PrefixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -695,7 +749,9 @@ void FullText::Fuzzy2PrefixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -711,7 +767,9 @@ void FullText::Fast1SuffixMatch(benchmark::State& state) { q.Where(kFastIndexTextName_, CondEq, MakeSuffixWord()); QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -728,7 +786,9 @@ void FullText::Fast2SuffixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -743,7 +803,9 @@ void FullText::Fuzzy1SuffixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -758,7 +820,9 @@ void FullText::Fuzzy2SuffixMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -775,7 +839,9 @@ void FullText::Fast1TypoWordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -792,7 +858,9 @@ void FullText::Fast2TypoWordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -807,7 +875,9 @@ void FullText::Fuzzy1TypoWordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -822,7 +892,9 @@ void FullText::Fuzzy2TypoWordMatch(benchmark::State& state) { QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } cnt += qres.Count(); } state.SetLabel(FormatString("RPR: %.1f", cnt / double(state.iterations()))); @@ -835,7 +907,9 @@ std::string FullText::CreatePhrase() { for (size_t i = 0; i < wordCnt; i++) { r << words_.at(randomGenerator_(randomEngine_, std::uniform_int_distribution::param_type{0, int(words_.size() - 1)})); - if (i < wordCnt - 1) r << " "; + if (i < wordCnt - 1) { + r << " "; + } } return std::string(r.Slice()); @@ -937,12 +1011,16 @@ void FullText::InitForAlternatingUpdatesAndSelects(State& state) { continue; } err = db_->Insert(alternatingNs_, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } auto err = db_->Commit(alternatingNs_); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } // Init index build assert(!values_.empty()); @@ -953,20 +1031,26 @@ void FullText::InitForAlternatingUpdatesAndSelects(State& state) { .search1); QueryResults qres; err = db_->Select(q1, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } size_t index = randomGenerator_(randomEngine_, std::uniform_int_distribution::param_type{0, int(values_.size() - 1)}); const Query q2 = Query(alternatingNs_).Where("search_comp", CondEq, values_[index].search1 + ' ' + values_[index].search2); qres.Clear(); err = db_->Select(q2, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } index = randomGenerator_(randomEngine_, std::uniform_int_distribution::param_type{0, int(values_.size() - 1)}); const Query q3 = Query(alternatingNs_).Where("search_comp_not_index_fields", CondEq, values_[index].field1 + ' ' + values_[index].field2); qres.Clear(); err = db_->Select(q3, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void FullText::updateAlternatingNs(reindexer::WrSerializer& ser, benchmark::State& state) { @@ -994,14 +1078,18 @@ void FullText::updateAlternatingNs(reindexer::WrSerializer& ser, benchmark::Stat return; } err = db_->Update(alternatingNs_, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } const std::string sql = "UPDATE "s + alternatingNs_ + " SET rand = " + std::to_string(rand()) + " WHERE id = " + std::to_string(randomGenerator_(randomEngine_, std::uniform_int_distribution::param_type{0, int(values_.size() - 1)})); QueryResults qres; err = db_->Select(sql, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } void FullText::AlternatingUpdatesAndSelects(benchmark::State& state) { @@ -1019,7 +1107,9 @@ void FullText::AlternatingUpdatesAndSelects(benchmark::State& state) { QueryResults qres; state.ResumeTiming(); const auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1035,7 +1125,9 @@ void FullText::AlternatingUpdatesAndSelectsByComposite(benchmark::State& state) QueryResults qres; state.ResumeTiming(); const auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -1051,14 +1143,18 @@ void FullText::AlternatingUpdatesAndSelectsByCompositeByNotIndexFields(benchmark QueryResults qres; state.ResumeTiming(); const auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } reindexer::Error FullText::readDictFile(const std::string& fileName, std::vector& words) { std::ifstream file; file.open(fileName); - if (!file) return reindexer::Error(errNotValid, "%s", strerror(errno)); + if (!file) { + return reindexer::Error(errNotValid, "%s", strerror(errno)); + } std::copy(std::istream_iterator(file), std::istream_iterator(), std::back_inserter(words)); return reindexer::Error(); } diff --git a/cpp_src/gtests/bench/fixtures/ft_fixture.h b/cpp_src/gtests/bench/fixtures/ft_fixture.h index 96cfba913..aae810c7f 100644 --- a/cpp_src/gtests/bench/fixtures/ft_fixture.h +++ b/cpp_src/gtests/bench/fixtures/ft_fixture.h @@ -146,8 +146,12 @@ class FullText : private BaseFixture { int tMin = INT32_MAX; int tMax = 0; for (auto v : timeOfTest_) { - if (v < tMin) tMin = v; - if (v > tMax) tMax = v; + if (v < tMin) { + tMin = v; + } + if (v > tMax) { + tMax = v; + } } std::vector gist; const int columnCount = 1000; @@ -168,7 +172,9 @@ class FullText : private BaseFixture { for (auto v : timeOfTest_) { averageTime += v; int indx = double(v - tMin) / dt; - if (indx >= columnCount) indx = columnCount - 1; + if (indx >= columnCount) { + indx = columnCount - 1; + } gist[indx]++; } averageTime /= timeOfTest_.size(); @@ -179,14 +185,18 @@ class FullText : private BaseFixture { fileOut << "\"data\":[" << std::endl; bool isFirst = true; for (auto v : gist) { - if (!isFirst) fileOut << "," << std::endl; + if (!isFirst) { + fileOut << "," << std::endl; + } fileOut << v; isFirst = false; } fileOut << "],\n \"raw_data\":[" << std::endl; isFirst = true; for (auto v : timeOfTest_) { - if (!isFirst) fileOut << "," << std::endl; + if (!isFirst) { + fileOut << "," << std::endl; + } fileOut << v; isFirst = false; } diff --git a/cpp_src/gtests/bench/fixtures/ft_merge_limit.cc b/cpp_src/gtests/bench/fixtures/ft_merge_limit.cc index ef7c78ec7..33f2daf89 100644 --- a/cpp_src/gtests/bench/fixtures/ft_merge_limit.cc +++ b/cpp_src/gtests/bench/fixtures/ft_merge_limit.cc @@ -110,7 +110,9 @@ void FullTextMergeLimit::Insert(State& state) { item["id"] = h; item[kFastIndexTextName_] = phrase; auto err = db_->Upsert(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } state.SetLabel("inserted " + std::to_string(id_seq_->Count()) + " documents"); @@ -124,7 +126,9 @@ void FullTextMergeLimit::BuildFastTextIndex(benchmark::State& state) { reindexer::QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -137,6 +141,8 @@ void FullTextMergeLimit::FastTextIndexSelect(benchmark::State& state, const std: reindexer::QueryResults qres; auto err = db_->Select(q, qres); state.SetLabel("select " + std::to_string(qres.Count()) + " documents"); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } diff --git a/cpp_src/gtests/bench/fixtures/geometry.cc b/cpp_src/gtests/bench/fixtures/geometry.cc index 455bfa000..ee917e484 100644 --- a/cpp_src/gtests/bench/fixtures/geometry.cc +++ b/cpp_src/gtests/bench/fixtures/geometry.cc @@ -14,15 +14,21 @@ void Geometry::Insert(State& state) { for (auto _ : state) { // NOLINT(*deadcode.DeadStores) for (size_t i = 0; i < N; ++i) { auto item = MakeItem(state); - if (!item.Status().ok()) state.SkipWithError(item.Status().what().c_str()); + if (!item.Status().ok()) { + state.SkipWithError(item.Status().what().c_str()); + } auto err = db_->Insert(nsdef_.name, item); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } auto err = db_->Commit(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } template @@ -33,7 +39,9 @@ void Geometry::GetDWithin(benchmark::State& state) { q.DWithin("point", reindexer::randPoint(kRange), kRange / N); reindexer::QueryResults qres; auto err = db_->Select(q, qres); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -46,10 +54,14 @@ void Geometry::Reset(State& state) { nsdef_.AddIndex("id", "hash", "int", IndexOpts().PK()).AddIndex("point", "rtree", "point", IndexOpts().RTreeType(rtreeType)); auto err = db_->DropNamespace(nsdef_.name); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } err = db_->AddNamespace(nsdef_); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } } } @@ -84,7 +96,9 @@ void Geometry::RegisterAllCases() { reindexer::Error Geometry::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } return {}; } @@ -101,7 +115,9 @@ reindexer::Item Geometry::MakeItem(benchmark::State& state) { bld.Array("point", {point.X(), point.Y()}); bld.End(); const auto err = item.FromJSON(wrSer_.Slice()); - if (!err.ok()) state.SkipWithError(err.what().c_str()); + if (!err.ok()) { + state.SkipWithError(err.what().c_str()); + } return item; } diff --git a/cpp_src/gtests/bench/fixtures/join_items.cc b/cpp_src/gtests/bench/fixtures/join_items.cc index 72a0f7de0..8bfc545d8 100644 --- a/cpp_src/gtests/bench/fixtures/join_items.cc +++ b/cpp_src/gtests/bench/fixtures/join_items.cc @@ -5,7 +5,9 @@ reindexer::Error JoinItems::Initialize() { assertrx(db_); auto err = db_->AddNamespace(nsdef_); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } adjectives_ = {"able", "above", "absolute", "balanced", "becoming", "beloved", "calm", "capable", "capital", "destined", "devoted", "direct", "enabled", "enabling", "endless", "factual", "fair", "faithful", "grand", "grateful", @@ -48,7 +50,9 @@ reindexer::Item JoinItems::MakeItem(benchmark::State&) { std::string JoinItems::randomString(const std::string& prefix) { std::string result; - if (!prefix.empty()) result += prefix + "_"; + if (!prefix.empty()) { + result += prefix + "_"; + } result += adjectives_.at(random(0, adjectives_.size() - 1)); result += "_"; result += names_.at(random(0, names_.size() - 1)); diff --git a/cpp_src/gtests/bench/ft_bench.cc b/cpp_src/gtests/bench/ft_bench.cc index 719a77093..c0bdb667d 100644 --- a/cpp_src/gtests/bench/ft_bench.cc +++ b/cpp_src/gtests/bench/ft_bench.cc @@ -32,12 +32,16 @@ int main(int argc, char** argv) { shared_ptr DB = std::make_shared(); auto err = DB->Connect("builtin://" + kStoragePath); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } FullText ft(DB.get(), "fulltext", kItemsInBenchDataset); err = ft.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } ::benchmark::Initialize(&argc, argv); std::optional slowIterationCount; diff --git a/cpp_src/gtests/bench/reindexer_bench.cc b/cpp_src/gtests/bench/reindexer_bench.cc index 065d04070..669055241 100644 --- a/cpp_src/gtests/bench/reindexer_bench.cc +++ b/cpp_src/gtests/bench/reindexer_bench.cc @@ -42,7 +42,9 @@ int main(int argc, char** argv) { shared_ptr DB = std::make_shared(); auto err = DB->Connect("builtin://" + kStoragePath); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } JoinItems joinItems(DB.get(), 50'000); ApiTvSimple apiTvSimple(DB.get(), "ApiTvSimple", kItemsInBenchDataset); @@ -54,31 +56,49 @@ int main(int argc, char** argv) { ApiEncDec decoding(DB.get(), "EncDec"); err = apiTvSimple.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = apiTvSimpleComparators.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = apiTvSimpleSparse.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = joinItems.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = apiTvComposite.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = geometry.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = aggregation.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } err = decoding.Initialize(); - if (!err.ok()) return err.code(); + if (!err.ok()) { + return err.code(); + } ::benchmark::Initialize(&argc, argv); - if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) { + return 1; + } joinItems.RegisterAllCases(); apiTvSimple.RegisterAllCases(); diff --git a/cpp_src/gtests/bench/tools/helpers.cc b/cpp_src/gtests/bench/tools/helpers.cc index 216c79f49..262e819e5 100644 --- a/cpp_src/gtests/bench/tools/helpers.cc +++ b/cpp_src/gtests/bench/tools/helpers.cc @@ -7,7 +7,9 @@ std::string HumanReadableNumber(size_t number, bool si, const std::string& unitL const std::string prefix = "KMGTPE"; size_t unit = si ? 1000 : 1024; - if (number < unit) return std::to_string(number) + " " + unitLabel; + if (number < unit) { + return std::to_string(number) + " " + unitLabel; + } int exp = static_cast(std::log(number) / std::log(unit)); std::string pre; @@ -38,11 +40,11 @@ std::string FormatString(const char* msg, va_list args) { va_end(args_cp); - if (ret == 0) // handle empty expansion + if (ret == 0) { // handle empty expansion return {}; - else if (static_cast(ret) < size) + } else if (static_cast(ret) < size) { return local_buff; - else { + } else { // we did not provide a long enough buffer on our first attempt. size = static_cast(ret) + 1; // + 1 for the null byte std::unique_ptr buff(new char[size]); diff --git a/cpp_src/gtests/bench/tools/helpers.h b/cpp_src/gtests/bench/tools/helpers.h index 061773258..b153bf54e 100644 --- a/cpp_src/gtests/bench/tools/helpers.h +++ b/cpp_src/gtests/bench/tools/helpers.h @@ -21,7 +21,9 @@ struct to_array_helper { static VariantArray to_array(const std::vector& vec) { VariantArray krs; krs.reserve(vec.size()); - for (auto& value : vec) krs.push_back(Variant{value}); + for (auto& value : vec) { + krs.push_back(Variant{value}); + } return krs; } }; @@ -31,7 +33,9 @@ struct to_array_helper { static VariantArray to_array(const std::vector& vec) { VariantArray krs; krs.reserve(vec.size()); - for (auto& value : vec) krs.push_back(Variant{p_string(value.c_str())}); + for (auto& value : vec) { + krs.push_back(Variant{p_string(value.c_str())}); + } return krs; } }; @@ -41,7 +45,9 @@ struct to_array_helper { static inline std::string randString(size_t size) { constexpr static std::string_view ch{"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"}; std::string ret(size, ' '); - for (size_t i = 0; i < size; ++i) ret[i] = ch[rand() % ch.size()]; + for (size_t i = 0; i < size; ++i) { + ret[i] = ch[rand() % ch.size()]; + } return ret; } @@ -112,7 +118,9 @@ template std::vector randomNumArray(int count, int start, int region) { std::vector result; result.reserve(count); - for (int i = 0; i < count; i++) result.emplace_back(random(start, start + region)); + for (int i = 0; i < count; i++) { + result.emplace_back(random(start, start + region)); + } return result; } diff --git a/cpp_src/gtests/bench/tools/reporter.h b/cpp_src/gtests/bench/tools/reporter.h index 88e4596f5..753d9b68b 100644 --- a/cpp_src/gtests/bench/tools/reporter.h +++ b/cpp_src/gtests/bench/tools/reporter.h @@ -16,7 +16,7 @@ class Reporter : public ConsoleReporter { std::string str = FormatString("%-*s %13s %13s", static_cast(name_field_width_), "Benchmark", "Time", "RPS"); if (!run.counters.empty()) { if (output_options_ & OO_Tabular) { - for (auto const& c : run.counters) { + for (const auto& c : run.counters) { if (std::string_view(c.first) == std::string_view("bytes_per_second") || std::string_view(c.first) == std::string_view("items_per_second")) { continue; @@ -60,7 +60,7 @@ class Reporter : public ConsoleReporter { continue; } const std::size_t cNameLen = std::max(std::string::size_type(10), c.first.length()); - auto const& s = HumanReadableNumber(c.second.value, true); + const auto& s = HumanReadableNumber(c.second.value, true); if (output_options_ & OO_Tabular) { if (c.second.flags & Counter::kIsRate) { IgnoreColorPrint(Out, " %*s/s", cNameLen - 2, s.c_str()); diff --git a/cpp_src/gtests/bench/tools/sequence.h b/cpp_src/gtests/bench/tools/sequence.h index 02f9d0331..8a0313884 100644 --- a/cpp_src/gtests/bench/tools/sequence.h +++ b/cpp_src/gtests/bench/tools/sequence.h @@ -37,7 +37,9 @@ class SequenceBase { value_type Next() { value_type val; - if ((val = counter_++) >= end_) return end_; + if ((val = counter_++) >= end_) { + return end_; + } return val; } diff --git a/cpp_src/gtests/tests/API/api.cc b/cpp_src/gtests/tests/API/api.cc index 013ecd2d1..517955efd 100644 --- a/cpp_src/gtests/tests/API/api.cc +++ b/cpp_src/gtests/tests/API/api.cc @@ -4,14 +4,14 @@ #include "tools/assertrx.h" #include "tools/fsops.h" -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { srand(time(NULL)); ::testing::InitGoogleTest(&argc, argv); reindexer::debug::backtrace_init(); #ifndef _WIN32 - const char *tmpDir = getenv("REINDEXER_TEST_DB_ROOT"); + const char* tmpDir = getenv("REINDEXER_TEST_DB_ROOT"); if (tmpDir && *tmpDir) { reindexer::fs::SetTempDir(std::string(tmpDir)); } diff --git a/cpp_src/gtests/tests/API/base_tests.cc b/cpp_src/gtests/tests/API/base_tests.cc index 4a4b16413..c75694529 100644 --- a/cpp_src/gtests/tests/API/base_tests.cc +++ b/cpp_src/gtests/tests/API/base_tests.cc @@ -15,6 +15,8 @@ #include "core/keyvalue/p_string.h" #include "server/loggerwrapper.h" +#include "spdlog/async.h" +#include "spdlog/sinks/reopen_file_sink.h" #include "tools/serializer.h" TEST_F(ReindexerApi, AddNamespace) { @@ -824,8 +826,12 @@ TEST_F(ReindexerApi, SortByMultipleColumns) { err = rt.reindexer->Upsert(default_namespace, item); ASSERT_TRUE(err.ok()) << err.what(); - if (i % 5 == 0) sameOldValue += 5; - if (i % 3 == 0) ++stringValuedIdx; + if (i % 5 == 0) { + sameOldValue += 5; + } + if (i % 3 == 0) { + ++stringValuedIdx; + } stringValuedIdx %= possibleValues.size(); } @@ -857,11 +863,12 @@ TEST_F(ReindexerApi, SortByMultipleColumns) { cmpRes[j] = lastValues[j].Compare(sortedValue); bool needToVerify = true; if (j != 0) { - for (int k = j - 1; k >= 0; --k) + for (int k = j - 1; k >= 0; --k) { if (cmpRes[k] != reindexer::ComparationResult::Eq) { needToVerify = false; break; } + } } needToVerify = (j == 0) || needToVerify; if (needToVerify) { @@ -1680,22 +1687,29 @@ TEST_F(ReindexerApi, LoggerWriteInterruptTest) { struct Logger { Logger() { spdlog::drop_all(); - spdlog::set_async_mode(16384, spdlog::async_overflow_policy::discard_log_msg, nullptr, std::chrono::seconds(2)); + spdlog::init_thread_pool(16384, 1); + spdlog::flush_every(std::chrono::seconds(2)); + spdlog::flush_on(spdlog::level::err); spdlog::set_level(spdlog::level::trace); - spdlog::set_pattern("[%L%d/%m %T.%e %t] %v"); + spdlog::set_pattern("%^[%L%d/%m %T.%e %t] %v%$", spdlog::pattern_time_type::utc); std::remove(logFile.c_str()); - sinkPtr = std::make_shared(logFile); - spdlog::create("log", sinkPtr); + using LogFactoryT = spdlog::async_factory_impl; + using spdlog::sinks::reopen_file_sink_st; + auto lptr = LogFactoryT::create("log", logFile); + assertrx(lptr->sinks().size() == 1); + sinkPtr = std::dynamic_pointer_cast(lptr->sinks()[0]); + assertrx(sinkPtr); logger = reindexer_server::LoggerWrapper("log"); } ~Logger() { spdlog::drop_all(); + spdlog::shutdown(); std::remove(logFile.c_str()); } const std::string logFile = "/tmp/reindex_logtest.out"; reindexer_server::LoggerWrapper logger; - std::shared_ptr sinkPtr; + std::shared_ptr sinkPtr; } instance; reindexer::logInstallWriter( @@ -1704,23 +1718,23 @@ TEST_F(ReindexerApi, LoggerWriteInterruptTest) { instance.logger.trace(buf); } }, - reindexer::LoggerPolicy::WithLocks); + reindexer::LoggerPolicy::WithLocks, int(LogTrace)); auto writeThread = std::thread([]() { for (size_t i = 0; i < 10000; ++i) { - reindexer::logPrintf(LogTrace, "Detailed and amazing description of this error: [%d]!", i); + logPrintf(LogTrace, "Detailed and amazing description of this error: [%d]!", i); } }); auto reopenThread = std::thread([&instance]() { for (size_t i = 0; i < 1000; ++i) { instance.sinkPtr->reopen(); - reindexer::logPrintf(LogTrace, "REOPENED [%d]", i); + logPrintf(LogTrace, "REOPENED [%d]", i); std::this_thread::sleep_for(std::chrono::milliseconds(3)); } }); writeThread.join(); reopenThread.join(); - reindexer::logPrintf(LogTrace, "FINISHED\n"); - reindexer::logInstallWriter(nullptr, reindexer::LoggerPolicy::WithLocks); + logPrintf(LogTrace, "FINISHED\n"); + reindexer::logInstallWriter(nullptr, reindexer::LoggerPolicy::WithLocks, int(LogTrace)); } TEST_F(ReindexerApi, IntToStringIndexUpdate) { diff --git a/cpp_src/gtests/tests/fixtures/btree_idsets_api.h b/cpp_src/gtests/tests/fixtures/btree_idsets_api.h index 935a86585..df5482436 100644 --- a/cpp_src/gtests/tests/fixtures/btree_idsets_api.h +++ b/cpp_src/gtests/tests/fixtures/btree_idsets_api.h @@ -39,8 +39,12 @@ class BtreeIdsetsApi : public ReindexerApi { Upsert(default_namespace, item); EXPECT_TRUE(item.Status().ok()) << item.Status().what(); - if (i % 100 == 0) currStrValue = RandString(); - if (i % 200 == 0) currIntValue = rand() % 100000; + if (i % 100 == 0) { + currStrValue = RandString(); + } + if (i % 200 == 0) { + currIntValue = rand() % 100000; + } } lastStrValue = currStrValue; @@ -61,7 +65,9 @@ class BtreeIdsetsApi : public ReindexerApi { Upsert(joinedNsName, item); EXPECT_TRUE(item.Status().ok()) << item.Status().what(); - if (i % 300) currValue = rand() % 10000; + if (i % 300) { + currValue = rand() % 10000; + } } Commit(joinedNsName); } diff --git a/cpp_src/gtests/tests/fixtures/equalpositionapi.h b/cpp_src/gtests/tests/fixtures/equalpositionapi.h index a2e3175df..8fe3ce528 100644 --- a/cpp_src/gtests/tests/fixtures/equalpositionapi.h +++ b/cpp_src/gtests/tests/fixtures/equalpositionapi.h @@ -43,7 +43,9 @@ class EqualPositionApi : public ReindexerApi { vec.reserve(length); for (size_t i = 0; i < static_cast(length); ++i) { vec.emplace_back(val); - if (i % multipleCond) val += initVal; + if (i % multipleCond) { + val += initVal; + } } return vec; } diff --git a/cpp_src/gtests/tests/fixtures/ft_api.cc b/cpp_src/gtests/tests/fixtures/ft_api.cc index b3046db17..8db2d3aff 100644 --- a/cpp_src/gtests/tests/fixtures/ft_api.cc +++ b/cpp_src/gtests/tests/fixtures/ft_api.cc @@ -232,7 +232,9 @@ std::vector FTApi::CreateAllPermutatedQueries(const std::string& qu result.push_back(queryStart); std::string& query = result.back(); for (auto it = indexedWords.cbegin(); it != indexedWords.cend(); ++it) { - if (it != indexedWords.cbegin()) query += sep; + if (it != indexedWords.cbegin()) { + query += sep; + } query += it->second; } query += queryEnd; diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/index.cc b/cpp_src/gtests/tests/fixtures/fuzzing/index.cc index 17f7f9c59..1dd3d3888 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/index.cc +++ b/cpp_src/gtests/tests/fixtures/fuzzing/index.cc @@ -47,45 +47,79 @@ reindexer::IndexDef Index::IndexDef(RandomGenerator& rnd, const NsScheme& scheme } void Index::Dump(std::ostream& os, const NsScheme& scheme, size_t offset) const { - for (size_t i = 0; i < offset; ++i) os << " "; + for (size_t i = 0; i < offset; ++i) { + os << " "; + } os << "{\n"; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "name: " << name_ << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "type: " << type_ << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "pk: " << std::boolalpha << isPk_ << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "array: " << std::boolalpha << IsArray() << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "sparse: " << std::boolalpha << (IsSparse() == IsSparseT::Yes) << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } std::visit(reindexer::overloaded{[&](const Child& child) { os << "composite: false\n"; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "field: {\n"; - for (size_t i = 0; i < offset + 2; ++i) os << " "; + for (size_t i = 0; i < offset + 2; ++i) { + os << " "; + } os << "type: " << child.type << '\n'; - for (size_t i = 0; i < offset + 2; ++i) os << " "; + for (size_t i = 0; i < offset + 2; ++i) { + os << " "; + } os << "json: " << scheme.GetJsonPath(child.fieldPath) << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "}\n"; }, [&](const Children& children) { os << "composite: true\n"; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "fields: [\n"; for (const auto& c : children) { - for (size_t i = 0; i < offset + 2; ++i) os << " "; + for (size_t i = 0; i < offset + 2; ++i) { + os << " "; + } os << "{\n"; - for (size_t i = 0; i <= offset + 2; ++i) os << " "; + for (size_t i = 0; i <= offset + 2; ++i) { + os << " "; + } os << "type: " << c.type << '\n'; - for (size_t i = 0; i <= offset + 2; ++i) os << " "; + for (size_t i = 0; i <= offset + 2; ++i) { + os << " "; + } os << "json: " << scheme.GetJsonPath(c.fieldPath) << '\n'; - for (size_t i = 0; i < offset + 2; ++i) os << " "; + for (size_t i = 0; i < offset + 2; ++i) { + os << " "; + } os << "}\n"; } - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "]\n"; }}, content_); diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/ns.cc b/cpp_src/gtests/tests/fixtures/fuzzing/ns.cc index 831653a84..18e2fea0e 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/ns.cc +++ b/cpp_src/gtests/tests/fixtures/fuzzing/ns.cc @@ -8,7 +8,9 @@ struct FieldPathHash { size_t operator()(const fuzzing::FieldPath& fp) const noexcept { constexpr static std::hash hasher; size_t ret = fp.size(); - for (const size_t f : fp) ret = ((ret * 127) ^ (ret >> 3)) ^ hasher(f); + for (const size_t f : fp) { + ret = ((ret * 127) ^ (ret >> 3)) ^ hasher(f); + } return ret; } }; @@ -84,7 +86,9 @@ Ns::Ns(std::string name, RandomGenerator::ErrFactorType errorFactor) } } if (!uniqueName) { - if (!name.empty()) name += '+'; + if (!name.empty()) { + name += '+'; + } name += scheme_.GetJsonPath(fieldData.fieldPath); } containsUuid |= fieldData.type == FieldType::Uuid; @@ -107,10 +111,14 @@ Ns::Ns(std::string name, RandomGenerator::ErrFactorType errorFactor) do { fldPath = rndGen_.RndField(scheme_); } while (!withErr && ++tryCounts < kMaxTries && usedPaths.find(fldPath) != usedPaths.end()); - if (tryCounts >= kMaxTries) continue; + if (tryCounts >= kMaxTries) { + continue; + } usedPaths.insert(fldPath); if (scheme_.IsStruct(fldPath)) { - if (!rndGen_.RndErr()) continue; + if (!rndGen_.RndErr()) { + continue; + } const auto fldType = rndGen_.RndFieldType(); indexes_.emplace_back(rndGen_.IndexName(usedIndexNames), rndGen_.RndIndexType({fldType}), rndGen_.RndBool(0.5) ? IsArrayT::Yes : IsArrayT::No, @@ -185,7 +193,9 @@ void Ns::Dump(std::ostream& os) const { os << "{\n"; scheme_.Dump(os, 1); os << " indexes: [\n"; - for (const auto& i : indexes_) i.Dump(os, scheme_, 2); + for (const auto& i : indexes_) { + i.Dump(os, scheme_, 2); + } os << " ]\n}" << std::endl; } diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/ns_scheme.cc b/cpp_src/gtests/tests/fixtures/fuzzing/ns_scheme.cc index 0a1c92829..24f33278e 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/ns_scheme.cc +++ b/cpp_src/gtests/tests/fixtures/fuzzing/ns_scheme.cc @@ -29,14 +29,18 @@ void NsScheme::NewItem(reindexer::WrSerializer& ser, RandomGenerator& rnd, const } bool NsScheme::IsStruct(const FieldPath& path) const noexcept { - if (path.empty()) return true; + if (path.empty()) { + return true; + } const Node::Children& ref = findLastContainer(path); assertrx(ref.size() > path.back()); return std::holds_alternative(ref[path.back()].content); } bool NsScheme::IsPoint(const FieldPath& path) const noexcept { - if (path.empty()) return false; + if (path.empty()) { + return false; + } const Node::Children& ref = findLastContainer(path); assertrx(ref.size() > path.back()); return !std::holds_alternative(ref[path.back()].content) && @@ -54,7 +58,9 @@ bool NsScheme::isTtl(const std::vector& idxNumbers, const std::vector& indexes) const noexcept { - if (path.empty()) return false; + if (path.empty()) { + return false; + } const Node::Children& ref = findLastContainer(path); assertrx(ref.size() > path.back()); if (std::holds_alternative(ref[path.back()].content)) { @@ -78,12 +84,16 @@ size_t NsScheme::FieldsCount(const FieldPath& path) const noexcept { } IsArrayT NsScheme::IsArray(const FieldPath& path) const noexcept { - if (path.empty()) return ns_.array; + if (path.empty()) { + return ns_.array; + } const Node::Children* ptr = &std::get(ns_.content); for (size_t i = 0, s = path.size() - 1; i < s; ++i) { assertrx(ptr->size() > path[i]); const auto& idx = (*ptr)[path[i]]; - if (idx.array == IsArrayT::Yes) return IsArrayT::Yes; + if (idx.array == IsArrayT::Yes) { + return IsArrayT::Yes; + } std::visit( reindexer::overloaded{[&ptr](const Node::Children& c) noexcept { ptr = &c; }, [](const Node::Child&) noexcept { assertrx(0); }}, idx.content); @@ -110,7 +120,9 @@ void NsScheme::SetFieldType(const FieldPath& path, FieldType ft) noexcept { } std::string NsScheme::GetJsonPath(const FieldPath& path) const noexcept { - if (path.empty()) return {}; + if (path.empty()) { + return {}; + } std::string res; const Node::Children* ptr = &std::get(ns_.content); for (size_t i = 0, s = path.size() - 1; i < s; ++i) { @@ -255,7 +267,9 @@ void NsScheme::rndValueToJson(reindexer::JsonBuilder& builder, FieldType ft, std void NsScheme::toJson(reindexer::JsonBuilder& builder, const Node::Children& children, RandomGenerator& rnd, const std::vector& indexes) { for (const Node& n : children) { - if (!rnd.NeedThisNode(n.sparse)) continue; + if (!rnd.NeedThisNode(n.sparse)) { + continue; + } if (rnd.RndArrayField(n.array) == IsArrayT::Yes) { auto arr = builder.Array(n.name); const size_t arrSize = rnd.ArraySize(); @@ -289,27 +303,45 @@ void NsScheme::toJson(reindexer::JsonBuilder& builder, const Node::Children& chi } void NsScheme::Node::Dump(std::ostream& os, size_t offset) const { - for (size_t i = 0; i < offset; ++i) os << " "; + for (size_t i = 0; i < offset; ++i) { + os << " "; + } os << "{\n"; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "name: " << name << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "sparse: " << std::boolalpha << (sparse == IsSparseT::Yes) << '\n'; - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "array: " << std::boolalpha << (array == IsArrayT::Yes) << '\n'; std::visit(reindexer::overloaded{[&](const Child& child) { - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "type: " << child.type << '\n'; }, [&](const Children& children) { - for (size_t i = 0; i <= offset; ++i) os << " "; + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "fields: [\n"; - for (const Node& n : children) n.Dump(os, offset + 2); - for (size_t i = 0; i <= offset; ++i) os << " "; + for (const Node& n : children) { + n.Dump(os, offset + 2); + } + for (size_t i = 0; i <= offset; ++i) { + os << " "; + } os << "]\n"; }}, content); - for (size_t i = 0; i < offset; ++i) os << " "; + for (size_t i = 0; i < offset; ++i) { + os << " "; + } os << "}\n"; } diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/query_generator.cc b/cpp_src/gtests/tests/fixtures/fuzzing/query_generator.cc index da0f1d081..f796ccc4e 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/query_generator.cc +++ b/cpp_src/gtests/tests/fixtures/fuzzing/query_generator.cc @@ -20,7 +20,9 @@ reindexer::Query QueryGenerator::operator()() { [&](const Index::Children& c) { std::vector types; types.reserve(c.size()); - for (const auto& child : c) types.push_back(child.type); + for (const auto& child : c) { + types.push_back(child.type); + } rndGen_.RndWhereComposite(query, idx.Name(), std::move(types), idx.Type()); }}, idx.Content()); diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.cc b/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.cc index 17fcd70b9..fc429300e 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.cc +++ b/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.cc @@ -137,7 +137,9 @@ std::string RandomGenerator::FieldName(std::unordered_set& generate case Printable: for (size_t i = 0; i < len;) { res[i] = rndChar_(gen_); - if (true) ++i; // TODO + if (true) { + ++i; // TODO + } } break; case Available: @@ -199,7 +201,9 @@ FieldPath RandomGenerator::RndField(const NsScheme& nsScheme) { } } const auto size = nsScheme.FieldsCount(res); - if (size == 0) return res; + if (size == 0) { + return res; + } const int idx = RndInt(0, size - 1); res.push_back(idx); } while (nsScheme.IsStruct(res)); @@ -222,16 +226,22 @@ FieldPath RandomGenerator::RndScalarField(const NsScheme& nsScheme) { } } const auto size = nsScheme.FieldsCount(res); - if (size == 0) return res; + if (size == 0) { + return res; + } int idx = RndInt(0, size - 1); res.push_back(idx); const int end = idx + size; while (idx < end) { res.back() = idx % size; - if (nsScheme.IsArray(res) == IsArrayT::No && !nsScheme.IsPoint(res)) break; + if (nsScheme.IsArray(res) == IsArrayT::No && !nsScheme.IsPoint(res)) { + break; + } ++idx; } - if (idx == end) return {}; + if (idx == end) { + return {}; + } } while (nsScheme.IsStruct(res)); return res; } @@ -311,7 +321,9 @@ IndexType RandomGenerator::RndPkIndexType(const std::vector& fieldTyp } size_t RandomGenerator::ArraySize() { - if (RndErr()) return RndInt(0, 100'000); + if (RndErr()) { + return RndInt(0, 100'000); + } enum Size : uint8_t { Short, Normal, Long, VeryLong, END = VeryLong }; switch (RndWhich()) { case Short: diff --git a/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.h b/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.h index bebb70490..f4819ae62 100644 --- a/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.h +++ b/cpp_src/gtests/tests/fixtures/fuzzing/random_generator.h @@ -83,7 +83,9 @@ class RandomGenerator { std::vector RndFieldsForCompositeIndex(const std::vector& scalarIndexes); std::string FieldName(std::unordered_set& generatedNames); std::string FieldName(const std::string& fieldName, std::unordered_set& generatedNames) { - if (RndErr()) return FieldName(generatedNames); + if (RndErr()) { + return FieldName(generatedNames); + } return fieldName; } FieldPath RndField(const NsScheme&); @@ -94,7 +96,9 @@ class RandomGenerator { return FieldName(generatedNames); } std::string NsName(const std::string& nsName) { - if (RndErr()) return GenerateNsName(); + if (RndErr()) { + return GenerateNsName(); + } return nsName; } int RndInt(int min, int max) { return rndInt_(gen_, IntRndParams(min, max)); } @@ -198,7 +202,9 @@ class RandomGenerator { assertrx(false); std::abort(); } - for (char& ch : res) ch = availableChars[rndInt(availableRndParams)]; // TODO + for (char& ch : res) { + ch = availableChars[rndInt(availableRndParams)]; // TODO + } return res; } std::string RndStrUuidValue() { return rndStrUuidValue(false); } diff --git a/cpp_src/gtests/tests/fixtures/get_pk_api.h b/cpp_src/gtests/tests/fixtures/get_pk_api.h index 29e7ad876..703a729eb 100644 --- a/cpp_src/gtests/tests/fixtures/get_pk_api.h +++ b/cpp_src/gtests/tests/fixtures/get_pk_api.h @@ -42,11 +42,15 @@ class ExtractPK : public testing::Test { public: Error CreateNamespace(const NamespaceDef& nsDef) { Error err = db_->OpenNamespace(nsDef.name); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } for (const auto& index : nsDef.indexes) { err = db_->AddIndex(nsDef.name, index); - if (!err.ok()) break; + if (!err.ok()) { + break; + } } return err; @@ -54,7 +58,9 @@ class ExtractPK : public testing::Test { Error UpsertAndCommit(const string& ns, Item& item) { Error err = db_->Upsert(ns, item); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } return db_->Commit(ns); } @@ -63,7 +69,9 @@ class ExtractPK : public testing::Test { typedef std::tuple ResultType; Item item = db_->NewItem(ns); - if (!item.Status().ok()) return ResultType(item.Status(), std::move(item), Data{0, 0, nullptr, nullptr, 0, 0}); + if (!item.Status().ok()) { + return ResultType(item.Status(), std::move(item), Data{0, 0, nullptr, nullptr, 0, 0}); + } Data data = (d == nullptr) ? randomItemData() : *d; std::string json = StringFormat(jsonPattern, data.id, data.name, data.color, data.weight, data.height, data.fk_id); @@ -88,9 +96,13 @@ class ExtractPK : public testing::Test { QueryResults qres; Error err = db_->Select(query, qres); - if (!err.ok()) return ResultType(err, QueryResults{}); + if (!err.ok()) { + return ResultType(err, QueryResults{}); + } - if (print) printQueryResults(query.NsName(), qres); + if (print) { + printQueryResults(query.NsName(), qres); + } return ResultType(err, std::move(qres)); } diff --git a/cpp_src/gtests/tests/fixtures/grpcclient_api.h b/cpp_src/gtests/tests/fixtures/grpcclient_api.h index d8ce17632..fc839a091 100644 --- a/cpp_src/gtests/tests/fixtures/grpcclient_api.h +++ b/cpp_src/gtests/tests/fixtures/grpcclient_api.h @@ -10,8 +10,8 @@ #include "core/cjson/cjsondecoder.h" #include "core/cjson/jsonbuilder.h" #include "core/payload/payloadiface.h" -#include "server/server.h" #include "reindexer_api.h" +#include "server/server.h" #include "tools/fsops.h" #include "yaml-cpp/yaml.h" diff --git a/cpp_src/gtests/tests/fixtures/item_move_semantics_api.h b/cpp_src/gtests/tests/fixtures/item_move_semantics_api.h index ba10e1784..e60acac2f 100644 --- a/cpp_src/gtests/tests/fixtures/item_move_semantics_api.h +++ b/cpp_src/gtests/tests/fixtures/item_move_semantics_api.h @@ -10,7 +10,7 @@ class ItemMoveSemanticsApi : public ReindexerApi { protected: const std::string pkField = "bookid"; const int32_t itemsCount = 100000; - const char *jsonPattern = "{\"bookid\":%d,\"title\":\"title\",\"pages\":200,\"price\":299,\"genreid_fk\":3,\"authorid_fk\":10}"; + const char* jsonPattern = "{\"bookid\":%d,\"title\":\"title\",\"pages\":200,\"price\":299,\"genreid_fk\":3,\"authorid_fk\":10}"; std::map items_; void SetUp() override { @@ -47,8 +47,8 @@ class ItemMoveSemanticsApi : public ReindexerApi { } void verifyAndUpsertItems() { - for (auto &pair : items_) { - auto &&item = pair.second; + for (auto& pair : items_) { + auto&& item = pair.second; Error err = rt.reindexer->Upsert(default_namespace, item); ASSERT_TRUE(err.ok()) << err.what(); ASSERT_NO_THROW(gason::JsonParser().Parse(item.GetJSON())); @@ -62,7 +62,7 @@ class ItemMoveSemanticsApi : public ReindexerApi { if (itItem == items_.end()) { return Item(); } - auto &&item = itItem->second; + auto&& item = itItem->second; return std::move(item); } diff --git a/cpp_src/gtests/tests/fixtures/join_selects_api.h b/cpp_src/gtests/tests/fixtures/join_selects_api.h index d4be1cd89..b58ed111d 100644 --- a/cpp_src/gtests/tests/fixtures/join_selects_api.h +++ b/cpp_src/gtests/tests/fixtures/join_selects_api.h @@ -154,7 +154,9 @@ class JoinSelectsApi : public ReindexerApi { { reindexer::shared_lock lck(authorsMutex); - if (i % 4 == 0) authorIdIdx = rand() % authorsIds.size(); + if (i % 4 == 0) { + authorIdIdx = rand() % authorsIds.size(); + } } } @@ -214,7 +216,9 @@ class JoinSelectsApi : public ReindexerApi { for (auto& qr : queryRes) { wrSer.Reset(); err = qr.GetJSON(wrSer, false); - if (!err.ok()) break; + if (!err.ok()) { + break; + } gason::JsonParser().Parse(reindexer::giftStr(wrSer.Slice())); } } catch (const gason::Exception& ex) { @@ -238,7 +242,9 @@ class JoinSelectsApi : public ReindexerApi { } std::cout << std::endl; ++idx; - if (itemIt.getJoinedFieldsCount() > 1) std::cout << std::endl; + if (itemIt.getJoinedFieldsCount() > 1) { + std::cout << std::endl; + } } } } @@ -264,7 +270,9 @@ class JoinSelectsApi : public ReindexerApi { bool CompareQueriesResults(QueryResultRows& lhs, QueryResultRows& rhs) { EXPECT_EQ(lhs.size(), rhs.size()) << "Two queries results have different size!"; - if (lhs.size() != rhs.size()) return false; + if (lhs.size() != rhs.size()) { + return false; + } for (auto it = lhs.begin(); it != lhs.end(); ++it) { const BookId& bookId(it->first); @@ -282,11 +290,13 @@ class JoinSelectsApi : public ReindexerApi { const reindexer::VariantArray& fieldVal1(it2->second); const reindexer::VariantArray& fieldVal2(itFieldValue->second); EXPECT_TRUE(fieldVal1 == fieldVal2) << "Fields " << fieldName << " have different values!"; - } else + } else { return false; + } } - } else + } else { return false; + } } return true; diff --git a/cpp_src/gtests/tests/fixtures/ns_api.h b/cpp_src/gtests/tests/fixtures/ns_api.h index a31d2b3ef..b3debfda3 100644 --- a/cpp_src/gtests/tests/fixtures/ns_api.h +++ b/cpp_src/gtests/tests/fixtures/ns_api.h @@ -45,11 +45,14 @@ class NsApi : public ReindexerApi { const char jsonPattern[] = R"json({"id": %s, "int_field":1, + "int_field2":88, "indexed_array_field": [11,22,33,44,55,66,77,88,99], "objects":[{"more":[{"array":[9,8,7,6,5]},{"array":[4,3,2,1,0]}]}], "":{"empty_obj_field":"not empty"}, "array_field": [1,2,3], "string_array":["first", "second", "third"], + "bool_array":[true, false], + "bool_array2":[false, true], "extra" : "%s", "sparse_field": %ld, "nested":{ @@ -144,7 +147,9 @@ class NsApi : public ReindexerApi { IndexDeclaration{"ft21+ft22+ft23=ft24", "text", "composite", IndexOpts(), 0}}); static constexpr int itemsCount = 1000; - for (int i = 0; i < itemsCount; ++i) InsertNewTruncateItem(i); + for (int i = 0; i < itemsCount; ++i) { + InsertNewTruncateItem(i); + } const static Query q{truncate_namespace}; QueryResults qr1; diff --git a/cpp_src/gtests/tests/fixtures/queries_api.cc b/cpp_src/gtests/tests/fixtures/queries_api.cc index ba1749a22..09eec45c4 100644 --- a/cpp_src/gtests/tests/fixtures/queries_api.cc +++ b/cpp_src/gtests/tests/fixtures/queries_api.cc @@ -683,181 +683,171 @@ void QueriesApi::CheckStandartQueries() { [[maybe_unused]] const int randomGenreUpper = rand() % 100; [[maybe_unused]] const int randomGenreLower = rand() % 100; - ExecuteAndVerify(Query(default_namespace).Distinct(distinct.c_str()).Sort(sortIdx, sortOrder).Limit(1)); + ExecuteAndVerify(Query(default_namespace).Distinct(distinct).Sort(sortIdx, sortOrder).Limit(1)); - ExecuteAndVerify(Query(default_namespace) - .Where(kFieldNameGenre, CondEq, randomGenre) - .Distinct(distinct.c_str()) - .Sort(sortIdx, sortOrder)); + ExecuteAndVerify( + Query(default_namespace).Where(kFieldNameGenre, CondEq, randomGenre).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameGenre, CondEq, std::to_string(randomGenre)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); - ExecuteAndVerify(Query(default_namespace) - .Where(kFieldNameName, CondEq, RandString()) - .Distinct(distinct.c_str()) - .Sort(sortIdx, sortOrder)); + ExecuteAndVerify( + Query(default_namespace).Where(kFieldNameName, CondEq, RandString()).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondEq, (rand() % 100) / 10.0) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondEq, std::to_string((rand() % 100) / 10.0)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameGenre, CondGt, randomGenre) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace)); - ExecuteAndVerify(Query(default_namespace) - .Where(kFieldNameName, CondGt, RandString()) - .Distinct(distinct.c_str()) - .Sort(sortIdx, sortOrder)); + ExecuteAndVerify( + Query(default_namespace).Where(kFieldNameName, CondGt, RandString()).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondGt, (rand() % 100) / 10.0) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); - ExecuteAndVerify(Query(default_namespace) - .Where(kFieldNameGenre, CondLt, randomGenre) - .Distinct(distinct.c_str()) - .Sort(sortIdx, sortOrder)); + ExecuteAndVerify( + Query(default_namespace).Where(kFieldNameGenre, CondLt, randomGenre).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameGenre, CondLt, std::to_string(randomGenre)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); - ExecuteAndVerify(Query(default_namespace) - .Where(kFieldNameName, CondLt, RandString()) - .Distinct(distinct.c_str()) - .Sort(sortIdx, sortOrder)); + ExecuteAndVerify( + Query(default_namespace).Where(kFieldNameName, CondLt, RandString()).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondLt, (rand() % 100) / 10.0) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondLt, std::to_string((rand() % 100) / 10.0)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameBtreeIdsets, CondLt, static_cast(rand() % 10000)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameBtreeIdsets, CondGt, static_cast(rand() % 10000)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameBtreeIdsets, CondEq, static_cast(rand() % 10000)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameGenre, CondRange, {randomGenreLower, randomGenreUpper}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameName, CondRange, {RandString(), RandString()}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameName, CondLike, RandLikePattern()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameRate, CondRange, {static_cast(rand() % 100) / 10, static_cast(rand() % 100) / 10}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNamePackages, CondSet, RandIntVector(10, 10000, 50)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNamePackages, CondAllSet, RandIntVector(2, 10000, 50)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNamePackages, CondAllSet, 10000 + rand() % 50) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); // check substituteCompositIndexes ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondEq, randomAge) .Where(kFieldNameGenre, CondEq, randomGenre) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondSet, RandIntVector(10, 0, 50)) .Where(kFieldNameGenre, CondEq, randomGenre) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondAllSet, RandIntVector(1, 0, 50)) .Where(kFieldNameGenre, CondEq, randomGenre) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondSet, RandIntVector(10, 0, 50)) .Where(kFieldNameGenre, CondSet, RandIntVector(10, 0, 50)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondSet, RandIntVector(10, 0, 20)) .Where(kFieldNameGenre, CondSet, RandIntVector(10, 0, 50)) .Where(kFieldNameAge, CondSet, RandIntVector(10, 30, 50)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameAge, CondSet, RandIntVector(10, 0, 20)) .Where(kFieldNameGenre, CondEq, randomGenre) .Where(kFieldNameAge, CondSet, RandIntVector(10, 30, 50)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); // end of check substituteCompositIndexes ExecuteAndVerify(Query(default_namespace) .Where(kFieldNamePackages, CondEmpty, VariantArray{}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameName, CondRange, {RandString(), RandString()}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(kFieldNameYear, true) .Sort(kFieldNameName, false) .Sort(kFieldNameLocation, true)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameName, CondRange, {RandString(), RandString()}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(kFieldNameGenre, true) .Sort(kFieldNameActor, false) .Sort(kFieldNameRate, true) @@ -865,7 +855,7 @@ void QueriesApi::CheckStandartQueries() { ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameName, CondLike, RandLikePattern()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(kFieldNameGenre, true) .Sort(kFieldNameActor, false) .Sort(kFieldNameRate, true) @@ -875,14 +865,14 @@ void QueriesApi::CheckStandartQueries() { ExecuteAndVerify(Query(default_namespace) .Where(kFieldNamePackages, CondAny, VariantArray{}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( - Query(default_namespace).Where(kFieldNameIsDeleted, CondEq, 1).Distinct(distinct.c_str()).Sort(sortIdx, sortOrder)); + Query(default_namespace).Where(kFieldNameIsDeleted, CondEq, 1).Distinct(distinct).Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Where(kFieldNameGenre, CondEq, 5) .Where(kFieldNameAge, CondEq, 3) @@ -891,7 +881,7 @@ void QueriesApi::CheckStandartQueries() { .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -905,7 +895,7 @@ void QueriesApi::CheckStandartQueries() { .Where(kFieldNameYear, CondGe, 2010)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameYear, CondGt, 2002) @@ -918,7 +908,7 @@ void QueriesApi::CheckStandartQueries() { .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameAge, CondSet, {1, 2, 3, 4}) @@ -930,7 +920,7 @@ void QueriesApi::CheckStandartQueries() { .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondSet, {5, 1, 7}) @@ -942,7 +932,7 @@ void QueriesApi::CheckStandartQueries() { .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondSet, {5, 1, 7}) @@ -953,7 +943,7 @@ void QueriesApi::CheckStandartQueries() { .Debug(LogTrace)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -963,7 +953,7 @@ void QueriesApi::CheckStandartQueries() { .Where(kFieldNamePackages, CondSet, RandIntVector(5, 10000, 50))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -974,13 +964,13 @@ void QueriesApi::CheckStandartQueries() { .Where(kFieldNamePackages, CondSet, RandIntVector(5, 10000, 50))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameActor, CondEq, RandString())); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Not() @@ -989,7 +979,7 @@ void QueriesApi::CheckStandartQueries() { .Where(kFieldNamePackages, CondSet, RandIntVector(5, 10000, 50))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -998,26 +988,26 @@ void QueriesApi::CheckStandartQueries() { .Where(kFieldNamePackages, CondSet, RandIntVector(5, 10000, 50))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Not() .Where(kFieldNameYear, CondEq, 10)); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(kFieldNameNumeric, sortOrder) .Debug(LogTrace) .Where(kFieldNameNumeric, CondGt, std::to_string(5))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(kFieldNameNumeric, sortOrder) .Debug(LogTrace) .Where(kFieldNameNumeric, CondLt, std::to_string(600))); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -1040,7 +1030,7 @@ void QueriesApi::CheckStandartQueries() { .CloseBracket()); ExecuteAndVerify(Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -1065,7 +1055,7 @@ void QueriesApi::CheckStandartQueries() { ExecuteAndVerify( Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameNumeric, CondRange, {std::to_string(rand() % 100), std::to_string(rand() % 100 + 500)})); @@ -1146,6 +1136,29 @@ void QueriesApi::CheckStandartQueries() { .InnerJoin(kFieldNameYear, kFieldNameYear, randCond(), Query(joinNs).Where(kFieldNameYear, CondLt, 2000 + rand() % 210).Sort(kFieldNameName, sortOrder)) .Distinct(distinct)); + + ExecuteAndVerify(Query(default_namespace) + .InnerJoin(kFieldNameId, kFieldNameId, CondEq, + Query(joinNs) + .Where(kFieldNameRegion, CondSet, + {Variant{rand() % 10}, Variant{rand() % 10}, Variant{rand() % 10}, + Variant{rand() % 10}, Variant{rand() % 10}}) + .Where(kFieldNameYear, CondLt, 2000 + rand() % 210) + .Where(kFieldNameAge, CondGe, rand() % 30) + .Sort(kFieldNameAge, sortOrder) + .Limit(3)) + .Distinct(distinct)); + ExecuteAndVerify(Query(default_namespace) + .InnerJoin(kFieldNameId, kFieldNameId, CondEq, + Query(joinNs) + .Where(kFieldNameRegion, CondSet, + {Variant{rand() % 10}, Variant{rand() % 10}, Variant{rand() % 10}, + Variant{rand() % 10}, Variant{rand() % 10}}) + .Where(kFieldNameYear, CondLt, 2000 + rand() % 210) + .Where(kFieldNameAge, CondGe, rand() % 30) + .Sort(kFieldNameYear, sortOrder) + .Limit(3)) + .Distinct(distinct)); ExecuteAndVerify(Query(default_namespace) .Join(InnerJoin, Query(joinNs).Where(kFieldNameYear, CondGt, 2000 + rand() % 210)) .OpenBracket() @@ -1434,33 +1447,33 @@ void QueriesApi::CheckStandartQueries() { if (argsCount.min <= 1 && argsCount.max >= 1) { ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuid, cond, randUuid()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuid, cond, randStrUuid()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuidArr, cond, randUuid()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuidArr, cond, randStrUuid()) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); } ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuid, cond, randHeterogeneousUuidArray(argsCount.min, argsCount.max)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuidArr, cond, randHeterogeneousUuidArray(argsCount.min, argsCount.max)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); std::vector compositeKeyValues; @@ -1471,75 +1484,75 @@ void QueriesApi::CheckStandartQueries() { [this](Variant&& uuid) { return VariantArray::Create(std::move(uuid), RandString()); }); ExecuteAndVerify(Query(default_namespace) .WhereComposite(kCompositeFieldUuidName, cond, compositeKeyValues) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); } ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuid, CondRange, randHeterogeneousUuidArray(2, 2)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameUuidArr, CondRange, randHeterogeneousUuidArray(2, 2)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( Query(default_namespace) .WhereComposite(kCompositeFieldUuidName, CondRange, {VariantArray::Create(nilUuid(), RandString()), VariantArray::Create(randUuid(), RandString())}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(Query(default_namespace).Where(kFieldNameId, CondEq, 10), CondAny, {}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Not() .Where(Query(default_namespace), CondEmpty, {}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameId, CondLt, Query(default_namespace).Aggregate(AggAvg, {kFieldNameId})) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(kFieldNameGenre, CondSet, Query(joinNs).Select({kFieldNameGenre}).Where(kFieldNameId, CondSet, {10, 20, 30, 40})) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( Query(default_namespace) .Where(Query(joinNs).Select({kFieldNameGenre}).Where(kFieldNameId, CondGt, 10), CondSet, {10, 20, 30, 40}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(Query(joinNs).Select({kFieldNameGenre}).Where(kFieldNameId, CondGt, 10).Offset(1), CondSet, {10, 20, 30, 40}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( Query(default_namespace) .Where(Query(joinNs).Where(kFieldNameId, CondGt, 10).Aggregate(AggMax, {kFieldNameGenre}), CondRange, {48, 50}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(Query(joinNs).Where(kFieldNameId, CondGt, 10).ReqTotal(), CondGt, {50}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( Query(default_namespace) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder) .Debug(LogTrace) .Where(kFieldNameGenre, CondEq, 5) @@ -1576,14 +1589,14 @@ void QueriesApi::CheckStandartQueries() { ExecuteAndVerify(Query(default_namespace) .Where(kCompositeFieldIdTemp, CondEq, Query(default_namespace).Select({kCompositeFieldIdTemp}).Where(kFieldNameId, CondGt, 10)) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify( Query(default_namespace) .Where(Query(default_namespace).Select({kCompositeFieldUuidName}).Where(kFieldNameId, CondGt, 10), CondRange, {VariantArray::Create(nilUuid(), RandString()), VariantArray::Create(randUuid(), RandString())}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) @@ -1593,17 +1606,17 @@ void QueriesApi::CheckStandartQueries() { .Sort(kCompositeFieldAgeGenre, false) .Limit(10), CondLe, {Variant(VariantArray::Create(rand() % 50, rand() % 50))}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(Query(default_namespace).Where(kFieldNameId, CondGt, 10).ReqTotal(), CondGe, {10}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); ExecuteAndVerify(Query(default_namespace) .Where(Query(default_namespace).Where(kFieldNameId, CondGt, 10).CachedTotal(), CondGe, {10}) - .Distinct(distinct.c_str()) + .Distinct(distinct) .Sort(sortIdx, sortOrder)); } } diff --git a/cpp_src/gtests/tests/fixtures/queries_api.h b/cpp_src/gtests/tests/fixtures/queries_api.h index 64e2a99e1..4c01e758f 100644 --- a/cpp_src/gtests/tests/fixtures/queries_api.h +++ b/cpp_src/gtests/tests/fixtures/queries_api.h @@ -99,13 +99,15 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { IndexDeclaration{kFieldNameAge, "tree", "int", IndexOpts(), 0}, IndexDeclaration{kFieldNameName, "tree", "string", IndexOpts(), 0}, IndexDeclaration{kFieldNameDescription, "text", "string", IndexOpts{}, 0}, - IndexDeclaration{kFieldNameYearSparse, "hash", "string", IndexOpts().Sparse(), 0}}); + IndexDeclaration{kFieldNameYearSparse, "hash", "string", IndexOpts().Sparse(), 0}, + IndexDeclaration{kFieldNameRegion, "hash", "int", IndexOpts{}, 0}}); addIndexFields(joinNs, kFieldNameId, {{kFieldNameId, reindexer::KeyValueType::Int{}}}); addIndexFields(joinNs, kFieldNameYear, {{kFieldNameYear, reindexer::KeyValueType::Int{}}}); addIndexFields(joinNs, kFieldNameAge, {{kFieldNameAge, reindexer::KeyValueType::Int{}}}); addIndexFields(joinNs, kFieldNameName, {{kFieldNameName, reindexer::KeyValueType::String{}}}); addIndexFields(joinNs, kFieldNameDescription, {{kFieldNameDescription, reindexer::KeyValueType::String{}}}); addIndexFields(joinNs, kFieldNameYearSparse, {{kFieldNameYearSparse, reindexer::KeyValueType::String{}}}); + addIndexFields(joinNs, kFieldNameRegion, {{kFieldNameRegion, reindexer::KeyValueType::Int{}}}); err = rt.reindexer->OpenNamespace(testSimpleNs); ASSERT_TRUE(err.ok()) << err.what(); @@ -283,12 +285,16 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { if (ser.Len()) { ser << "\nExpected values:\n"; for (size_t i = 0; i < expectedValues.size(); ++i) { - if (i != 0) ser << ", "; + if (i != 0) { + ser << ", "; + } expectedValues[i].Dump(ser); } ser << "\nObtained values:\n"; for (size_t i = 0; i < qr.Count(); ++i) { - if (i != 0) ser << ", "; + if (i != 0) { + ser << ", "; + } reindexer::Item item(qr[i].GetItem(false)); const reindexer::Variant fieldValue = item[fieldName]; fieldValue.Dump(ser); @@ -345,8 +351,8 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { Commit(forcedSortOffsetNs); } - void FillTestJoinNamespace() { - for (int i = 0; i < 300; ++i) { + void FillTestJoinNamespace(int start, int count) { + for (int i = start; i < start + count; ++i) { Item item = NewItem(joinNs); item[kFieldNameId] = i; item[kFieldNameYear] = 1900 + i; @@ -357,6 +363,7 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { if (rand() % 4 != 0) { item[kFieldNameYearSparse] = std::to_string(rand() % 50 + 2000); } + item[kFieldNameRegion] = rand() % 10; Upsert(joinNs, item); saveItem(std::move(item), joinNs); } @@ -436,7 +443,9 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { std::vector ForcedSortOffsetTestExpectedResults(size_t offset, size_t limit, bool desc, const std::vector& forcedSortOrder, Column column) const { - if (limit == 0 || offset >= forcedSortOffsetValues.size()) return {}; + if (limit == 0 || offset >= forcedSortOffsetValues.size()) { + return {}; + } std::vector res; res.resize(forcedSortOffsetValues.size()); std::transform( @@ -464,7 +473,9 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { bool desc2Column, const std::vector& forcedSortOrder, Column firstSortColumn) { - if (limit == 0 || offset >= forcedSortOffsetValues.size()) return {}; + if (limit == 0 || offset >= forcedSortOffsetValues.size()) { + return {}; + } if (firstSortColumn == First) { std::sort(forcedSortOffsetValues.begin(), forcedSortOffsetValues.end(), [desc1Column, desc2Column](std::pair lhs, std::pair rhs) { @@ -581,7 +592,9 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { std::vector RandStrVector(size_t count) { std::vector res; res.reserve(count); - for (size_t i = 0; i < count; ++i) res.emplace_back(RandString()); + for (size_t i = 0; i < count; ++i) { + res.emplace_back(RandString()); + } return res; } @@ -618,13 +631,17 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { item[kFieldNameUuid] = randUuid(); std::vector arr; arr.reserve(s); - for (size_t i = 0; i < s; ++i) arr.emplace_back(randUuid()); + for (size_t i = 0; i < s; ++i) { + arr.emplace_back(randUuid()); + } item[kFieldNameUuidArr] = std::move(arr); } else { item[kFieldNameUuid] = randStrUuid(); std::vector arr; arr.reserve(s); - for (size_t i = 0; i < s; ++i) arr.emplace_back(randStrUuid()); + for (size_t i = 0; i < s; ++i) { + arr.emplace_back(randStrUuid()); + } item[kFieldNameUuidArr] = std::move(arr); } @@ -922,7 +939,9 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { std::string name; int year; bool operator<(const MultifieldFacetItem& other) const { - if (year == other.year) return name < other.name; + if (year == other.year) { + return name < other.name; + } return year > other.year; } }; @@ -1158,6 +1177,7 @@ class QueriesApi : public ReindexerApi, public QueriesVerifier { const char* kFieldNameCountries = "countries"; const char* kFieldNameAge = "age"; const char* kFieldNameDescription = "description"; + const char* kFieldNameRegion = "region"; const char* kFieldNameRate = "rate"; const char* kFieldNameIsDeleted = "is_deleted"; const char* kFieldNameActor = "actor"; diff --git a/cpp_src/gtests/tests/fixtures/queries_verifier.h b/cpp_src/gtests/tests/fixtures/queries_verifier.h index bdc231aa5..945ac0384 100644 --- a/cpp_src/gtests/tests/fixtures/queries_verifier.h +++ b/cpp_src/gtests/tests/fixtures/queries_verifier.h @@ -25,7 +25,9 @@ class QueriesVerifier : public virtual ::testing::Test { struct PkHash { size_t operator()(const std::vector pk) const noexcept { size_t ret = pk.size(); - for (const auto& k : pk) ret = ((ret * 127) ^ (ret >> 3)) ^ k.Hash(); + for (const auto& k : pk) { + ret = ((ret * 127) ^ (ret >> 3)) ^ k.Hash(); + } return ret; } }; @@ -230,15 +232,21 @@ class QueriesVerifier : public virtual ::testing::Test { // Check non found items, to not match conditions // If query has limit and offset, skip verification - if (query.HasOffset() || query.HasLimit()) return; + if (query.HasOffset() || query.HasLimit()) { + return; + } // If query has distinct, skip verification for (const auto& agg : query.aggregations_) { - if (agg.Type() == AggDistinct) return; + if (agg.Type() == AggDistinct) { + return; + } } for (auto& insertedItem : insertedItems_[query.NsName()]) { - if (pks.find(insertedItem.first) != pks.end()) continue; + if (pks.find(insertedItem.first) != pks.end()) { + continue; + } bool conditionsSatisfied = checkConditions(insertedItem.second, query.Entries().cbegin(), query.Entries().cend(), joinedSelectors, indexesFields); @@ -280,7 +288,9 @@ class QueriesVerifier : public virtual ::testing::Test { auto& ii = insertedItems_[ns]; const auto it = ii.find(pk); if (it == ii.end()) { - for (auto& p : pk) p.EnsureHold(); + for (auto& p : pk) { + p.EnsureHold(); + } [[maybe_unused]] const auto res = ii.emplace(std::move(pk), std::move(item)); assertrx(res.second); } else { @@ -324,9 +334,11 @@ class QueriesVerifier : public virtual ::testing::Test { bool result = true; for (; it != to; ++it) { OpType op = it->operation; - if (op != OpOr && !result) return false; + if (op != OpOr && !result) { + return false; + } bool skip = false; - bool const iterationResult = it->Visit( + const bool iterationResult = it->Visit( [](const reindexer::SubQueryEntry&) -> bool { assertrx(0); std::abort(); @@ -367,7 +379,9 @@ class QueriesVerifier : public virtual ::testing::Test { return checkCondition(item, qe, indexesFields); }, [](const reindexer::AlwaysFalse&) noexcept { return false; }, [](const reindexer::AlwaysTrue&) noexcept { return true; }); - if (skip) continue; + if (skip) { + continue; + } switch (op) { case OpNot: result = !iterationResult; @@ -399,14 +413,20 @@ class QueriesVerifier : public virtual ::testing::Test { bool result = true; // check only on root level for (auto it = qr.Entries().cbegin(); it != qr.Entries().cend(); ++it) { - if (!it->Is()) continue; + if (!it->Is()) { + continue; + } const reindexer::QueryEntry& qentry = it->Value(); - if (!qentry.Distinct()) continue; + if (!qentry.Distinct()) { + continue; + } const std::string fieldName = getFieldName(qentry.FieldName(), indexesFields); reindexer::VariantArray fieldValue = item[fieldName]; EXPECT_EQ(fieldValue.size(), 1) << "Distinct field's size cannot be > 1"; - if (fieldValue.empty()) return false; + if (fieldValue.empty()) { + return false; + } std::unordered_set& values = distincts[fieldName]; reindexer::Variant keyValue(fieldValue[0]); @@ -428,7 +448,9 @@ class QueriesVerifier : public virtual ::testing::Test { assertrx(joinEntries[0].Operation() != OpOr); for (const auto& je : joinEntries) { if (je.Operation() == OpOr) { - if (result) continue; + if (result) { + continue; + } } else if (!result) { break; } @@ -448,7 +470,9 @@ class QueriesVerifier : public virtual ::testing::Test { assertrx(0); } } - if (result) return true; + if (result) { + return true; + } } return false; } @@ -522,7 +546,9 @@ class QueriesVerifier : public virtual ::testing::Test { static bool checkGeomConditions(const reindexer::Item& item, const reindexer::QueryEntry& qentry, const IndexesData& indexesFields) { assertrx(qentry.Values().size() == 2); const reindexer::VariantArray coordinates = item[getFieldName(qentry.FieldName(), indexesFields)]; - if (coordinates.empty()) return false; + if (coordinates.empty()) { + return false; + } assertrx(coordinates.size() == 2); const double x = coordinates[0].As(); const double y = coordinates[1].As(); @@ -591,12 +617,16 @@ class QueriesVerifier : public virtual ::testing::Test { case CondEq: case CondSet: for (const reindexer::Variant& kv : keyValues) { - if (compareCompositeValues(indexesValues, kv, opts) == reindexer::ComparationResult::Eq) return true; + if (compareCompositeValues(indexesValues, kv, opts) == reindexer::ComparationResult::Eq) { + return true; + } } return false; case CondAllSet: for (const reindexer::Variant& kv : keyValues) { - if (compareCompositeValues(indexesValues, kv, opts) != reindexer::ComparationResult::Eq) return false; + if (compareCompositeValues(indexesValues, kv, opts) != reindexer::ComparationResult::Eq) { + return false; + } } return !keyValues.empty(); case CondLike: @@ -704,7 +734,9 @@ class QueriesVerifier : public virtual ::testing::Test { case CondEq: case CondSet: for (const reindexer::Variant& kv : keys) { - if (compare(value, kv, opts, fieldType) == reindexer::ComparationResult::Eq) return true; + if (compare(value, kv, opts, fieldType) == reindexer::ComparationResult::Eq) { + return true; + } } return false; case CondLike: @@ -743,8 +775,9 @@ class QueriesVerifier : public virtual ::testing::Test { if (!checkCondition(item, reindexer::BetweenFieldsQueryEntry{std::string{firstFields[i].name}, qentry.Condition(), std::string{secondFields[i].name}}, - indexesFields)) + indexesFields)) { return false; + } } return !firstFields.empty(); } @@ -860,7 +893,9 @@ class QueriesVerifier : public virtual ::testing::Test { const auto values2 = getJoinedField(item.GetID(), qr, i.nsIdx, i.index2, i.column2); return distance(static_cast(values1), static_cast(values2)); }); - if (it->operation.negative) value = -value; + if (it->operation.negative) { + value = -value; + } switch (it->operation.op) { case OpPlus: result += value; @@ -926,7 +961,9 @@ class QueriesVerifier : public virtual ::testing::Test { } else { ret += '['; for (size_t i = 0, s = values.size(); i < s; ++i) { - if (i != 0) ret += ','; + if (i != 0) { + ret += ','; + } ret += values[i].template As(); } ret += ']'; @@ -973,7 +1010,9 @@ class QueriesVerifier : public virtual ::testing::Test { static void printFailedSortOrder(const reindexer::Query& query, const reindexer::QueryResults& qr, int itemIndex, int itemsToShow = 10) { - if (qr.Count() == 0) return; + if (qr.Count() == 0) { + return; + } TestCout() << "Sort order or last items:" << std::endl; reindexer::Item rdummy(qr[0].GetItem(false)); @@ -985,22 +1024,32 @@ class QueriesVerifier : public virtual ::testing::Test { TestCout().BoldOff(); int firstItem = itemIndex - itemsToShow; - if (firstItem < 0) firstItem = 0; + if (firstItem < 0) { + firstItem = 0; + } for (int i = firstItem; i <= itemIndex; ++i) { reindexer::Item item(qr[i].GetItem(false)); - if (i == itemIndex) TestCout().BoldOn(); + if (i == itemIndex) { + TestCout().BoldOn(); + } for (size_t j = 0; j < query.sortingEntries_.size(); ++j) { TestCout() << item[query.sortingEntries_[j].expression].As() << " "; } - if (i == itemIndex) TestCout().BoldOff(); + if (i == itemIndex) { + TestCout().BoldOff(); + } TestCout().Endl(); } firstItem = itemIndex + 1; int lastItem = firstItem + itemsToShow; const int count = static_cast(qr.Count()); - if (firstItem >= count) firstItem = count - 1; - if (lastItem > count) lastItem = count; + if (firstItem >= count) { + firstItem = count - 1; + } + if (lastItem > count) { + lastItem = count; + } for (int i = firstItem; i < lastItem; ++i) { reindexer::Item item(qr[i].GetItem(false)); for (size_t j = 0; j < query.sortingEntries_.size(); ++j) { diff --git a/cpp_src/gtests/tests/fixtures/reindexer_api.h b/cpp_src/gtests/tests/fixtures/reindexer_api.h index 70dbc4b5b..d425f6794 100644 --- a/cpp_src/gtests/tests/fixtures/reindexer_api.h +++ b/cpp_src/gtests/tests/fixtures/reindexer_api.h @@ -27,25 +27,25 @@ class ReindexerApi : public virtual ::testing::Test { void DefineNamespaceDataset(std::string_view ns, std::initializer_list fields) { rt.DefineNamespaceDataset(ns, fields); } - void DefineNamespaceDataset(std::string_view ns, const std::vector &fields) { rt.DefineNamespaceDataset(ns, fields); } - void DefineNamespaceDataset(Reindexer &rx, const std::string &ns, std::initializer_list fields) { + void DefineNamespaceDataset(std::string_view ns, const std::vector& fields) { rt.DefineNamespaceDataset(ns, fields); } + void DefineNamespaceDataset(Reindexer& rx, const std::string& ns, std::initializer_list fields) { rt.DefineNamespaceDataset(rx, ns, fields); } Item NewItem(std::string_view ns) { return rt.NewItem(ns); } void Commit(std::string_view ns) { rt.Commit(ns); } - void Upsert(std::string_view ns, Item &item) { rt.Upsert(ns, item); } - size_t Update(const Query &q) { return rt.Update(q); } - void Delete(std::string_view ns, Item &item) { rt.Delete(ns, item); } - size_t Delete(const Query &q) { return rt.Delete(q); } + void Upsert(std::string_view ns, Item& item) { rt.Upsert(ns, item); } + size_t Update(const Query& q) { return rt.Update(q); } + void Delete(std::string_view ns, Item& item) { rt.Delete(ns, item); } + size_t Delete(const Query& q) { return rt.Delete(q); } - void PrintQueryResults(const std::string &ns, const QueryResults &res) { rt.PrintQueryResults(ns, res); } + void PrintQueryResults(const std::string& ns, const QueryResults& res) { rt.PrintQueryResults(ns, res); } std::string RandString() { return rt.RandString(); } std::string RandLikePattern() { return rt.RandLikePattern(); } std::string RuRandString() { return rt.RuRandString(); } std::vector RandIntVector(size_t size, int start, int range) { return rt.RandIntVector(size, start, range); } - void AwaitIndexOptimization(const std::string &nsName) { + void AwaitIndexOptimization(const std::string& nsName) { bool optimization_completed = false; unsigned waitForIndexOptimizationCompleteIterations = 0; while (!optimization_completed) { @@ -73,7 +73,7 @@ class ReindexerApi : public virtual ::testing::Test { ASSERT_TRUE(err.ok()) << err.what(); } - static Item getMemStat(Reindexer &rx, const std::string &ns) { + static Item getMemStat(Reindexer& rx, const std::string& ns) { QueryResults qr; auto err = rx.Select(Query("#memstats").Where("name", CondEq, ns), qr); EXPECT_TRUE(err.ok()) << err.what(); diff --git a/cpp_src/gtests/tests/fixtures/reindexertestapi.h b/cpp_src/gtests/tests/fixtures/reindexertestapi.h index 7d0365d1c..66f7b9c65 100644 --- a/cpp_src/gtests/tests/fixtures/reindexertestapi.h +++ b/cpp_src/gtests/tests/fixtures/reindexertestapi.h @@ -28,9 +28,9 @@ class ReindexerTestApi { ReindexerTestApi() : reindexer(std::make_shared()) {} template - static void DefineNamespaceDataset(DB &rx, std::string_view ns, const FieldsT &fields) { + static void DefineNamespaceDataset(DB& rx, std::string_view ns, const FieldsT& fields) { auto err = reindexer::Error(); - for (const auto &field : fields) { + for (const auto& field : fields) { if (field.indexType != "composite") { err = rx.AddIndex(ns, {std::string{field.indexName}, {std::string{field.indexName}}, @@ -59,7 +59,7 @@ class ReindexerTestApi { void DefineNamespaceDataset(std::string_view ns, std::initializer_list fields) { DefineNamespaceDataset(*reindexer, ns, fields); } - void DefineNamespaceDataset(std::string_view ns, const std::vector &fields) { + void DefineNamespaceDataset(std::string_view ns, const std::vector& fields) { DefineNamespaceDataset(*reindexer, ns, fields); } @@ -76,7 +76,7 @@ class ReindexerTestApi { auto err = reindexer->OpenNamespace(ns); ASSERT_TRUE(err.ok()) << err.what() << "; namespace: " << ns; } - void AddIndex(std::string_view ns, const reindexer::IndexDef &idef) { + void AddIndex(std::string_view ns, const reindexer::IndexDef& idef) { auto err = reindexer->AddIndex(ns, idef); if (!err.ok()) { reindexer::WrSerializer ser; @@ -88,7 +88,7 @@ class ReindexerTestApi { auto err = reindexer->DropIndex(ns, reindexer::IndexDef(std::string(name))); ASSERT_TRUE(err.ok()) << err.what() << "; namespace: " << ns << "; name: " << name; } - void Upsert(std::string_view ns, ItemType &item) { + void Upsert(std::string_view ns, ItemType& item) { assertrx(!!item); auto err = reindexer->Upsert(ns, item); ASSERT_TRUE(err.ok()) << err.what(); @@ -101,45 +101,47 @@ class ReindexerTestApi { err = reindexer->Upsert(ns, item); ASSERT_TRUE(err.ok()) << err.what() << "; " << json; } - void Update(const reindexer::Query &q, QueryResultsType &qr) { + void Update(const reindexer::Query& q, QueryResultsType& qr) { auto err = reindexer->Update(q, qr); ASSERT_TRUE(err.ok()) << err.what() << "; " << q.GetSQL(QueryUpdate); } - size_t Update(const reindexer::Query &q) { + size_t Update(const reindexer::Query& q) { QueryResultsType qr; Update(q, qr); return qr.Count(); } - QueryResultsType UpdateQR(const reindexer::Query &q) { + QueryResultsType UpdateQR(const reindexer::Query& q) { QueryResultsType qr; Update(q, qr); return qr; } - void Select(const reindexer::Query &q, QueryResultsType &qr) { + void Select(const reindexer::Query& q, QueryResultsType& qr) { auto err = reindexer->Select(q, qr); ASSERT_TRUE(err.ok()) << err.what() << "; " << q.GetSQL(); } - QueryResultsType Select(const reindexer::Query &q) { + QueryResultsType Select(const reindexer::Query& q) { QueryResultsType qr; Select(q, qr); return qr; } - void Delete(std::string_view ns, ItemType &item) { + void Delete(std::string_view ns, ItemType& item) { assertrx(!!item); auto err = reindexer->Delete(ns, item); ASSERT_TRUE(err.ok()) << err.what(); } - size_t Delete(const reindexer::Query &q) { + size_t Delete(const reindexer::Query& q) { QueryResultsType qr; auto err = reindexer->Delete(q, qr); EXPECT_TRUE(err.ok()) << err.what() << "; " << q.GetSQL(QueryDelete); return qr.Count(); } - reindexer::Error DumpIndex(std::ostream &os, std::string_view ns, std::string_view index) { + reindexer::Error DumpIndex(std::ostream& os, std::string_view ns, std::string_view index) { return reindexer->DumpIndex(os, ns, index); } - void PrintQueryResults(const std::string &ns, const QueryResultsType &res) { - if (!verbose) return; + void PrintQueryResults(const std::string& ns, const QueryResultsType& res) { + if (!verbose) { + return; + } { ItemType rdummy(reindexer->NewItem(ns)); std::string outBuf; diff --git a/cpp_src/gtests/tests/fixtures/replication_api.cc b/cpp_src/gtests/tests/fixtures/replication_api.cc index f2a4c2982..ac10273ff 100644 --- a/cpp_src/gtests/tests/fixtures/replication_api.cc +++ b/cpp_src/gtests/tests/fixtures/replication_api.cc @@ -6,7 +6,9 @@ bool ReplicationApi::StopServer(size_t id) { std::lock_guard lock(m_); assertrx(id < svc_.size()); - if (!svc_[id].Get()) return false; + if (!svc_[id].Get()) { + return false; + } svc_[id].Drop(); auto now = std::chrono::milliseconds(0); const auto pause = std::chrono::milliseconds(10); @@ -24,7 +26,9 @@ bool ReplicationApi::StartServer(size_t id) { std::lock_guard lock(m_); assertrx(id < svc_.size()); - if (svc_[id].IsRunning()) return false; + if (svc_[id].IsRunning()) { + return false; + } svc_[id].InitServer(id, kDefaultRpcPort + id, kDefaultHttpPort + id, kStoragePath + "node/" + std::to_string(id), "node" + std::to_string(id), true); return true; @@ -92,21 +96,27 @@ void ReplicationApi::ForceSync() { } }); for (size_t i = 0; i < svc_.size(); i++) { - if (i != masterId_) GetSrv(i)->ForceSync(); + if (i != masterId_) { + GetSrv(i)->ForceSync(); + } } done = true; awaitForceSync.join(); } void ReplicationApi::SwitchMaster(size_t id, const ReplicationConfigTest::NsSet& namespaces) { - if (id == masterId_) return; + if (id == masterId_) { + return; + } masterId_ = id; ReplicationConfigTest config("master", false, true, id); GetSrv(masterId_)->MakeMaster(config); for (size_t i = 0; i < svc_.size(); i++) { std::string masterDsn = "cproto://127.0.0.1:" + std::to_string(kDefaultRpcPort + masterId_) + "/node" + std::to_string(masterId_); ReplicationConfigTest config("slave", false, true, i, masterDsn, "server_" + std::to_string(i), namespaces); - if (i != masterId_) GetSrv(i)->MakeSlave(config); + if (i != masterId_) { + GetSrv(i)->MakeSlave(config); + } } } @@ -150,10 +160,14 @@ void ReplicationApi::SetUp() { void ReplicationApi::TearDown() { std::lock_guard lock(m_); for (auto& server : svc_) { - if (server.Get()) server.Get()->Stop(); + if (server.Get()) { + server.Get()->Stop(); + } } for (auto& server : svc_) { - if (!server.Get()) continue; + if (!server.Get()) { + continue; + } server.Drop(); auto now = std::chrono::milliseconds(0); const auto pause = std::chrono::milliseconds(10); diff --git a/cpp_src/gtests/tests/fixtures/replication_load_api.h b/cpp_src/gtests/tests/fixtures/replication_load_api.h index e21b72cf4..758e0f3a4 100644 --- a/cpp_src/gtests/tests/fixtures/replication_load_api.h +++ b/cpp_src/gtests/tests/fixtures/replication_load_api.h @@ -9,7 +9,7 @@ class ReplicationLoadApi : public ReplicationApi { public: class UpdatesReciever : public reindexer::IUpdatesObserver { public: - void OnWALUpdate(reindexer::LSNPair, std::string_view nsName, const reindexer::WALRecord &) override final { + void OnWALUpdate(reindexer::LSNPair, std::string_view nsName, const reindexer::WALRecord&) override final { std::lock_guard lck(mtx_); auto found = updatesCounters_.find(nsName); if (found != updatesCounters_.end()) { @@ -18,7 +18,7 @@ class ReplicationLoadApi : public ReplicationApi { updatesCounters_.emplace(std::string(nsName), 1); } } - void OnConnectionState(const Error &) override final {} + void OnConnectionState(const Error&) override final {} void OnUpdatesLost(std::string_view) override final {} using map = tsl::hopscotch_map; @@ -34,7 +34,7 @@ class ReplicationLoadApi : public ReplicationApi { void Dump() const { std::cerr << "Reciever dump: " << std::endl; auto counters = Counters(); - for (auto &it : counters) { + for (auto& it : counters) { std::cerr << it.first << ": " << it.second << std::endl; } } @@ -51,7 +51,7 @@ class ReplicationLoadApi : public ReplicationApi { // untill we use shared ptr it will be not destroyed auto srv = GetSrv(masterId_); - auto &api = srv->api; + auto& api = srv->api; Error err = api.reindexer->OpenNamespace("some", opt); ASSERT_TRUE(err.ok()) << err.what(); @@ -75,7 +75,7 @@ class ReplicationLoadApi : public ReplicationApi { void FillData(size_t count) { // untill we use shared ptr it will be not destroyed auto srv = GetSrv(masterId_); - auto &api = srv->api; + auto& api = srv->api; reindexer::shared_lock lk(restartMutex_); @@ -98,7 +98,7 @@ class ReplicationLoadApi : public ReplicationApi { BaseApi::QueryResultsType SimpleSelect(size_t num) { reindexer::Query qr("some"); auto srv = GetSrv(num); - auto &api = srv->api; + auto& api = srv->api; BaseApi::QueryResultsType res(api.reindexer.get()); auto err = api.reindexer->Select(qr, res); EXPECT_TRUE(err.ok()) << err.what(); @@ -107,18 +107,18 @@ class ReplicationLoadApi : public ReplicationApi { } BaseApi::QueryResultsType DeleteFromMaster() { auto srv = GetSrv(masterId_); - auto &api = srv->api; + auto& api = srv->api; BaseApi::QueryResultsType res(api.reindexer.get()); auto err = api.reindexer->Delete(reindexer::Query("some"), res); EXPECT_TRUE(err.ok()) << err.what(); return res; } - void RestartWithConfigFile(size_t num, const std::string &configYaml) { + void RestartWithConfigFile(size_t num, const std::string& configYaml) { GetSrv(num)->WriteServerConfig(configYaml); StopServer(num); StartServer(num); } - void SetServerConfig(size_t num, const ReplicationConfigTest &config) { + void SetServerConfig(size_t num, const ReplicationConfigTest& config) { auto srv = GetSrv(num); if (num) { srv->MakeSlave(config); @@ -126,13 +126,13 @@ class ReplicationLoadApi : public ReplicationApi { srv->MakeMaster(config); } } - void CheckSlaveConfigFile(size_t num, const ReplicationConfigTest &config) { + void CheckSlaveConfigFile(size_t num, const ReplicationConfigTest& config) { assertrx(num); auto srv = GetSrv(num); auto curConfig = srv->GetServerConfig(ServerControl::ConfigType::File); EXPECT_TRUE(config == curConfig) << "config:\n" << config.GetJSON() << "\ncurConfig:\n" << curConfig.GetJSON(); } - void CheckSlaveConfigNamespace(size_t num, const ReplicationConfigTest &config, std::chrono::seconds awaitTime) { + void CheckSlaveConfigNamespace(size_t num, const ReplicationConfigTest& config, std::chrono::seconds awaitTime) { assertrx(num); auto srv = GetSrv(num); for (int i = 0; i < awaitTime.count(); ++i) { @@ -150,7 +150,7 @@ class ReplicationLoadApi : public ReplicationApi { versions.reserve(GetServersCount()); for (size_t i = 0; i < GetServersCount(); i++) { auto srv = GetSrv(i); - auto &api = srv->api; + auto& api = srv->api; BaseApi::QueryResultsType res(api.reindexer.get()); auto err = api.reindexer->Select(reindexer::Query(ns), res); EXPECT_TRUE(err.ok()) << err.what(); diff --git a/cpp_src/gtests/tests/fixtures/rpcclient_api.h b/cpp_src/gtests/tests/fixtures/rpcclient_api.h index bb22c9776..3cf36189d 100644 --- a/cpp_src/gtests/tests/fixtures/rpcclient_api.h +++ b/cpp_src/gtests/tests/fixtures/rpcclient_api.h @@ -43,7 +43,7 @@ class RPCClientTestApi : public ::testing::Test { void Stop(); const std::string& GetDsn() const { return dsn_; } RPCServerStatus Status() const { return server_->Status(); } - Error const& ErrorStatus() const { return err_; } + const Error& ErrorStatus() const { return err_; } size_t CloseQRRequestsCount() const { return server_->CloseQRRequestsCount(); } private: diff --git a/cpp_src/gtests/tests/fixtures/runtime_indexes_api.h b/cpp_src/gtests/tests/fixtures/runtime_indexes_api.h index a9bac392a..70d75dbe2 100644 --- a/cpp_src/gtests/tests/fixtures/runtime_indexes_api.h +++ b/cpp_src/gtests/tests/fixtures/runtime_indexes_api.h @@ -157,7 +157,9 @@ class RuntimeIndexesApi : public ReindexerApi { void AddRuntimeStringIndex(int indexNumber, bool pk = false) { IndexOpts opts; - if (pk) opts.PK(); + if (pk) { + opts.PK(); + } std::string indexName = getRuntimeStringIndexName(indexNumber); Error err = rt.reindexer->AddIndex(default_namespace, {indexName, "hash", "string", opts}); ASSERT_TRUE(err.ok()) << err.what(); diff --git a/cpp_src/gtests/tests/fixtures/selector_plan_test.h b/cpp_src/gtests/tests/fixtures/selector_plan_test.h index 8b4c2be1d..41e9552dd 100644 --- a/cpp_src/gtests/tests/fixtures/selector_plan_test.h +++ b/cpp_src/gtests/tests/fixtures/selector_plan_test.h @@ -100,14 +100,18 @@ class SelectorPlanTest : public ReindexerApi { static std::vector adoptValuesType(std::initializer_list values) { std::vector result; result.reserve(values.size()); - for (const T& v : values) result.push_back(v); + for (const T& v : values) { + result.push_back(v); + } return result; } static std::vector adoptValuesType(std::initializer_list values) { std::vector result; result.reserve(values.size()); - for (const char* v : values) result.emplace_back(v); + for (const char* v : values) { + result.emplace_back(v); + } return result; } diff --git a/cpp_src/gtests/tests/fixtures/servercontrol.cc b/cpp_src/gtests/tests/fixtures/servercontrol.cc index cd8ffc465..11385372d 100644 --- a/cpp_src/gtests/tests/fixtures/servercontrol.cc +++ b/cpp_src/gtests/tests/fixtures/servercontrol.cc @@ -61,7 +61,9 @@ void ServerControl::Interface::Stop() { std::string ServerControl::Interface::getLogName(const std::string& log, bool core) { std::string name = getTestLogPath(); name += (log + "_"); - if (!core) name += std::to_string(id_); + if (!core) { + name += std::to_string(id_); + } name += ".log"; return name; } @@ -313,7 +315,9 @@ void ServerControl::Interface::setReplicationConfig(const ReplicationConfigTest& replConf.Put("server_id", config.serverId_); auto nsArray = replConf.Array("namespaces"); - for (auto& ns : config.namespaces_) nsArray.Put(nullptr, ns); + for (auto& ns : config.namespaces_) { + nsArray.Put(nullptr, ns); + } nsArray.End(); replConf.End(); jb.End(); @@ -371,8 +375,9 @@ ReplicationTestState ServerControl::Interface::GetState(std::string_view ns) { state.ownLsn.FromJSON(root["replication"]["last_lsn_v2"]); if (!isSlave) { state.lsn.FromJSON(root["replication"]["last_lsn_v2"]); - } else + } else { state.lsn.FromJSON(root["replication"]["origin_lsn"]); + } state.dataCount = root["replication"]["data_count"].As(); state.dataHash = root["replication"]["data_hash"].As(); diff --git a/cpp_src/gtests/tests/fixtures/systemhelpers.cc b/cpp_src/gtests/tests/fixtures/systemhelpers.cc index fae4110cb..0a427745e 100644 --- a/cpp_src/gtests/tests/fixtures/systemhelpers.cc +++ b/cpp_src/gtests/tests/fixtures/systemhelpers.cc @@ -60,7 +60,9 @@ pid_t StartProcess(const std::string& program, const std::vector& p Error EndProcess(pid_t PID) { #ifdef __linux__ int r = kill(PID, SIGTERM); - if (r != 0) return Error(errLogic, "errno=%d (%s)", errno, strerror(errno)); + if (r != 0) { + return Error(errLogic, "errno=%d (%s)", errno, strerror(errno)); + } #else (void)PID; assertrx(false); @@ -78,7 +80,9 @@ Error WaitEndProcess(pid_t PID) { if (WEXITSTATUS(status)) { return Error(errLogic, "WEXITSTATUS(status) != 0. status: %d", WEXITSTATUS(status)); } - if (waitres != PID) return Error(errLogic, "waitres != PID. errno=%d (%s)", errno, strerror(errno)); + if (waitres != PID) { + return Error(errLogic, "waitres != PID. errno=%d (%s)", errno, strerror(errno)); + } #else (void)PID; assertrx(false); diff --git a/cpp_src/gtests/tests/fixtures/test_helpers.h b/cpp_src/gtests/tests/fixtures/test_helpers.h index 51d72cfe9..9940c0adb 100644 --- a/cpp_src/gtests/tests/fixtures/test_helpers.h +++ b/cpp_src/gtests/tests/fixtures/test_helpers.h @@ -13,11 +13,11 @@ struct QueryWatcher { } } - const reindexer::Query &q; + const reindexer::Query& q; }; template -std::string PrintItem(const ItemType &item) { +std::string PrintItem(const ItemType& item) { std::stringstream out; for (auto idx = 1; idx < item.NumFields(); idx++) { out << item[idx].Name() << '='; @@ -27,7 +27,9 @@ std::string PrintItem(const ItemType &item) { } else { out << '['; for (size_t i = 0, s = values.size(); i < s; ++i) { - if (i != 0) out << ", "; + if (i != 0) { + out << ", "; + } out << values[i].template As(); } out << "] "; diff --git a/cpp_src/gtests/tests/fixtures/ttl_index_api.h b/cpp_src/gtests/tests/fixtures/ttl_index_api.h index 8e434914f..98c1ddbcd 100644 --- a/cpp_src/gtests/tests/fixtures/ttl_index_api.h +++ b/cpp_src/gtests/tests/fixtures/ttl_index_api.h @@ -68,7 +68,9 @@ class TtlIndexApi : public ReindexerApi { for (size_t i = 0; i < 10; ++i) { std::this_thread::sleep_for(kStep); count = GetItemsCount(); - if (count == 0) break; + if (count == 0) { + break; + } } } return count; diff --git a/cpp_src/gtests/tests/fuzzing/fuzzing.cc b/cpp_src/gtests/tests/fuzzing/fuzzing.cc index 55a109b64..f4e753118 100644 --- a/cpp_src/gtests/tests/fuzzing/fuzzing.cc +++ b/cpp_src/gtests/tests/fuzzing/fuzzing.cc @@ -53,14 +53,20 @@ TEST_F(Fuzzing, BaseTest) { auto item = rx_.NewItem(ns.GetName()); err = item.Status(); EXPECT_TRUE(err.ok()) << err.what(); - if (!err.ok()) continue; + if (!err.ok()) { + continue; + } ns.NewItem(ser); // TODO not json err = item.FromJSON(ser.Slice()); EXPECT_TRUE(err.ok()) << err.what() << std::endl << "size: " << ser.Slice().size() << std::endl << ser.Slice(); - if (!err.ok()) continue; + if (!err.ok()) { + continue; + } err = item.Status(); EXPECT_TRUE(err.ok()) << err.what(); - if (!err.ok()) continue; + if (!err.ok()) { + continue; + } enum Op : uint8_t { Insert, Upsert, Update, Delete, END = Delete }; switch (rnd.RndWhich()) { case Insert: diff --git a/cpp_src/gtests/tests/mocks/rpcserver_fake.cc b/cpp_src/gtests/tests/mocks/rpcserver_fake.cc index c287d1f7b..27c2609a1 100644 --- a/cpp_src/gtests/tests/mocks/rpcserver_fake.cc +++ b/cpp_src/gtests/tests/mocks/rpcserver_fake.cc @@ -6,14 +6,14 @@ #include "net/listener.h" #include "reindexer_version.h" -RPCServerFake::RPCServerFake(const RPCServerConfig &conf) : startTs_(system_clock_w::now()), conf_(conf), state_(Init) {} +RPCServerFake::RPCServerFake(const RPCServerConfig& conf) : startTs_(system_clock_w::now()), conf_(conf), state_(Init) {} -Error RPCServerFake::Ping(cproto::Context &) { +Error RPCServerFake::Ping(cproto::Context&) { // return {}; } -Error RPCServerFake::Login(cproto::Context &ctx, p_string /*login*/, p_string /*password*/, p_string /*db*/) { +Error RPCServerFake::Login(cproto::Context& ctx, p_string /*login*/, p_string /*password*/, p_string /*db*/) { if (loginError_.ok()) { std::this_thread::sleep_for(conf_.loginDelay); } @@ -31,8 +31,8 @@ Error RPCServerFake::Login(cproto::Context &ctx, p_string /*login*/, p_string /* return loginError_.code(); } -Error RPCServerFake::CheckAuth(cproto::Context &ctx) { - auto clientData = dynamic_cast(ctx.GetClientData()); +Error RPCServerFake::CheckAuth(cproto::Context& ctx) { + auto clientData = dynamic_cast(ctx.GetClientData()); if (ctx.call->cmd == cproto::kCmdLogin || ctx.call->cmd == cproto::kCmdPing) { return {}; @@ -45,24 +45,24 @@ Error RPCServerFake::CheckAuth(cproto::Context &ctx) { return {}; } -Error RPCServerFake::OpenNamespace(cproto::Context &, p_string) { +Error RPCServerFake::OpenNamespace(cproto::Context&, p_string) { std::this_thread::sleep_for(conf_.openNsDelay); return {}; } -Error RPCServerFake::DropNamespace(cproto::Context &, p_string) { return Error(errOK); } +Error RPCServerFake::DropNamespace(cproto::Context&, p_string) { return Error(errOK); } Error RPCServerFake::Stop() { listener_->Stop(); state_ = Stopped; - if (int const openedQR = OpenedQRCount(); openedQR == 0) { + if (const int openedQR = OpenedQRCount(); openedQR == 0) { return errOK; } else { return Error{errLogic, "There are %d opened QueryResults", openedQR}; } } -Error RPCServerFake::Select(cproto::Context &ctx, p_string /*query*/, int /*flags*/, int /*limit*/, p_string /*ptVersions*/) { +Error RPCServerFake::Select(cproto::Context& ctx, p_string /*query*/, int /*flags*/, int /*limit*/, p_string /*ptVersions*/) { static constexpr size_t kQueryResultsPoolSize = 1024; std::this_thread::sleep_for(conf_.selectDelay); int qrId; @@ -87,7 +87,7 @@ Error RPCServerFake::Select(cproto::Context &ctx, p_string /*query*/, int /*flag return errOK; } -Error RPCServerFake::CloseResults(cproto::Context &ctx, int reqId, std::optional /*qrUID*/, std::optional doNotReply) { +Error RPCServerFake::CloseResults(cproto::Context& ctx, int reqId, std::optional /*qrUID*/, std::optional doNotReply) { if (doNotReply && *doNotReply) { ctx.respSent = true; } @@ -109,7 +109,7 @@ size_t RPCServerFake::OpenedQRCount() { return usedQrIds_.size(); } -bool RPCServerFake::Start(const std::string &addr, ev::dynamic_loop &loop, Error loginError) { +bool RPCServerFake::Start(const std::string& addr, ev::dynamic_loop& loop, Error loginError) { #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif diff --git a/cpp_src/gtests/tests/mocks/rpcserver_fake.h b/cpp_src/gtests/tests/mocks/rpcserver_fake.h index 07906fbb6..ae888cdc0 100644 --- a/cpp_src/gtests/tests/mocks/rpcserver_fake.h +++ b/cpp_src/gtests/tests/mocks/rpcserver_fake.h @@ -26,20 +26,20 @@ struct RPCClientData final : public cproto::ClientData { class RPCServerFake { public: - RPCServerFake(const RPCServerConfig &conf); + RPCServerFake(const RPCServerConfig& conf); - bool Start(const std::string &addr, ev::dynamic_loop &loop, Error loginError); + bool Start(const std::string& addr, ev::dynamic_loop& loop, Error loginError); Error Stop(); - Error Ping(cproto::Context &ctx); - Error Login(cproto::Context &ctx, p_string login, p_string password, p_string db); - Error Select(cproto::Context &ctx, p_string query, int flags, int limit, p_string ptVersions); - Error OpenNamespace(cproto::Context &ctx, p_string ns); - Error DropNamespace(cproto::Context &ctx, p_string ns); - Error CloseResults(cproto::Context &ctx, int reqId, std::optional qrUID, std::optional doNotReply); + Error Ping(cproto::Context& ctx); + Error Login(cproto::Context& ctx, p_string login, p_string password, p_string db); + Error Select(cproto::Context& ctx, p_string query, int flags, int limit, p_string ptVersions); + Error OpenNamespace(cproto::Context& ctx, p_string ns); + Error DropNamespace(cproto::Context& ctx, p_string ns); + Error CloseResults(cproto::Context& ctx, int reqId, std::optional qrUID, std::optional doNotReply); RPCServerStatus Status() const; - Error CheckAuth(cproto::Context &ctx); + Error CheckAuth(cproto::Context& ctx); size_t OpenedQRCount(); size_t CloseQRRequestsCount() const { return closeQRRequestsCounter_.load(std::memory_order_relaxed); } diff --git a/cpp_src/gtests/tests/unit/btree_idsets_tests.cc b/cpp_src/gtests/tests/unit/btree_idsets_tests.cc index a182d8941..47f1d209f 100644 --- a/cpp_src/gtests/tests/unit/btree_idsets_tests.cc +++ b/cpp_src/gtests/tests/unit/btree_idsets_tests.cc @@ -10,7 +10,7 @@ TEST_F(BtreeIdsetsApi, SelectByStringField) { std::string strValueToCheck = lastStrValue; Error err = rt.reindexer->Select(Query(default_namespace).Not().Where(kFieldOne, CondEq, strValueToCheck), qr); EXPECT_TRUE(err.ok()) << err.what(); - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant kr = item[kFieldOne]; EXPECT_TRUE(kr.Type().Is()); @@ -24,7 +24,7 @@ TEST_F(BtreeIdsetsApi, SelectByIntField) { QueryResults qr; Error err = rt.reindexer->Select(Query(default_namespace).Where(kFieldTwo, CondGe, Variant(static_cast(boundaryValue))), qr); EXPECT_TRUE(err.ok()) << err.what(); - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant kr = item[kFieldTwo]; EXPECT_TRUE(kr.Type().Is()); @@ -44,7 +44,7 @@ TEST_F(BtreeIdsetsApi, SelectByBothFields) { .Where(kFieldTwo, CondGe, Variant(static_cast(boundaryValue))), qr); EXPECT_TRUE(err.ok()) << err.what(); - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant krOne = item[kFieldOne]; EXPECT_TRUE(krOne.Type().Is()); @@ -154,7 +154,9 @@ TEST_F(ReindexerApi, BtreeUnbuiltIndexIteratorsTest) { pos = ids2.size() - 1; while (bIt2.Next()) { EXPECT_TRUE(bIt2.Value() == ids2[pos]) << "iterator value = " << bIt2.Value() << "; expected value = " << ids2[pos]; - if (pos) --pos; + if (pos) { + --pos; + } } EXPECT_TRUE(pos == 0); EXPECT_TRUE(!bIt2.Next()); diff --git a/cpp_src/gtests/tests/unit/csv2jsonconverter.cc b/cpp_src/gtests/tests/unit/csv2jsonconverter.cc index c92f0c16c..ae407e276 100644 --- a/cpp_src/gtests/tests/unit/csv2jsonconverter.cc +++ b/cpp_src/gtests/tests/unit/csv2jsonconverter.cc @@ -57,7 +57,7 @@ std::vector parseCSVRow(std::string_view row) { return fields; } -std::string csv2json(std::string_view row, const std::vector &schema) { +std::string csv2json(std::string_view row, const std::vector& schema) { auto fields = parseCSVRow(row); if (schema.size() < fields.size()) { @@ -72,7 +72,7 @@ std::string csv2json(std::string_view row, const std::vector &schem try { gason::JsonParser().Parse(std::string_view{fields[i]}); builder.Raw(schema[i], fields[i]); - } catch (const gason::Exception &) { + } catch (const gason::Exception&) { builder.Raw(schema[i], '"' + fields[i] + '"'); } } diff --git a/cpp_src/gtests/tests/unit/csv2jsonconverter.h b/cpp_src/gtests/tests/unit/csv2jsonconverter.h index 68d9acaf6..1d5606140 100644 --- a/cpp_src/gtests/tests/unit/csv2jsonconverter.h +++ b/cpp_src/gtests/tests/unit/csv2jsonconverter.h @@ -6,6 +6,6 @@ namespace reindexer { std::vector parseCSVRow(std::string_view row); -std::string csv2json(std::string_view row, const std::vector &schema); +std::string csv2json(std::string_view row, const std::vector& schema); } // namespace reindexer \ No newline at end of file diff --git a/cpp_src/gtests/tests/unit/equalposition_tests.cc b/cpp_src/gtests/tests/unit/equalposition_tests.cc index 1dfa80a3d..5051fcdc7 100644 --- a/cpp_src/gtests/tests/unit/equalposition_tests.cc +++ b/cpp_src/gtests/tests/unit/equalposition_tests.cc @@ -30,7 +30,7 @@ void VerifyQueryResult(const QueryResults& qr, const std::vector& f EXPECT_TRUE(fields.size() == keys.size()); EXPECT_TRUE(keys.size() == condTypes.size()); size_t totalFound = 0; - for (auto &item : qr) { + for (auto& item : qr) { size_t len = INT_MAX; Item it = item.GetItem(false); @@ -45,8 +45,12 @@ void VerifyQueryResult(const QueryResults& qr, const std::vector& f bool equal = true; for (;;) { size_t key = 0; - while ((j < len) && !Compare(vals[key][j], keys[key], condTypes[key])) ++j; - if (eof()) break; + while ((j < len) && !Compare(vals[key][j], keys[key], condTypes[key])) { + ++j; + } + if (eof()) { + break; + } equal = true; while (++key < keys.size()) { equal &= Compare(vals[key][j], keys[key], condTypes[key]); @@ -60,7 +64,9 @@ void VerifyQueryResult(const QueryResults& qr, const std::vector& f } ++j; } - if (!equal) TEST_COUT << it.GetJSON() << std::endl; + if (!equal) { + TEST_COUT << it.GetJSON() << std::endl; + } } EXPECT_TRUE(totalFound == qr.Count()) << " totalFound=" << totalFound << ", qr.Count()=" << qr.Count(); } diff --git a/cpp_src/gtests/tests/unit/ft/ft_generic.cc b/cpp_src/gtests/tests/unit/ft/ft_generic.cc index e039bd551..6398ea66f 100644 --- a/cpp_src/gtests/tests/unit/ft/ft_generic.cc +++ b/cpp_src/gtests/tests/unit/ft/ft_generic.cc @@ -66,7 +66,9 @@ TEST_P(FTGenericApi, CompositeSelect) { auto ritem(it.GetItem(false)); for (auto idx = 1; idx < ritem.NumFields(); idx++) { auto field = ritem[idx].Name(); - if (field == "id") continue; + if (field == "id") { + continue; + } auto it = data.find(ritem[field].As()); ASSERT_TRUE(it != data.end()); data.erase(it); @@ -103,7 +105,9 @@ TEST_P(FTGenericApi, CompositeSelectWithFields) { auto ritem(it.GetItem(false)); for (auto idx = 1; idx < ritem.NumFields(); idx++) { auto curField = ritem[idx].Name(); - if (curField != field) continue; + if (curField != field) { + continue; + } auto it = data.find(ritem[curField].As()); ASSERT_TRUE(it != data.end()); data.erase(it); @@ -151,7 +155,9 @@ TEST_P(FTGenericApi, MergeWithSameNSAndSelectFunctions) { auto ritem(it.GetItem(false)); for (auto idx = 1; idx < ritem.NumFields(); idx++) { auto curField = ritem[idx].Name(); - if (curField != field) continue; + if (curField != field) { + continue; + } auto it = data.find(ritem[curField].As()); ASSERT_TRUE(it != data.end()); data.erase(it); @@ -766,7 +772,7 @@ TEST_P(FTGenericApi, Unique) { std::vector data; std::set check; std::set checks; - reindexer::logInstallWriter([](int, char*) { /*std::cout << buf << std::endl;*/ }, reindexer::LoggerPolicy::WithLocks); + reindexer::logInstallWriter([](int, char*) { /*std::cout << buf << std::endl;*/ }, reindexer::LoggerPolicy::WithLocks, int(LogTrace)); for (int i = 0; i < 1000; ++i) { bool inserted = false; diff --git a/cpp_src/gtests/tests/unit/index_tuple_test.cc b/cpp_src/gtests/tests/unit/index_tuple_test.cc index c02519341..f6ca60b6b 100644 --- a/cpp_src/gtests/tests/unit/index_tuple_test.cc +++ b/cpp_src/gtests/tests/unit/index_tuple_test.cc @@ -26,8 +26,8 @@ class IndexTupleTest : public ReindexerApi { return createNS(ns, pattern); } - void DoTestDefault(const std::shared_ptr &reindexer, std::string_view ns, const reindexer::IndexDef &indexDef, - std::string_view pattern, std::string_view field, const VariantArray &expectedValues, + void DoTestDefault(const std::shared_ptr& reindexer, std::string_view ns, const reindexer::IndexDef& indexDef, + std::string_view pattern, std::string_view field, const VariantArray& expectedValues, std::string_view description) const { auto err = rt.reindexer->AddIndex(ns, indexDef); ASSERT_TRUE(err.ok()) << err.what() << "\n" << description; @@ -35,7 +35,7 @@ class IndexTupleTest : public ReindexerApi { validateResults(reindexer, ns, pattern, field, expectedValues, description); } - void DoTestEmpty(const std::shared_ptr &reindexer, std::string_view ns, const reindexer::IndexDef &indexDef, + void DoTestEmpty(const std::shared_ptr& reindexer, std::string_view ns, const reindexer::IndexDef& indexDef, std::string_view pattern, std::string_view description) const { auto err = reindexer->AddIndex(ns, indexDef); ASSERT_TRUE(err.ok()) << err.what(); @@ -43,8 +43,8 @@ class IndexTupleTest : public ReindexerApi { checkExpectations(reindexer, ns, pattern, description); } - void DoCallAndCheckError(const std::shared_ptr &reindexer, std::string_view ns, - const reindexer::IndexDef &indexDef, std::string_view errMsg) const { + void DoCallAndCheckError(const std::shared_ptr& reindexer, std::string_view ns, + const reindexer::IndexDef& indexDef, std::string_view errMsg) const { std::vector items; getItems(reindexer, ns, items); @@ -55,8 +55,8 @@ class IndexTupleTest : public ReindexerApi { checkItems(reindexer, ns, items); } - void ValidateReloadState(const std::shared_ptr &reindexer, std::string_view ns, std::string_view pattern, - std::string_view description, const std::string &storagePath) const { + void ValidateReloadState(const std::shared_ptr& reindexer, std::string_view ns, std::string_view pattern, + std::string_view description, const std::string& storagePath) const { auto err = rt.reindexer->CloseNamespace(ns); ASSERT_TRUE(err.ok()) << err.what(); @@ -72,9 +72,8 @@ class IndexTupleTest : public ReindexerApi { reindexer::fs::RmDirAll(storagePath); } - void SpecialCheckForNull(const std::shared_ptr &reindexer, std::string_view ns, - std::string_view firstItemPattern, std::string_view itemPattern, - std::string_view description, const std::string &storagePath) const { + void SpecialCheckForNull(const std::shared_ptr& reindexer, std::string_view ns, std::string_view firstItemPattern, + std::string_view itemPattern, std::string_view description, const std::string& storagePath) const { specialCheckForNull(reindexer, ns, firstItemPattern, itemPattern, description); validateReloadStateForNull(reindexer, ns, firstItemPattern, itemPattern, description, storagePath); } @@ -83,7 +82,7 @@ class IndexTupleTest : public ReindexerApi { private: static constexpr char kStoragePath[] = "/tmp/reindex/"; - static constexpr uint32_t itemNumber_ = 5; // NOTE: minimum 2 + static constexpr uint32_t itemNumber_ = 5; // NOTE: minimum 2 [[nodiscard]] std::string createNS(std::string_view ns, std::string_view itemPattern) { std::string storage; @@ -92,7 +91,7 @@ class IndexTupleTest : public ReindexerApi { return storage; } - void createNamespace(std::string_view ns, std::string &storagePath) { + void createNamespace(std::string_view ns, std::string& storagePath) { storagePath = kStoragePath; storagePath.append(ns); @@ -118,15 +117,17 @@ class IndexTupleTest : public ReindexerApi { } } - void checkIfItemJSONValid(QueryResults::Iterator &it, bool print = false) const { + void checkIfItemJSONValid(QueryResults::Iterator& it, bool print = false) const { reindexer::WrSerializer wrser; Error err = it.GetJSON(wrser, false); EXPECT_TRUE(err.ok()) << err.what(); - if (err.ok() && print) std::cout << wrser.Slice() << std::endl; + if (err.ok() && print) { + std::cout << wrser.Slice() << std::endl; + } } - void validateResults(const std::shared_ptr &reindexer, std::string_view ns, std::string_view pattern, - std::string_view field, const VariantArray &expectedValues, std::string_view description) const { + void validateResults(const std::shared_ptr& reindexer, std::string_view ns, std::string_view pattern, + std::string_view field, const VariantArray& expectedValues, std::string_view description) const { SCOPED_TRACE(description); QueryResults qr; @@ -154,7 +155,7 @@ class IndexTupleTest : public ReindexerApi { } } - void checkExpectations(const std::shared_ptr &reindexer, std::string_view ns, std::string_view pattern, + void checkExpectations(const std::shared_ptr& reindexer, std::string_view ns, std::string_view pattern, std::string_view description) const { SCOPED_TRACE(description); @@ -176,22 +177,21 @@ class IndexTupleTest : public ReindexerApi { } } - void getItems(const std::shared_ptr &reindexer, std::string_view ns, - std::vector &items) const { + void getItems(const std::shared_ptr& reindexer, std::string_view ns, std::vector& items) const { QueryResults qr; auto err = reindexer->Select("SELECT * FROM " + std::string(ns), qr); ASSERT_TRUE(err.ok()) << err.what(); items.clear(); items.reserve(qr.Count()); - for (auto &it : qr) { + for (auto& it : qr) { auto item = it.GetItem(false); items.emplace_back(item.GetJSON()); } } - void checkItems(const std::shared_ptr &reindexer, std::string_view ns, - const std::vector &items) const { + void checkItems(const std::shared_ptr& reindexer, std::string_view ns, + const std::vector& items) const { QueryResults qr; auto err = reindexer->Select("SELECT * FROM " + std::string(ns), qr); ASSERT_TRUE(err.ok()) << err.what(); @@ -201,15 +201,14 @@ class IndexTupleTest : public ReindexerApi { auto itQR = qr.begin(); auto endItems = items.cend(); auto endQR = qr.end(); - for ( ; (itItems != endItems) && (itQR != endQR); ++itItems, ++itQR) { + for (; (itItems != endItems) && (itQR != endQR); ++itItems, ++itQR) { auto item = itQR.GetItem(false); ASSERT_EQ(*itItems, item.GetJSON()); } } - void specialCheckForNull(const std::shared_ptr &reindexer, std::string_view ns, - std::string_view firstItemPattern, std::string_view itemPattern, - std::string_view description) const { + void specialCheckForNull(const std::shared_ptr& reindexer, std::string_view ns, std::string_view firstItemPattern, + std::string_view itemPattern, std::string_view description) const { SCOPED_TRACE(description); // first element should not update values, all others should be initialized to default values @@ -224,7 +223,7 @@ class IndexTupleTest : public ReindexerApi { Item item = it.GetItem(false); checkIfItemJSONValid(it); const auto json = item.GetJSON(); - const auto &pattern = (idx == IdStart)? firstItemPattern : itemPattern; + const auto& pattern = (idx == IdStart) ? firstItemPattern : itemPattern; const auto expJson = fmt::sprintf(pattern.data(), idx); ASSERT_EQ(json, expJson); @@ -232,9 +231,9 @@ class IndexTupleTest : public ReindexerApi { } } - void validateReloadStateForNull(const std::shared_ptr &reindexer, std::string_view ns, - std::string_view firstItemPattern, std::string_view itemPattern, - std::string_view description, const std::string &storagePath) const { + void validateReloadStateForNull(const std::shared_ptr& reindexer, std::string_view ns, + std::string_view firstItemPattern, std::string_view itemPattern, std::string_view description, + const std::string& storagePath) const { auto err = rt.reindexer->CloseNamespace(ns); ASSERT_TRUE(err.ok()) << err.what(); @@ -320,17 +319,13 @@ TEST_F(IndexTupleTest, SparseItemTest) { const auto storage = CreateSparseNamespace(ns); DoTestEmpty(rt.reindexer, ns, {"sparse1", {"fld1"}, "hash", "int", IndexOpts().Sparse()}, - R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", - "add some sparse index to present nested field. Do nothing"); - DoCallAndCheckError(rt.reindexer, ns, {"sparse2", {"fld2"}, "hash", "int", IndexOpts().Sparse()}, - "Can't convert 'test' to number"); + R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", "add some sparse index to present nested field. Do nothing"); + DoCallAndCheckError(rt.reindexer, ns, {"sparse2", {"fld2"}, "hash", "int", IndexOpts().Sparse()}, "Can't convert 'test' to number"); DoCallAndCheckError(rt.reindexer, ns, {"sparse3", {"fld2.nested"}, "hash", "int", IndexOpts().Sparse()}, "Can't convert 'test' to number"); DoTestEmpty(rt.reindexer, ns, {"sparse2", {"fld2"}, "hash", "string", IndexOpts().Sparse()}, - R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", - "add some sparse index to present part path field. Do nothing"); - ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", - "reload ns (SparseItemTest)", storage); + R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", "add some sparse index to present part path field. Do nothing"); + ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"fld1":1,"fld2":{"nested":"test"}})", "reload ns (SparseItemTest)", storage); } TEST_F(IndexTupleTest, NestedUpdateTest) { @@ -364,19 +359,24 @@ TEST_F(IndexTupleTest, ArrayTest) { {"obj.some.new_array", {"obj.some.new_array", "arr_fld1", "arr_fld2"}, "hash", "int64", IndexOpts().Array(), 0}, R"("array":[],"arr_fld":[],"arr_fld2":[])", "arr_fld2", VariantArray{}.MarkArray(), "add another array index (chooses last of two). Add empty array"); + // TODO: This logic is disabled due to #1819 DoTestDefault(rt.reindexer, ns, {"obj.new.array", {"obj.new.array"}, "hash", "int64", IndexOpts().Array(), 0}, - R"("array":[],"arr_fld":[],"arr_fld2":[],"obj":{"new":{"array":[]}})", - "obj.new.array", VariantArray{}, "add new nested (only) index. Add empty array"); + R"("array":[],"arr_fld":[],"arr_fld2":[]})" /*,"obj":{"new":{"array":[]}})"*/, "obj.new.array", VariantArray{}, + "add new nested (only) index. Add empty array"); + // TODO: This logic is disabled due to #1819 DoTestDefault(rt.reindexer, ns, {"arr", "hash", "int64", IndexOpts().Array()}, - R"("array":[],"arr_fld":[],"arr_fld2":[],"obj":{"new":{"array":[]}},"arr":[])", - "arr", VariantArray{}, "add new field with nested (only) indexes. Add empty array"); + R"("array":[],"arr_fld":[],"arr_fld2":[],"arr":[]})" /*,"obj":{"new":{"array":[]}},"arr":[])"*/, "arr", VariantArray{}, + "add new field with nested (only) indexes. Add empty array"); DoCallAndCheckError(rt.reindexer, ns, {"arr_restriction", {"arr_fld3", "arr_fld4", "arr.some.arr_1st"}, "hash", "int64", IndexOpts().Array(), 0}, "Cannot add field with name 'arr_restriction' (jsonpath 'arr.some.arr_1st') and type 'int64' to namespace" " 'testNSArray'. Already exists json path 'arr' with type 'int64' in field 'arr'. Rewriting is impossible"); DoTestEmpty(rt.reindexer, ns, {"new_sparse_array", {"new_sparse_array"}, "hash", "int64", IndexOpts().Array().Sparse(), 0}, - R"({"id":%d,"array":[],"arr_fld":[],"arr_fld2":[],"obj":{"new":{"array":[]}},"arr":[]})", "add new sparse array index. Do nothing"); - ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"array":[],"arr_fld":[],"arr_fld2":[],"obj":{"new":{"array":[]}},"arr":[]})", "reload ns (ArrayTest)", storage); + R"({"id":%d,"array":[],"arr_fld":[],"arr_fld2":[],"arr":[]})" /*,"obj":{"new":{"array":[]}},"arr":[]})"*/, + "add new sparse array index. Do nothing"); + ValidateReloadState(rt.reindexer, ns, + R"({"id":%d,"array":[],"arr_fld":[],"arr_fld2":[],"arr":[]})" /*,"obj":{"new":{"array":[]}},"arr":[]})"*/, + "reload ns (ArrayTest)", storage); } TEST_F(IndexTupleTest, ArrayNestedTest) { @@ -387,28 +387,42 @@ TEST_F(IndexTupleTest, ArrayNestedTest) { "Can't convert 'OK' to number"); DoCallAndCheckError(rt.reindexer, ns, {"try_change_type", {"last.text"}, "hash", "int", IndexOpts().Array()}, "Can't convert 'OK' to number"); + // TODO: This logic is disabled due to #1819 DoTestDefault( rt.reindexer, ns, {"next.another.last", {"next.another.last"}, "hash", "string", IndexOpts().Array()}, - R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}})", + R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}]})" /*,"next":{"another":{"last":[]}})"*/ + , "next.another.last", VariantArray{}, "add nested index to field by new path. Add empty array"); DoTestDefault( rt.reindexer, ns, {"obj.alternative", {"obj.alternative"}, "hash", "string", IndexOpts().Array()}, - R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}})", + R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}]})" /*,"next":{"another":{"last":[]}})"*/ + , "obj.alternative", VariantArray{}, "add nested index to field. Add empty array"); + DoTestDefault( - rt.reindexer, ns, {"last.1st.2nd.ext.more", {"last.1st.2nd.ext.more"}, "hash", "string", IndexOpts().Array()}, - R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":{"more":[]}}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}})", + rt.reindexer, ns, {"last.1st.2nd.ext", {"last.1st.2nd.ext"}, "hash", "string", IndexOpts().Array()}, + R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":[]}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}]})" /*,"next":{"another":{"last":[]}})"*/ + , "last.1st.2nd.ext.more", VariantArray{}, "add nested-nested index to field. Add empty array"); - DoCallAndCheckError(rt.reindexer, ns, - {"last.1st.2nd.ext.more", {"last.alt", "last.1st.2nd.ext.more"}, "hash", "string", IndexOpts().Array()}, - "Index 'testNSArrayObj.last.1st.2nd.ext.more' already exists with different settings"); + DoCallAndCheckError(rt.reindexer, ns, {"last.1st.2nd.ext", {"last.alt", "last.1st.2nd.ext"}, "hash", "string", IndexOpts().Array()}, + "Index 'testNSArrayObj.last.1st.2nd.ext' already exists with different settings"); + // TODO: This logic is disabled due to #1819 + // DoTestDefault( + // rt.reindexer, ns, {"last.1st.2nd.ext.more", {"last.1st.2nd.ext.more"}, "hash", "string", IndexOpts().Array()}, + // R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":{"more":[]}}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}})", + // "last.1st.2nd.ext.more", VariantArray{}, "add nested-nested index to field. Add empty array"); + // DoCallAndCheckError(rt.reindexer, ns, + // {"last.1st.2nd.ext.more", {"last.alt", "last.1st.2nd.ext.more"}, "hash", "string", IndexOpts().Array()}, + // "Index 'testNSArrayObj.last.1st.2nd.ext.more' already exists with different settings"); DoTestDefault( rt.reindexer, ns, {"last.1st.ext", {"last.1st.ext"}, "hash", "string", IndexOpts().Array()}, - R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":{"more":[]}}},"ext":[]},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}})", + R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":[]}},"ext":[]},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}]})" /*,"next":{"another":{"last":[]}})"*/ + , "last.1st.ext", VariantArray{}, "add array index into the presented nested field. Add empty array"); ValidateReloadState( rt.reindexer, ns, - R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":{"more":[]}}},"ext":[]},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}],"next":{"another":{"last":[]}}})", + R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0,"alternative":[]},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14,"ext":[]}},"ext":[]},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}]})" /*,"next":{"another":{"last":[]}}})"*/ + , "reload ns (ArrayNestedTest)", storage); } @@ -416,25 +430,26 @@ TEST_F(IndexTupleTest, ArrayInToArrayTest) { static const std::string ns = "testNSArrayArr"; const auto storage = CreateNamespace(ns); + // TODO: This logic is disabled due to #1819 DoTestDefault( rt.reindexer, ns, {"objs.more", {"objs.more"}, "hash", "string", IndexOpts().Array()}, - R"("objs":[{"fld":1,"more":[]},{"fld":2,"more":[]},{"fld":5,"more":[]}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}])", - "obj.more", VariantArray{}, "add nested index into array. Add empty array"); + R"("objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":[3,2,1]},{"field":11},{"field":[9]}]}])", + "obj.more", VariantArray{}, "do not add anything into objects array"); DoTestEmpty( rt.reindexer, ns, {"arr.nested_arr.field", {"arr.nested_arr.field"}, "hash", "string", IndexOpts().Array()}, - R"({"id":%d,"objs":[{"fld":1,"more":[]},{"fld":2,"more":[]},{"fld":5,"more":[]}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", + R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", "add nested index to array array (update). Do nothing"); DoTestEmpty( rt.reindexer, ns, {"arr.new_fld", {"arr.new_fld"}, "hash", "string", IndexOpts().Array()}, - R"({"id":%d,"objs":[{"fld":1,"more":[]},{"fld":2,"more":[]},{"fld":5,"more":[]}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", + R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", "add nested index to array array. Do nothing"); DoTestEmpty( rt.reindexer, ns, {"arr.nested_arr.ext_fld", {"arr.nested_arr.ext_fld"}, "hash", "string", IndexOpts().Array()}, - R"({"id":%d,"objs":[{"fld":1,"more":[]},{"fld":2,"more":[]},{"fld":5,"more":[]}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", + R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", "add nested nested index to array array. Do nothing"); ValidateReloadState( rt.reindexer, ns, - R"({"id":%d,"objs":[{"fld":1,"more":[]},{"fld":2,"more":[]},{"fld":5,"more":[]}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", + R"({"id":%d,"objs":[{"fld":1},{"fld":2},{"fld":5}],"obj":{"nested":0},"last":{"text":"OK","1st":{"2nd":{"3rd":3.14}}},"arr":[{"nested_arr":[{"field":["3","2","1"]},{"field":"11"},{"field":["9"]}]}]})", "reload ns (ArrayInToArrayTest)", storage); } @@ -462,8 +477,7 @@ TEST_F(IndexTupleTest, NullTest) { // update only one first item { - const std::string sql = "UPDATE testNSNull SET fld1 = null, fld2 = [null, null] WHERE id = " + - std::to_string(IdStart); + const std::string sql = "UPDATE testNSNull SET fld1 = null, fld2 = [null, null] WHERE id = " + std::to_string(IdStart); Query query = Query::FromSQL(sql); QueryResults qr; auto err = rt.reindexer->Update(query, qr); @@ -479,8 +493,8 @@ TEST_F(IndexTupleTest, NullTest) { ASSERT_TRUE(err.ok()) << err.what(); } - SpecialCheckForNull(rt.reindexer, ns, R"({"id":%d,"fld1":null,"fld2":["null","null"]})", - R"({"id":%d,"fld1":0,"fld2":[]})", "null values test", storage); + SpecialCheckForNull(rt.reindexer, ns, R"({"id":%d,"fld1":null,"fld2":["null","null"]})", R"({"id":%d,"fld1":0,"fld2":[]})", + "null values test", storage); } TEST_F(IndexTupleTest, FailTest) { @@ -489,8 +503,8 @@ TEST_F(IndexTupleTest, FailTest) { DoTestDefault(rt.reindexer, ns, {"nest", {"obj.nest"}, "hash", "int", IndexOpts()}, R"("obj":{"nest":0})", "nest", VariantArray{Variant{0}}, "add nest. Add default value"); - DoTestDefault(rt.reindexer, ns, {"idx", {"idx"}, "-", "bool", IndexOpts()}, R"("obj":{"nest":0},"idx":false)", - "idx", VariantArray{Variant{false}}, "add idx. Add default value"); + DoTestDefault(rt.reindexer, ns, {"idx", {"idx"}, "-", "bool", IndexOpts()}, R"("obj":{"nest":0},"idx":false)", "idx", + VariantArray{Variant{false}}, "add idx. Add default value"); ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"obj":{"nest":0},"idx":false})", "reload ns (FailTest)", storage); } @@ -498,9 +512,12 @@ TEST_F(IndexTupleTest, NestedArrayTest) { static const std::string ns = "testNSNestedArray"; const auto storage = CreateArrayNamespace(ns); + // TODO: This logic is disabled due to #1819 DoTestDefault(rt.reindexer, ns, {"obj.obj1.arr", {"obj.obj1.arr"}, "hash", "int", IndexOpts().Array()}, - R"("obj":{"val":10,"obj1":{"arr":[]}},"arr":[1,2,3])", "obj.obj1.arr", - VariantArray{}, "add obj.obj1.arr. Add default value"); - ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"obj":{"val":10,"obj1":{"arr":[]}},"arr":[1,2,3]})", - "reload ns (NestedArrayTest)", storage); + R"("obj":{"val":10},"arr":[1,2,3])", "obj.obj1.arr", VariantArray{}, + // R"("obj":{"val":10,"obj1":{"arr":[]}},"arr":[1,2,3])", "obj.obj1.arr", VariantArray{}, + "add obj.obj1.arr. Add default value"); + DoTestDefault(rt.reindexer, ns, {"obj.arr", {"obj.arr"}, "hash", "int", IndexOpts().Array()}, + R"("obj":{"val":10,"arr":[]},"arr":[1,2,3])", "obj.arr", VariantArray{}, "add obj.arr. Add default value"); + ValidateReloadState(rt.reindexer, ns, R"({"id":%d,"obj":{"val":10,"arr":[]},"arr":[1,2,3]})", "reload ns (NestedArrayTest)", storage); } diff --git a/cpp_src/gtests/tests/unit/join_test.cc b/cpp_src/gtests/tests/unit/join_test.cc index f143594cc..bd50e388f 100644 --- a/cpp_src/gtests/tests/unit/join_test.cc +++ b/cpp_src/gtests/tests/unit/join_test.cc @@ -183,7 +183,9 @@ TEST_F(JoinSelectsApi, LeftJoinTest) { const reindexer::ItemRef& rowid = rowIt.GetItemRef(); auto itemIt = rowIt.GetJoined(); - if (itemIt.getJoinedItemsCount() == 0) continue; + if (itemIt.getJoinedItemsCount() == 0) { + continue; + } for (auto joinedFieldIt = itemIt.begin(); joinedFieldIt != itemIt.end(); ++joinedFieldIt) { reindexer::ItemImpl item2(joinedFieldIt.GetItem(0, joinQueryRes.getPayloadType(1), joinQueryRes.getTagsMatcher(1))); Variant authorIdKeyRef2 = item2.GetField(joinQueryRes.getPayloadType(1).FieldByName(authorid_fk)); @@ -198,7 +200,9 @@ TEST_F(JoinSelectsApi, LeftJoinTest) { for (auto rowIt : joinQueryRes) { IdType rowid = rowIt.GetItemRef().Id(); auto itemIt = rowIt.GetJoined(); - if (itemIt.getJoinedItemsCount() == 0) continue; + if (itemIt.getJoinedItemsCount() == 0) { + continue; + } auto joinedFieldIt = itemIt.begin(); for (int i = 0; i < joinedFieldIt.ItemsCount(); ++i) { reindexer::ItemImpl item(joinedFieldIt.GetItem(i, joinQueryRes.getPayloadType(1), joinQueryRes.getTagsMatcher(1))); @@ -296,7 +300,9 @@ TEST_F(JoinSelectsApi, JoinTestSorting) { Variant key = item[authorid]; auto itemIt = rowIt.GetJoined(); - if (itemIt.getJoinedItemsCount() == 0) continue; + if (itemIt.getJoinedItemsCount() == 0) { + continue; + } auto joinedFieldIt = itemIt.begin(); Variant prevJoinedValue; @@ -443,17 +449,23 @@ TEST_F(JoinSelectsApi, JoinsEasyStressTest) { std::vector threads; for (size_t i = 0; i < 20; ++i) { threads.push_back(std::thread(selectTh)); - if (i % 2 == 0) threads.push_back(std::thread(removeTh)); - if (i % 4 == 0) threads.push_back(std::thread([this, since, count]() { FillBooksNamespace(since, count); })); + if (i % 2 == 0) { + threads.push_back(std::thread(removeTh)); + } + if (i % 4 == 0) { + threads.push_back(std::thread([this, since, count]() { FillBooksNamespace(since, count); })); + } since += 1000; } - for (size_t i = 0; i < threads.size(); ++i) threads[i].join(); + for (size_t i = 0; i < threads.size(); ++i) { + threads[i].join(); + } } TEST_F(JoinSelectsApi, JoinPreResultStoreValuesOptimizationStressTest) { using reindexer::JoinedSelector; static const std::string rightNs = "rightNs"; - static constexpr char const* data = "data"; + static constexpr const char* data = "data"; static constexpr int maxDataValue = 10; static constexpr int maxRightNsRowCount = maxDataValue * JoinedSelector::MaxIterationsForPreResultStoreValuesOptimization(); static constexpr int maxLeftNsRowCount = 10000; @@ -461,7 +473,9 @@ TEST_F(JoinSelectsApi, JoinPreResultStoreValuesOptimizationStressTest) { static std::vector leftNs; if (leftNs.empty()) { leftNs.reserve(leftNsCount); - for (size_t i = 0; i < leftNsCount; ++i) leftNs.push_back("leftNs" + std::to_string(i)); + for (size_t i = 0; i < leftNsCount; ++i) { + leftNs.push_back("leftNs" + std::to_string(i)); + } } const auto createNs = [this](const std::string& ns) { @@ -492,13 +506,17 @@ TEST_F(JoinSelectsApi, JoinPreResultStoreValuesOptimizationStressTest) { // about 50% of queries will use the optimization Query q{Query(leftNs[i]).InnerJoin(data, data, CondEq, Query(rightNs).Where(data, CondEq, rand() % maxDataValue))}; QueryResults qres; - while (!start) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!start) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } Error err = rt.reindexer->Select(q, qres); ASSERT_TRUE(err.ok()) << err.what(); }); } start = true; - for (auto& th : threads) th.join(); + for (auto& th : threads) { + th.join(); + } } static void checkForAllowedJsonTags(const std::vector& tags, gason::JsonValue jsonValue) { diff --git a/cpp_src/gtests/tests/unit/namespace_test.cc b/cpp_src/gtests/tests/unit/namespace_test.cc index 5f0379291..28992e66d 100644 --- a/cpp_src/gtests/tests/unit/namespace_test.cc +++ b/cpp_src/gtests/tests/unit/namespace_test.cc @@ -92,8 +92,8 @@ TEST_F(NsApi, AddTooManyIndexes) { } TEST_F(NsApi, TruncateNamespace) { - TruncateNamespace([&](const std::string &nsName) { return rt.reindexer->TruncateNamespace(nsName); }); - TruncateNamespace([&](const std::string &nsName) { + TruncateNamespace([&](const std::string& nsName) { return rt.reindexer->TruncateNamespace(nsName); }); + TruncateNamespace([&](const std::string& nsName) { QueryResults qr; return rt.reindexer->Select("TRUNCATE " + nsName, qr); }); @@ -214,7 +214,7 @@ TEST_F(NsApi, UpdateIndex) { rt.OpenNamespace(default_namespace); DefineNamespaceDataset(default_namespace, {IndexDeclaration{idIdxName, "hash", "int", IndexOpts().PK(), 0}}); - auto const wrongIdx = reindexer::IndexDef(idIdxName, reindexer::JsonPaths{"wrongPath"}, "hash", "double", IndexOpts().PK()); + const auto wrongIdx = reindexer::IndexDef(idIdxName, reindexer::JsonPaths{"wrongPath"}, "hash", "double", IndexOpts().PK()); err = rt.reindexer->UpdateIndex(default_namespace, wrongIdx); ASSERT_FALSE(err.ok()); EXPECT_EQ(err.what(), "Unsupported combination of field 'id' type 'double' and index type 'hash'"); @@ -228,12 +228,12 @@ TEST_F(NsApi, UpdateIndex) { ASSERT_TRUE(err.ok()) << err.what(); auto nsDefIt = - std::find_if(nsDefs.begin(), nsDefs.end(), [&](const reindexer::NamespaceDef &nsDef) { return nsDef.name == default_namespace; }); + std::find_if(nsDefs.begin(), nsDefs.end(), [&](const reindexer::NamespaceDef& nsDef) { return nsDef.name == default_namespace; }); ASSERT_TRUE(nsDefIt != nsDefs.end()) << "Namespace " + default_namespace + " is not found"; - auto &indexes = nsDefIt->indexes; - auto receivedIdx = std::find_if(indexes.begin(), indexes.end(), [&](const reindexer::IndexDef &idx) { return idx.name_ == idIdxName; }); + auto& indexes = nsDefIt->indexes; + auto receivedIdx = std::find_if(indexes.begin(), indexes.end(), [&](const reindexer::IndexDef& idx) { return idx.name_ == idIdxName; }); ASSERT_TRUE(receivedIdx != indexes.end()) << "Expect index was created, but it wasn't"; reindexer::WrSerializer newIdxSer; @@ -254,7 +254,7 @@ TEST_F(NsApi, QueryperfstatsNsDummyTest) { rt.OpenNamespace(default_namespace); DefineNamespaceDataset(default_namespace, {IndexDeclaration{idIdxName, "hash", "int", IndexOpts().PK(), 0}}); - const char *const configNs = "#config"; + const char* const configNs = "#config"; Item item = NewItem(configNs); ASSERT_TRUE(item.Status().ok()) << item.Status().what(); @@ -304,7 +304,7 @@ TEST_F(NsApi, QueryperfstatsNsDummyTest) { ASSERT_TRUE(err.ok()) << err.what(); }; - auto getPerformanceParams = [&](QueryPerformance &performanceRes) { + auto getPerformanceParams = [&](QueryPerformance& performanceRes) { QueryResults qres; auto err = rt.reindexer->Select(Query("#queriesperfstats").Where("query", CondEq, Variant(querySql)), qres); ASSERT_TRUE(err.ok()) << err.what(); @@ -312,7 +312,7 @@ TEST_F(NsApi, QueryperfstatsNsDummyTest) { auto qr = rt.Select(Query("#queriesperfstats")); ASSERT_TRUE(err.ok()) << err.what(); ASSERT_GT(qr.Count(), 0) << "#queriesperfstats table is empty!"; - for (auto &it : qr) { + for (auto& it : qr) { std::cout << it.GetItem(false).GetJSON() << std::endl; } } @@ -345,11 +345,13 @@ TEST_F(NsApi, QueryperfstatsNsDummyTest) { } } -static void checkIfItemJSONValid(QueryResults::Iterator &it, bool print = false) { +static void checkIfItemJSONValid(QueryResults::Iterator& it, bool print = false) { reindexer::WrSerializer wrser; Error err = it.GetJSON(wrser, false); ASSERT_TRUE(err.ok()) << err.what(); - if (err.ok() && print) std::cout << wrser.Slice() << std::endl; + if (err.ok() && print) { + std::cout << wrser.Slice() << std::endl; + } } TEST_F(NsApi, TestUpdateIndexedField) { @@ -442,7 +444,7 @@ TEST_F(NsApi, TestUpdateNewFieldCheckTmVersion) { DefineDefaultNamespace(); FillDefaultNamespace(); - auto check = [this](const Query &query, int tmVersion) { + auto check = [this](const Query& query, int tmVersion) { auto qrUpdate = rt.UpdateQR(query); ASSERT_EQ(qrUpdate.Count(), 1); ASSERT_EQ(qrUpdate.getTagsMatcher(0).version(), tmVersion); @@ -472,7 +474,7 @@ TEST_F(NsApi, TestUpdateNewFieldCheckTmVersion) { check(updateQuery, tmVersion); } -static void checkUpdateArrayFieldResults(std::string_view updateFieldPath, const QueryResults &results, const VariantArray &values) { +static void checkUpdateArrayFieldResults(std::string_view updateFieldPath, const QueryResults& results, const VariantArray& values) { for (auto it : results) { Item item = it.GetItem(false); VariantArray val = item[updateFieldPath]; @@ -495,8 +497,8 @@ static void checkUpdateArrayFieldResults(std::string_view updateFieldPath, const } } -static void updateArrayField(const std::shared_ptr &reindexer, const std::string &ns, - std::string_view updateFieldPath, const VariantArray &values) { +static void updateArrayField(const std::shared_ptr& reindexer, const std::string& ns, + std::string_view updateFieldPath, const VariantArray& values) { QueryResults qrUpdate; { SCOPED_TRACE("Checking array update"); @@ -610,8 +612,8 @@ TEST_F(NsApi, TestUpdateIndexedArrayField2) { ASSERT_NE(pos, std::string::npos) << "'indexed_array_field' was not updated properly" << json; } -static void addAndSetNonindexedField(const std::shared_ptr &reindexer, const std::string &ns, - const std::string &updateFieldPath) { +static void addAndSetNonindexedField(const std::shared_ptr& reindexer, const std::string& ns, + const std::string& updateFieldPath) { QueryResults qrUpdate; Query updateQuery{Query(ns).Where("nested.bonus", CondGe, Variant(500)).Set(updateFieldPath, static_cast(777))}; Error err = reindexer->Update(updateQuery, qrUpdate); @@ -648,7 +650,7 @@ TEST_F(NsApi, TestAddAndSetNonindexedField3) { addAndSetNonindexedField(rt.reindexer, default_namespace, "nested3.nested4.extrabonus"); } -static void setAndCheckArrayItem(const std::shared_ptr &reindexer, std::string_view ns, std::string_view fullItemPath, +static void setAndCheckArrayItem(const std::shared_ptr& reindexer, std::string_view ns, std::string_view fullItemPath, std::string_view jsonPath, std::string_view description, int i = IndexValueType::NotSet, int j = IndexValueType::NotSet) { SCOPED_TRACE(description); @@ -668,7 +670,7 @@ static void setAndCheckArrayItem(const std::shared_ptr &re // Check if array item with appropriate index equals to 777 and // is a type of Int64. - auto checkItem = [](const VariantArray &values, size_t index, std::string_view description) { + auto checkItem = [](const VariantArray& values, size_t index, std::string_view description) { SCOPED_TRACE(description); ASSERT_LT(index, values.size()); ASSERT_TRUE(values[index].Type().Is()); @@ -777,8 +779,8 @@ TEST_F(NsApi, TestAddAndSetArrayField4) { } } -static void dropArrayItem(const std::shared_ptr &reindexer, const std::string &ns, const std::string &fullItemPath, - const std::string &jsonPath, int i = IndexValueType::NotSet, int j = IndexValueType::NotSet) { +static void dropArrayItem(const std::shared_ptr& reindexer, const std::string& ns, const std::string& fullItemPath, + const std::string& jsonPath, int i = IndexValueType::NotSet, int j = IndexValueType::NotSet) { // Drop item(s) with name = fullItemPath QueryResults qrUpdate; Query updateQuery{Query(ns).Where("nested.bonus", CondGe, Variant(500)).Drop(fullItemPath)}; @@ -986,8 +988,8 @@ TEST_F(NsApi, ExtendArrayWithExpressions) { } } -static void validateResults(const std::shared_ptr &reindexer, const Query &baseQuery, const Query &testQuery, - std::string_view ns, std::string_view pattern, std::string_view field, const VariantArray &expectedValues, +static void validateResults(const std::shared_ptr& reindexer, const Query& baseQuery, const Query& testQuery, + std::string_view ns, std::string_view pattern, std::string_view field, const VariantArray& expectedValues, std::string_view description, int resCount = 5) { SCOPED_TRACE(description); @@ -1499,16 +1501,14 @@ TEST_F(NsApi, ArrayRemoveSeveralJsonPathsField) { } TEST_F(NsApi, ArrayRemoveWithSql) { - // 1. Define NS - // 2. Fill NS DefineDefaultNamespace(); AddUnindexedData(); - // 3. Remove from array_field with expression substantially + // Remove from array_field with expression substantially { - Query updateQuery = Query::FromSQL( + auto updateQuery = Query::FromSQL( "update test_namespace set array_field = [0] || array_remove(array_field, [3,2,1])" - " || array_remove_once(indexed_array_field, [99]) || [7,9]"); + " || array_remove_once(indexed_array_field, 99) || [7,9]"); auto qrUpdate = rt.UpdateQR(updateQuery); // Check if array_field was modified properly @@ -1516,21 +1516,39 @@ TEST_F(NsApi, ArrayRemoveWithSql) { Item item = it.GetItem(false); checkIfItemJSONValid(it); VariantArray values = item["array_field"]; - ASSERT_EQ(values.size(), 1 + 8 + 2); - int i = 0; - ASSERT_EQ(values[i++].As(), 0); - for (int k = 1; k < 9; ++k) { - ASSERT_EQ(values[i++].As(), k * 11); + ASSERT_EQ(values.size(), 1 + 8 + 2); // [0] || [11,22,33,44,55,66,77,88] || [7,9] remove 99 + int i = 0; // 1 + for ( ; i < 9; ++i) { + ASSERT_EQ(values[i].As(), i * 11); // +8 } ASSERT_EQ(values[i++].As(), 7); - ASSERT_EQ(values[i++].As(), 9); + ASSERT_EQ(values[i].As(), 9); // +2 + } + } + + // Remove scalar value of an array_field + { + auto updateQuery = Query::FromSQL("update test_namespace set array_field = array_remove(array_field, 7)"); + auto qrUpdate = rt.UpdateQR(updateQuery); + + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["array_field"]; + ASSERT_EQ(values.size(), 1 + 8 + 1); // [0,11,22,33,44,55,66,77,88,9] remove 7 + int i = 0; // 1 + for ( ; i < 9; ++i) { + ASSERT_EQ(values[i].As(), i * 11); // +8 + } + ASSERT_EQ(values[i].As(), 9); // +1 } } - // 4. Second attempt. Remove & concatenate for string array field + // Remove & concatenate for string array field { - Query updateQuery = - Query::FromSQL("update test_namespace set string_array = array_remove(string_array, [\'first\']) || [\'POCOMAXA\']"); + auto updateQuery = + Query::FromSQL(R"(update test_namespace set string_array = array_remove(string_array, ['first']) || ['POCOMAXA'])"); auto qrUpdate = rt.UpdateQR(updateQuery); // Check if array_field was modified properly @@ -1544,9 +1562,121 @@ TEST_F(NsApi, ArrayRemoveWithSql) { ASSERT_EQ(values[2].As(), "POCOMAXA"); } } + + // Remove scalar value from string array field + { + std::vector words({"second", "third", "POCOMAXA"}); + for (size_t idx = 0, sz = words.size(); idx < sz; ++idx) { + const auto& word = words[idx]; + auto updateQuery = Query::FromSQL(R"(update test_namespace set string_array = array_remove(string_array, ')" + word + R"('))"); + auto qrUpdate = rt.UpdateQR(updateQuery); + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["string_array"]; + ASSERT_EQ(values.size(), sz - 1 - idx); + for (size_t i = 0, sz1 = values.size(); i < sz1; ++i) { + ASSERT_EQ(values[i].As(), words[i + idx + 1]); + } + } + } + } + + // Remove scalar value from bool array field + { + std::vector boolVals({"false", "true"}); + for (size_t idx = 0, sz = boolVals.size(); idx < sz; ++idx) { + const auto& boolVal = boolVals[idx]; + auto updateQuery = Query::FromSQL("update test_namespace set bool_array = array_remove(bool_array, " + boolVal + ")"); + auto qrUpdate = rt.UpdateQR(updateQuery); + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["bool_array"]; + ASSERT_EQ(values.size(), sz - 1 - idx); + for (const auto& value : values) { + ASSERT_EQ(value.As(), true); + } + } + } + } + + // Remove array value from bool array field + { + std::vector boolVals({"true", "false"}); + for (size_t idx = 0, sz = boolVals.size(); idx < sz; ++idx) { + const auto& boolVal = boolVals[idx]; + auto updateQuery = Query::FromSQL("update test_namespace set bool_array2 = array_remove(bool_array2, [" + boolVal + "])"); + auto qrUpdate = rt.UpdateQR(updateQuery); + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["bool_array2"]; + ASSERT_EQ(values.size(), sz - 1 - idx); + for (const auto& value : values) { + ASSERT_EQ(value.As(), false); + } + } + } + } + + // Remove value from array_field by index of an array_field + { + auto updateQuery = Query::FromSQL("update test_namespace set array_field = array_remove(array_field, array_field[0])"); + auto qrUpdate = rt.UpdateQR(updateQuery); + + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["array_field"]; + ASSERT_EQ(values.size(), 9); // [11,22,33,44,55,66,77,88,9] remove 0 + int i = 0; + for ( ; i < 8; ++i) { + ASSERT_EQ(values[i].As(), (i + 1) * 11); // +8 + } + ASSERT_EQ(values[i].As(), 9); // +1 + } + } + + // Remove value from int_field2{88} of an array_field + { + auto updateQuery = Query::FromSQL("update test_namespace set array_field = array_remove(array_field, int_field2)"); + auto qrUpdate = rt.UpdateQR(updateQuery); + + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["array_field"]; + ASSERT_EQ(values.size(), 8); // [11,22,33,44,55,66,77,9] remove 88 + int i = 0; + for ( ; i < 7; ++i) { + ASSERT_EQ(values[i].As(), (i + 1) * 11); // +7 + } + ASSERT_EQ(values[i].As(), 9); // +1 + } + } + + // Remove all elements from array_field. Destroy itself + { + auto updateQuery = Query::FromSQL("update test_namespace set array_field = array_remove(array_field, array_field)"); + auto qrUpdate = rt.UpdateQR(updateQuery); + + // Check if array_field was modified properly + for (auto it : qrUpdate) { + Item item = it.GetItem(false); + checkIfItemJSONValid(it); + VariantArray values = item["array_field"]; + ASSERT_TRUE(values.empty()); + } + } } -static void validateUpdateJSONResults(const std::shared_ptr &reindexer, const Query &updateQuery, +static void validateUpdateJSONResults(const std::shared_ptr& reindexer, const Query& updateQuery, std::string_view expectation, std::string_view description) { SCOPED_TRACE(description); @@ -1747,7 +1877,7 @@ TEST_F(NsApi, UpdateObjectsArray4) { constexpr char kIndexName[] = "objects.array.field"; const Query kBaseQuery = Query(default_namespace).Where("id", CondSet, {1199, 1201, 1203, 1210, 1240}); - auto ValidateResults = [this, &kBaseQuery](const QueryResults &qr, std::string_view pattern, std::string_view description) { + auto ValidateResults = [this, &kBaseQuery](const QueryResults& qr, std::string_view pattern, std::string_view description) { SCOPED_TRACE(description); // Check initial result ASSERT_EQ(qr.Count(), 5); @@ -1772,7 +1902,7 @@ TEST_F(NsApi, UpdateObjectsArray4) { } }; - for (const auto &index : indexTypes) { + for (const auto& index : indexTypes) { Error err = rt.reindexer->TruncateNamespace(default_namespace); ASSERT_TRUE(err.ok()) << err.what(); // 2. Refill NS @@ -1973,14 +2103,14 @@ TEST_F(NsApi, UpdateArrayIndexFieldWithSeveralJsonPaths) { enum class OpT { Insert, Update }; - auto makeFieldsList = [&fieldsValues](const reindexer::fast_hash_set &indexes, OpT type) { + auto makeFieldsList = [&fieldsValues](const reindexer::fast_hash_set& indexes, OpT type) { auto quote = type == OpT::Insert ? '"' : '\''; std::vector Values::*list = type == OpT::Insert ? &Values::valsList : &Values::newValsList; const auto fieldsListTmplt = type == OpT::Insert ? R"("%sfield%d": [%s])" : R"(%sfield%d = [%s])"; std::string fieldsList; for (int idx : indexes) { std::string fieldList; - for (const auto &data : fieldsValues[idx].*list) { + for (const auto& data : fieldsValues[idx].*list) { fieldList += std::string(fieldList.empty() ? "" : ", ") + quote + data + quote; } fieldsList += fmt::sprintf(fieldsListTmplt, fieldsList.empty() ? "" : ", ", idx, fieldList); @@ -1988,12 +2118,12 @@ TEST_F(NsApi, UpdateArrayIndexFieldWithSeveralJsonPaths) { return fieldsList; }; - auto makeItem = [&makeFieldsList](int id, const reindexer::fast_hash_set &indexes) { + auto makeItem = [&makeFieldsList](int id, const reindexer::fast_hash_set& indexes) { auto list = makeFieldsList(indexes, OpT::Insert); return fmt::sprintf(R"({"id": %d%s})", id, (list.empty() ? "" : ", ") + list); }; - auto makeUpdate = [this, &makeFieldsList](int id, const reindexer::fast_hash_set &indexes) { + auto makeUpdate = [this, &makeFieldsList](int id, const reindexer::fast_hash_set& indexes) { return fmt::sprintf("UPDATE %s SET %s WHERE id = %d", default_namespace, makeFieldsList(indexes, OpT::Update), id); }; @@ -2042,8 +2172,8 @@ TEST_F(NsApi, UpdateArrayIndexFieldWithSeveralJsonPaths) { auto item = qr.begin().GetItem(false); for (auto idx : testCases[i].expected()) { int varArrCnt = 0; - for (auto &&var : VariantArray(item[fmt::sprintf("field%d", idx)])) { - const auto &data = testCases[i].updateIdxs.count(idx) ? fieldsValues[idx].newValsList : fieldsValues[idx].valsList; + for (auto&& var : VariantArray(item[fmt::sprintf("field%d", idx)])) { + const auto& data = testCases[i].updateIdxs.count(idx) ? fieldsValues[idx].newValsList : fieldsValues[idx].valsList; ASSERT_EQ(var.As(), data[varArrCnt++]); } } @@ -2114,33 +2244,33 @@ TEST_F(NsApi, UpdateOutOfBoundsArrayField) { const std::string_view name; const std::string baseUpdateExpr; const std::vector arrayIdx; - const std::function createQueryF; + const std::function createQueryF; }; const std::vector cases = { {.name = "update-index-array-field", .baseUpdateExpr = "indexed_array_field[%d]", .arrayIdx = {9, 10, 100, 10000, 5000000}, .createQueryF = - [&](const std::string &path) { + [&](const std::string& path) { return Query(default_namespace).Where("id", CondEq, kTargetID).Set(path, static_cast(777)); }}, {.name = "update-non-indexed-array-field", .baseUpdateExpr = "array_field[%d]", .arrayIdx = {3, 4, 100, 10000, 5000000}, .createQueryF = - [&](const std::string &path) { + [&](const std::string& path) { return Query(default_namespace).Where("id", CondEq, kTargetID).Set(path, static_cast(777)); }}, {.name = "update-object-array-field", .baseUpdateExpr = "nested.nested_array[%d]", .arrayIdx = {3, 4, 100, 10000, 5000000}, - .createQueryF = [&](const std::string &path) { + .createQueryF = [&](const std::string& path) { return Query(default_namespace) .Where("id", CondEq, kTargetID) .SetObject(path, Variant(std::string(R"({"id":5,"name":"fifth", "prices":[3,5,5]})")), false); }}}; - for (auto &c : cases) { + for (auto& c : cases) { SCOPED_TRACE(c.name); for (auto idx : c.arrayIdx) { @@ -2282,8 +2412,8 @@ TEST_F(NsApi, CheckIndexedArrayItem) { } } -static void checkFieldConversion(const std::shared_ptr &reindexer, const std::string &ns, - const std::string &updateFieldPath, const VariantArray &newValue, const VariantArray &updatedValue, +static void checkFieldConversion(const std::shared_ptr& reindexer, const std::string& ns, + const std::string& updateFieldPath, const VariantArray& newValue, const VariantArray& updatedValue, reindexer::KeyValueType sourceType, bool expectFail) { const Query selectQuery{Query(ns).Where("id", CondGe, Variant("500"))}; QueryResults qrUpdate; @@ -2292,7 +2422,9 @@ static void checkFieldConversion(const std::shared_ptr &re Error err = reindexer->Update(updateQuery, qrUpdate); if (expectFail) { if (err.ok()) { - for (auto it : qrUpdate) checkIfItemJSONValid(it, true); + for (auto it : qrUpdate) { + checkIfItemJSONValid(it, true); + } } ASSERT_TRUE(!err.ok()); } else { @@ -2308,7 +2440,7 @@ static void checkFieldConversion(const std::shared_ptr &re Item item = it.GetItem(false); VariantArray val = item[updateFieldPath.c_str()]; ASSERT_TRUE(val.size() == updatedValue.size()); - for (const Variant &v : val) { + for (const Variant& v : val) { ASSERT_TRUE(v.Type().IsSame(sourceType)) << v.Type().Name(); } ASSERT_TRUE(val == updatedValue); @@ -2444,7 +2576,7 @@ TEST_F(NsApi, TestUpdatePkFieldNoConditions) { ASSERT_GT(qr.Count(), 0); int i = 0; - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant intFieldVal = item[idIdxName]; ASSERT_EQ(static_cast(intFieldVal), i + qrCount.totalCount + 100); @@ -2461,7 +2593,7 @@ TEST_F(NsApi, TestUpdateIndexArrayWithNull) { ASSERT_TRUE(err.ok()) << err.what(); ASSERT_EQ(qr.Count(), 1); - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); VariantArray fieldVal = item[indexedArrayField]; ASSERT_TRUE(fieldVal.empty()); @@ -2553,7 +2685,7 @@ TEST_F(NsApi, TestUpdateNonIndexFieldWithNull) { ASSERT_TRUE(err.ok()) << err.what(); ASSERT_EQ(qr.Count(), 1); - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant fieldVal = item["extra"]; ASSERT_TRUE(fieldVal.Type().Is()); @@ -2710,7 +2842,7 @@ TEST_F(NsApi, TestUpdateFieldWithFunction) { ASSERT_GT(qr.Count(), 0); int i = 1; - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant intFieldVal = item[intField]; Variant extraFieldVal = item["extra"]; @@ -2734,7 +2866,7 @@ TEST_F(NsApi, TestUpdateFieldWithExpressions) { ASSERT_GT(qr.Count(), 0); int i = 1; - for (auto &it : qr) { + for (auto& it : qr) { Item item = it.GetItem(false); Variant intFieldVal = item[intField]; Variant extraFieldVal = item["extra"]; @@ -2746,7 +2878,7 @@ TEST_F(NsApi, TestUpdateFieldWithExpressions) { } } -static void checkQueryDsl(const Query &src) { +static void checkQueryDsl(const Query& src) { Query dst; const std::string dsl = src.GetJSON(); Error err = dst.FromJSON(dsl); @@ -2829,7 +2961,7 @@ TEST_F(NsApi, TestModifyQueriesSqlEncoder) { checkQueryDsl(q7); } -static void generateObject(reindexer::JsonBuilder &builder, const std::string &prefix, ReindexerApi *rtapi) { +static void generateObject(reindexer::JsonBuilder& builder, const std::string& prefix, ReindexerApi* rtapi) { builder.Put(prefix + "ID", rand() % 1000); builder.Put(prefix + "Name", rtapi->RandString()); builder.Put(prefix + "Rating", rtapi->RandString()); @@ -2839,7 +2971,9 @@ static void generateObject(reindexer::JsonBuilder &builder, const std::string &p builder.Put(prefix + "Subsription", bool(rand() % 100 > 50 ? 1 : 0)); { auto idsArray = builder.Array(prefix + "IDS"); - for (auto id : rtapi->RandIntVector(10, 10, 1000)) idsArray.Put(0, id); + for (auto id : rtapi->RandIntVector(10, 10, 1000)) { + idsArray.Put(0, id); + } } { auto homogeneousArray = builder.Array(prefix + "HomogeneousValues"); @@ -2857,7 +2991,7 @@ static void generateObject(reindexer::JsonBuilder &builder, const std::string &p } } -void addObjectsArray(reindexer::JsonBuilder &builder, bool withInnerArray, ReindexerApi *rtapi) { +void addObjectsArray(reindexer::JsonBuilder& builder, bool withInnerArray, ReindexerApi* rtapi) { size_t size = rand() % 10 + 5; reindexer::JsonBuilder array = builder.Array("object"); for (size_t i = 0; i < size; ++i) { @@ -2883,7 +3017,9 @@ TEST_F(NsApi, MsgPackEncodingTest) { jsonBuilder.Put("superName", RandString()); { auto priceArray = jsonBuilder.Array("superPrices"); - for (auto price : RandIntVector(10, 10, 1000)) priceArray.Put(0, price); + for (auto price : RandIntVector(10, 10, 1000)) { + priceArray.Put(0, price); + } } { reindexer::JsonBuilder objectBuilder = jsonBuilder.Object("nested1"); @@ -2908,7 +3044,7 @@ TEST_F(NsApi, MsgPackEncodingTest) { size_t offset = 0; Item item2 = NewItem(default_namespace); - err = item2.FromMsgPack(std::string_view(reinterpret_cast(wrSer2.Buf()), wrSer2.Len()), offset); + err = item2.FromMsgPack(std::string_view(reinterpret_cast(wrSer2.Buf()), wrSer2.Len()), offset); ASSERT_TRUE(err.ok()) << err.what(); std::string_view json1(item.GetJSON()); @@ -2925,7 +3061,7 @@ TEST_F(NsApi, MsgPackEncodingTest) { Item item = NewItem(default_namespace); ASSERT_TRUE(item.Status().ok()) << item.Status().what(); - Error err = item.FromMsgPack(std::string_view(reinterpret_cast(wrSer1.Buf()), wrSer1.Len()), offset); + Error err = item.FromMsgPack(std::string_view(reinterpret_cast(wrSer1.Buf()), wrSer1.Len()), offset); ASSERT_TRUE(err.ok()) << err.what(); err = rt.reindexer->Update(default_namespace, item, qr); @@ -2936,7 +3072,7 @@ TEST_F(NsApi, MsgPackEncodingTest) { } reindexer::WrSerializer wrSer3; - for (auto &it : qr) { + for (auto& it : qr) { const auto err = it.GetMsgPack(wrSer3, false); ASSERT_TRUE(err.ok()) << err.what(); } @@ -2947,7 +3083,7 @@ TEST_F(NsApi, MsgPackEncodingTest) { Item item = NewItem(default_namespace); ASSERT_TRUE(item.Status().ok()) << item.Status().what(); - Error err = item.FromMsgPack(std::string_view(reinterpret_cast(wrSer3.Buf()), wrSer3.Len()), offset); + Error err = item.FromMsgPack(std::string_view(reinterpret_cast(wrSer3.Buf()), wrSer3.Len()), offset); ASSERT_TRUE(err.ok()) << err.what(); std::string_view json(item.GetJSON()); @@ -3011,22 +3147,22 @@ TEST_F(NsApi, DeleteLastItems) { } TEST_F(NsApi, IncorrectNsName) { - auto check = [&](const std::vector &names, auto func) { - for (const auto &v : names) { + auto check = [&](const std::vector& names, auto func) { + for (const auto& v : names) { func(v); } }; std::vector variants = {"tes@t1", "@test1", "test1@", "tes#t1", "#test1", "test1#", "test 1", " test1", "test1 ", "'test1'", "\"test1\"", "test1", "/test1", "test1,test2"}; - auto open = [&](const std::string &name) { + auto open = [&](const std::string& name) { Error err = rt.reindexer->OpenNamespace(name); ASSERT_FALSE(err.ok()); ASSERT_EQ(err.what(), "Namespace name contains invalid character. Only alphas, digits,'_','-', are allowed"); }; check(variants, open); - auto add = [&](const std::string &name) { + auto add = [&](const std::string& name) { reindexer::NamespaceDef nsDef(name); Error err = rt.reindexer->AddNamespace(nsDef); ASSERT_FALSE(err.ok()); @@ -3034,7 +3170,7 @@ TEST_F(NsApi, IncorrectNsName) { }; check(variants, add); - auto rename = [&](const std::string &name) { + auto rename = [&](const std::string& name) { const std::string kNsName("test3"); reindexer::NamespaceDef nsDef(kNsName); Error err = rt.reindexer->AddNamespace(nsDef); @@ -3081,7 +3217,7 @@ TEST_F(NsApi, MultiDimensionalArrayQueryErrors) { "explicitly set in the query"; QueryResults qr; - auto &rx = *rt.reindexer; + auto& rx = *rt.reindexer; // Set tuple to the field auto err = rx.Update(Query(default_namespace).Set(field, {Variant{VariantArray::Create({1, 2, 3})}}), qr); diff --git a/cpp_src/gtests/tests/unit/protobuf_test.cc b/cpp_src/gtests/tests/unit/protobuf_test.cc index 2cc866167..885f0c65f 100644 --- a/cpp_src/gtests/tests/unit/protobuf_test.cc +++ b/cpp_src/gtests/tests/unit/protobuf_test.cc @@ -395,7 +395,9 @@ TEST_F(ReindexerApi, ProtobufSchemaFromNsSchema) { } } auto collection = jsonBuilder.Array("Collection"); - for (int i = 0; i < 10; ++i) collection.Put(0, i); + for (int i = 0; i < 10; ++i) { + collection.Put(0, i); + } collection.End(); jsonBuilder.End(); diff --git a/cpp_src/gtests/tests/unit/queries_test.cc b/cpp_src/gtests/tests/unit/queries_test.cc index b394f18fc..f68cc074e 100644 --- a/cpp_src/gtests/tests/unit/queries_test.cc +++ b/cpp_src/gtests/tests/unit/queries_test.cc @@ -16,7 +16,7 @@ TEST_F(QueriesApi, QueriesStandardTestSet) { FillCompositeIndexesNamespace(0, 1000); FillTestSimpleNamespace(); FillComparatorsNamespace(); - FillTestJoinNamespace(); + FillTestJoinNamespace(0, 300); FillGeomNamespace(); CheckStandartQueries(); @@ -36,7 +36,9 @@ TEST_F(QueriesApi, QueriesStandardTestSet) { Error err = rt.reindexer->Delete(default_namespace, it->second); ASSERT_TRUE(err.ok()) << err.what(); it = items.erase(it); - if (++itemsCount == 4000) break; + if (++itemsCount == 4000) { + break; + } } FillDefaultNamespace(0, 500, 0); @@ -47,7 +49,9 @@ TEST_F(QueriesApi, QueriesStandardTestSet) { Error err = rt.reindexer->Delete(default_namespace, it->second); ASSERT_TRUE(err.ok()) << err.what(); it = items.erase(it); - if (++itemsCount == 5000) break; + if (++itemsCount == 5000) { + break; + } } for (size_t i = 0; i < 5000; ++i) { @@ -664,7 +668,9 @@ TEST_F(QueriesApi, DslGenerateParse) { static std::vector generateForcedSortOrder(int maxValue, size_t size) { std::set res; - while (res.size() < size) res.insert(rand() % maxValue); + while (res.size() < size) { + res.insert(rand() % maxValue); + } return {res.cbegin(), res.cend()}; } @@ -801,7 +807,9 @@ TEST_F(QueriesApi, JoinByNotIndexField) { ser.Reset(); reindexer::JsonBuilder json{ser}; json.Put("id", i); - if (i % 2 == 1) json.Put("f", i); + if (i % 2 == 1) { + json.Put("f", i); + } json.End(); Item item = rt.reindexer->NewItem(nsName); ASSERT_TRUE(item.Status().ok()) << item.Status().what(); @@ -1018,16 +1026,22 @@ TEST_F(QueriesApi, TestCsvProcessingWithSchema) { } { auto data0 = json.Array(fmt::sprintf("Array_level0_id_%d", id)); - for (int i = 0; i < 5; ++i) data0.Put(nullptr, fmt::sprintf("array_data_0_%d", i)); + for (int i = 0; i < 5; ++i) { + data0.Put(nullptr, fmt::sprintf("array_data_0_%d", i)); + } data0.Put(nullptr, std::string("\"arr_quoted_field(\"this is quoted too\")\"")); } { auto data0 = json.Object(fmt::sprintf("Object_level0_id_%d", id)); - for (int i = 0; i < 5; ++i) data0.Put(fmt::sprintf("Object_%d", i), fmt::sprintf("object_data_0_%d", i)); + for (int i = 0; i < 5; ++i) { + data0.Put(fmt::sprintf("Object_%d", i), fmt::sprintf("object_data_0_%d", i)); + } data0.Put("Quoted Field lvl0", std::string("\"obj_quoted_field(\"this is quoted too\")\"")); { auto data1 = data0.Object(fmt::sprintf("Object_level1_id_%d", id)); - for (int j = 0; j < 5; ++j) data1.Put(fmt::sprintf("objectData1 %d", j), fmt::sprintf("objectData1 %d", j)); + for (int j = 0; j < 5; ++j) { + data1.Put(fmt::sprintf("objectData1 %d", j), fmt::sprintf("objectData1 %d", j)); + } data1.Put("Quoted Field lvl1", std::string("\"obj_quoted_field(\"this is quoted too\")\"")); } } diff --git a/cpp_src/gtests/tests/unit/query_aggregate_strict_mode_test.h b/cpp_src/gtests/tests/unit/query_aggregate_strict_mode_test.h index 95b40c5fb..f9a3bdb85 100644 --- a/cpp_src/gtests/tests/unit/query_aggregate_strict_mode_test.h +++ b/cpp_src/gtests/tests/unit/query_aggregate_strict_mode_test.h @@ -160,7 +160,11 @@ void QueryAggStrictModeTest(const std::unique_ptr& client) { } }; - for (const auto& aggType : aggTypes) - for (const auto& [field, modes] : scenarios) - for (const auto& [mode, err] : modes) testUnit(field, aggType, mode, err); + for (const auto& aggType : aggTypes) { + for (const auto& [field, modes] : scenarios) { + for (const auto& [mode, err] : modes) { + testUnit(field, aggType, mode, err); + } + } + } } diff --git a/cpp_src/gtests/tests/unit/replication_master_master_test.cc b/cpp_src/gtests/tests/unit/replication_master_master_test.cc index 705eb87c6..cba25beca 100644 --- a/cpp_src/gtests/tests/unit/replication_master_master_test.cc +++ b/cpp_src/gtests/tests/unit/replication_master_master_test.cc @@ -1,5 +1,6 @@ #include #include "core/defnsconfigs.h" +#include "core/formatters/lsn_fmt.h" #include "servercontrol.h" using namespace reindexer; @@ -14,7 +15,9 @@ class ReplicationSlaveSlaveApi : public ::testing::Test { class ServerControlVec : public std::vector { public: ~ServerControlVec() { - for (auto& node : *this) node.Stop(); + for (auto& node : *this) { + node.Stop(); + } } }; @@ -24,9 +27,9 @@ class ReplicationSlaveSlaveApi : public ::testing::Test { ReplicationTestState state1, state2; while (true) { now += pause; - ASSERT_TRUE(now < kMaxSyncTime) << "Wait sync is too long. s1 lsn: " << state1.lsn << "; s2 lsn: " << state2.lsn - << "; s1 count: " << state1.dataCount << "; s2 count: " << state2.dataCount - << " s1 hash: " << state1.dataHash << "; s2 hash: " << state2.dataHash; + ASSERT_TRUE(now < kMaxSyncTime) << fmt::format( + "Wait sync is too long. s1 lsn: {}; s2 lsn: {}; s1 count: {}; s2 count: {}; s1 hash: {}; s2 hash: {}", state1.lsn, + state2.lsn, state1.dataCount, state2.dataCount, state1.dataHash, state2.dataHash); state1 = s1.Get()->GetState(nsName); state2 = s2.Get()->GetState(nsName); if (state1.lsn == state2.lsn && state1.dataCount == state2.dataCount && state1.dataHash == state2.dataHash) { @@ -714,8 +717,12 @@ TEST_F(ReplicationSlaveSlaveApi, NodeWithMasterAndSlaveNs1) { } { std::vector results_data; - for (unsigned int i = 0; i < n; i++) results_data.push_back(c1 + i); - for (unsigned int i = 0; i < n; i++) results_data.push_back(c2 + i); + for (unsigned int i = 0; i < n; i++) { + results_data.push_back(c1 + i); + } + for (unsigned int i = 0; i < n; i++) { + results_data.push_back(c2 + i); + } std::vector results_3; testns3.GetData(slave, results_3); @@ -771,8 +778,12 @@ TEST_F(ReplicationSlaveSlaveApi, NodeWithMasterAndSlaveNs2) { } { std::vector results_data; - for (unsigned int i = 0; i < n; i++) results_data.push_back(c1 + i); - for (unsigned int i = 0; i < n; i++) results_data.push_back(c2 + i); + for (unsigned int i = 0; i < n; i++) { + results_data.push_back(c1 + i); + } + for (unsigned int i = 0; i < n; i++) { + results_data.push_back(c2 + i); + } std::vector results_3; testns3.GetData(slave, results_3); @@ -979,7 +990,9 @@ TEST_F(ReplicationSlaveSlaveApi, RestrictUpdates) { ASSERT_TRUE(err.ok()) << err.what(); master.Get()->api.Upsert(nsName, item); ASSERT_TRUE(err.ok()) << err.what(); - if (i % 100 == 0) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (i % 100 == 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } } }; @@ -1258,7 +1271,7 @@ class ServerIdChange : public ReplicationSlaveSlaveApi, public ::testing::WithPa ASSERT_TRUE(err.ok()) << err.what(); master.Get()->api.Upsert("ns1", item); } - }; + } void ChangeServerId(bool isMaster, ServerControl& node, int newServerId, int port) { if (isMaster) { diff --git a/cpp_src/gtests/tests/unit/replication_test.cc b/cpp_src/gtests/tests/unit/replication_test.cc index b038feef8..3a4449ff8 100644 --- a/cpp_src/gtests/tests/unit/replication_test.cc +++ b/cpp_src/gtests/tests/unit/replication_test.cc @@ -69,7 +69,9 @@ TEST_F(ReplicationLoadApi, Base) { SetWALSize(masterId_, 50000, "some"); for (size_t i = 0; i < 2; ++i) { - if (i % 3 == 0) DeleteFromMaster(); + if (i % 3 == 0) { + DeleteFromMaster(); + } SetWALSize(masterId_, (int64_t(i) + 1) * 25000, "some1"); FillData(1000); SetWALSize(masterId_, (int64_t(i) + 1) * 50000, "some"); @@ -112,7 +114,9 @@ TEST_F(ReplicationLoadApi, BaseTagsMatcher) { SetSchema(masterId_, "some1", kReplTestSchema2); FillData(1000); for (size_t i = 0; i < 2; ++i) { - if (i == 1) DeleteFromMaster(); + if (i == 1) { + DeleteFromMaster(); + } FillData(1000); } StartServer(1); @@ -312,7 +316,9 @@ TEST_F(ReplicationLoadApi, DISABLED_BasicTestNoMasterRestart) { }); for (size_t i = 0; i < 10; ++i) { - if (i % 3 == 0) DeleteFromMaster(); + if (i % 3 == 0) { + DeleteFromMaster(); + } FillData(1000); SimpleSelect(0); SimpleSelect(rand() % 3 + 1); @@ -341,7 +347,9 @@ TEST_F(ReplicationLoadApi, SingleSlaveTest) { counter++; RestartServer(i); - if (counter % 3 == 0) DeleteFromMaster(); + if (counter % 3 == 0) { + DeleteFromMaster(); + } } }); @@ -375,7 +383,9 @@ TEST_F(ReplicationLoadApi, DuplicatePKSlaveTest) { bool isFirst = true; for (const auto id : ids) { - if (!isFirst) changedIds += ", "; + if (!isFirst) { + changedIds += ", "; + } changedIds += std::to_string(id); isFirst = false; } diff --git a/cpp_src/gtests/tests/unit/rpcclient_test.cc b/cpp_src/gtests/tests/unit/rpcclient_test.cc index 153684471..f0181fe67 100644 --- a/cpp_src/gtests/tests/unit/rpcclient_test.cc +++ b/cpp_src/gtests/tests/unit/rpcclient_test.cc @@ -130,12 +130,16 @@ TEST_F(RPCClientTestApi, SeveralDsnReconnect) { ASSERT_TRUE(res.ok()) << res.what(); for (size_t i = 0; i < 100; ++i) { - if (CheckIfFakeServerConnected(uris[0])) break; + if (CheckIfFakeServerConnected(uris[0])) { + break; + } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } for (size_t i = 0; i < 100; ++i) { - if (rx.Status().ok()) break; + if (rx.Status().ok()) { + break; + } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } @@ -146,7 +150,9 @@ TEST_F(RPCClientTestApi, SeveralDsnReconnect) { for (size_t j = 0; j < 10; ++j) { client::QueryResults qr; res = rx.Select(queryConfingNs, qr); - if (res.ok()) break; + if (res.ok()) { + break; + } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } ASSERT_TRUE(res.ok()) << res.what(); @@ -404,7 +410,7 @@ TEST_F(RPCClientTestApi, CoroSelectTimeout) { for (size_t i = 0; i < kCorCount; ++i) { ASSERT_TRUE(finished[i]); } - Error const err = StopServer(); + const Error err = StopServer(); ASSERT_TRUE(err.ok()) << err.what(); } diff --git a/cpp_src/gtests/tests/unit/rtree_test.cc b/cpp_src/gtests/tests/unit/rtree_test.cc index 578bef44d..68ab5bc61 100644 --- a/cpp_src/gtests/tests/unit/rtree_test.cc +++ b/cpp_src/gtests/tests/unit/rtree_test.cc @@ -19,7 +19,9 @@ struct Compare; template <> struct Compare { bool operator()(reindexer::Point lhs, reindexer::Point rhs) const noexcept { - if (lhs.X() == rhs.X()) return lhs.Y() < rhs.Y(); + if (lhs.X() == rhs.X()) { + return lhs.Y() < rhs.Y(); + } return lhs.X() < rhs.X(); } }; @@ -101,7 +103,9 @@ static void TestIterators() { size_t dublicates = 0; for (size_t i = 0; i < 10000 + dublicates; ++i) { const auto res = tree.insert(reindexer::randPoint(kRange)); - if (!res.second) ++dublicates; + if (!res.second) { + ++dublicates; + } ASSERT_TRUE(tree.Check()); auto it = tree.begin(), end = tree.end(); auto cit = tree.cbegin(), cend = tree.cend(); @@ -152,7 +156,9 @@ static void TestSearch() { const reindexer::Point point{randPoint(kRange)}; const double distance = randBinDouble(0, 100); for (const auto& r : data) { - if (reindexer::DWithin(point, r, distance)) DWithinVisitor.Add(r); + if (reindexer::DWithin(point, r, distance)) { + DWithinVisitor.Add(r); + } } tree.DWithin(point, distance, DWithinVisitor); @@ -251,7 +257,9 @@ static void TestMap() { const reindexer::Point point{randPoint(kRange)}; const double distance = randBinDouble(0, 100); for (const auto& r : data) { - if (reindexer::DWithin(point, r.first, distance)) visitor.Add(r); + if (reindexer::DWithin(point, r.first, distance)) { + visitor.Add(r); + } } map.DWithin(point, distance, visitor); ASSERT_EQ(visitor.Size(), 0); diff --git a/cpp_src/gtests/tests/unit/selector_plan_test.cc b/cpp_src/gtests/tests/unit/selector_plan_test.cc index f7978eba4..df77be49e 100644 --- a/cpp_src/gtests/tests/unit/selector_plan_test.cc +++ b/cpp_src/gtests/tests/unit/selector_plan_test.cc @@ -231,7 +231,9 @@ TEST_F(SelectorPlanTest, SortByUnbuiltBtreeIndex) { } for (const char* additionalSearchField : {kFieldId, kFieldTree1, kFieldTree2, kFieldHash}) { - if (additionalSearchField == searchField) continue; + if (additionalSearchField == searchField) { + continue; + } for (const Query& query : {Query(unbuiltBtreeNs).Explain().Where(additionalSearchField, CondEq, RandInt()).Where(searchField, cond, RandInt()), Query(unbuiltBtreeNs) @@ -336,7 +338,9 @@ TEST_F(SelectorPlanTest, SortByUnbuiltBtreeIndex) { } for (const char* additionalSearchField : {kFieldId, kFieldTree1, kFieldTree2, kFieldHash}) { - if (additionalSearchField == searchField) continue; + if (additionalSearchField == searchField) { + continue; + } for (const Query& query : {Query(unbuiltBtreeNs) .Explain() .Where(additionalSearchField, CondEq, RandInt()) diff --git a/cpp_src/gtests/tests/unit/tolal_lru_cache.cc b/cpp_src/gtests/tests/unit/tolal_lru_cache.cc index f3e7890f7..80832acba 100644 --- a/cpp_src/gtests/tests/unit/tolal_lru_cache.cc +++ b/cpp_src/gtests/tests/unit/tolal_lru_cache.cc @@ -145,7 +145,7 @@ TEST(LruCache, StressTest) { threads.emplace_back([&]() { for (auto i = 0; i < iterCount; i++) { auto idx = rand() % qs.size(); - auto const& qce = qs.at(idx); + const auto& qce = qs.at(idx); QueryCacheKey ckey{qce, kCountCachedKeyMode, static_cast(nullptr)}; auto cached = cache.Get(ckey); diff --git a/cpp_src/gtests/tests/unit/ttl_index_api.cc b/cpp_src/gtests/tests/unit/ttl_index_api.cc index 51c2b6ecb..b2d8910d8 100644 --- a/cpp_src/gtests/tests/unit/ttl_index_api.cc +++ b/cpp_src/gtests/tests/unit/ttl_index_api.cc @@ -27,7 +27,9 @@ TEST_F(TtlIndexApi, ItemsVanishingAfterInsertRemove) { threads.emplace_back(std::thread(&TtlIndexApi::RemoveItemsSlowly, this)); threads.emplace_back(std::thread(&TtlIndexApi::SelectData, this)); - for (size_t i = 0; i < threads.size(); ++i) threads[i].join(); + for (size_t i = 0; i < threads.size(); ++i) { + threads[i].join(); + } std::this_thread::sleep_for(std::chrono::milliseconds(2000)); count = WaitForVanishing(); diff --git a/cpp_src/gtests/tests/unit/uuid.cc b/cpp_src/gtests/tests/unit/uuid.cc index 96c20878e..09801c0c9 100644 --- a/cpp_src/gtests/tests/unit/uuid.cc +++ b/cpp_src/gtests/tests/unit/uuid.cc @@ -155,7 +155,9 @@ static void fillItemThroughJson(reindexer::Item& item, int id, Values& v template static void fillItem(reindexer::Item& item, int id, Values& value) { - if (rand() % 3 == 0) return fillItemThroughJson(item, id, value); + if (rand() % 3 == 0) { + return fillItemThroughJson(item, id, value); + } ASSERT_TRUE(item.Status().ok()) << item.Status().what(); fillRndValue(value); item["id"] = id; @@ -359,7 +361,9 @@ TEST(UUID, DropIndex) { std::vector> testValues1; testValues1.reserve(uuidValues.size()); - for (const auto& value : uuidValues) testValues1.emplace_back(value.scalar, value.array); + for (const auto& value : uuidValues) { + testValues1.emplace_back(value.scalar, value.array); + } test(rx, testValues1, EmptyValues::CouldBeEmpty); err = rx.DropIndex(nsName, {"uuid_a"}); @@ -371,7 +375,9 @@ TEST(UUID, DropIndex) { if (value.array) { std::vector strUuidArray; strUuidArray.reserve(value.array->size()); - for (auto uuid : *value.array) strUuidArray.emplace_back(uuid); + for (auto uuid : *value.array) { + strUuidArray.emplace_back(uuid); + } testValues2.emplace_back(value.scalar, std::move(strUuidArray)); } else { testValues2.emplace_back(value.scalar, std::nullopt); @@ -400,7 +406,9 @@ TEST(UUID, AddIndex) { if (value.array) { std::vector strValues; strValues.reserve(value.array->size()); - for (auto uuid : *value.array) strValues.emplace_back(uuid); + for (auto uuid : *value.array) { + strValues.emplace_back(uuid); + } testValues1.emplace_back(value.scalar, std::move(strValues)); } else { testValues1.emplace_back(value.scalar, std::nullopt); @@ -446,7 +454,9 @@ TEST(UUID, UpdateIndexUuidToString) { std::vector> testValues1; testValues1.reserve(uuidValues.size()); - for (const auto& value : uuidValues) testValues1.emplace_back(value.scalar, value.array); + for (const auto& value : uuidValues) { + testValues1.emplace_back(value.scalar, value.array); + } test(rx, testValues1); err = rx.UpdateIndex(nsName, reindexer::IndexDef{"uuid_a", "hash", "string", IndexOpts().Array()}); @@ -458,7 +468,9 @@ TEST(UUID, UpdateIndexUuidToString) { if (value.array) { std::vector strUuidArray; strUuidArray.reserve(value.array->size()); - for (auto uuid : *value.array) strUuidArray.emplace_back(uuid); + for (auto uuid : *value.array) { + strUuidArray.emplace_back(uuid); + } testValues2.emplace_back(value.scalar, std::move(strUuidArray)); } else { testValues2.emplace_back(value.scalar, std::nullopt); @@ -487,7 +499,9 @@ TEST(UUID, UpdateIndexStringToUuid) { std::vector> testValues1; testValues1.reserve(strUuidValues.size()); - for (const auto& value : strUuidValues) testValues1.emplace_back(value.scalar, value.array); + for (const auto& value : strUuidValues) { + testValues1.emplace_back(value.scalar, value.array); + } test(rx, testValues1); err = rx.UpdateIndex(nsName, reindexer::IndexDef{"uuid_a", "hash", "uuid", IndexOpts().Array()}); @@ -499,7 +513,9 @@ TEST(UUID, UpdateIndexStringToUuid) { if (value.array) { std::vector uuidArray; uuidArray.reserve(value.array->size()); - for (const auto& uuid : *value.array) uuidArray.emplace_back(uuid); + for (const auto& uuid : *value.array) { + uuidArray.emplace_back(uuid); + } testValues2.emplace_back(value.scalar, std::move(uuidArray)); } else { testValues2.emplace_back(value.scalar, std::nullopt); @@ -528,7 +544,9 @@ TEST(UUID, AddArrayUuidIndexOnNotArrayField) { std::vector> testValues; testValues.reserve(strUuidValues.size()); - for (const auto& value : strUuidValues) testValues.emplace_back(value.scalar, value.array); + for (const auto& value : strUuidValues) { + testValues.emplace_back(value.scalar, value.array); + } test(rx, testValues); } catch (const reindexer::Error& e) { ASSERT_TRUE(false) << e.what() << std::endl; diff --git a/cpp_src/gtests/tests/unit/value_by_json_path.cc b/cpp_src/gtests/tests/unit/value_by_json_path.cc index ebf460ece..7c162d019 100644 --- a/cpp_src/gtests/tests/unit/value_by_json_path.cc +++ b/cpp_src/gtests/tests/unit/value_by_json_path.cc @@ -91,7 +91,9 @@ TEST_F(ReindexerApi, SelectByJsonPath) { std::string dumpField = "str_" + pk; snprintf(json, sizeof(json) - 1, jsonPattern, pk.c_str(), dumpField.c_str(), i); - if (i >= 5) properIntValues.push_back(i); + if (i >= 5) { + properIntValues.push_back(i); + } err = item.FromJSON(json); ASSERT_TRUE(err.ok()) << err.what(); diff --git a/cpp_src/gtests/tools.h b/cpp_src/gtests/tools.h index 7095193b9..d597d23ac 100644 --- a/cpp_src/gtests/tools.h +++ b/cpp_src/gtests/tools.h @@ -10,7 +10,9 @@ inline bool isUuidDelimPos(unsigned i) noexcept { } inline std::string randStrUuid() { - if (rand() % 1000 == 0) return std::string{nilUUID}; + if (rand() % 1000 == 0) { + return std::string{nilUUID}; + } std::string strUuid; strUuid.reserve(reindexer::Uuid::kStrFormLen); for (size_t i = 0; i < reindexer::Uuid::kStrFormLen; ++i) { diff --git a/cpp_src/net/connectinstatscollector.h b/cpp_src/net/connectinstatscollector.h index fa1a8dff8..77c54d10d 100644 --- a/cpp_src/net/connectinstatscollector.h +++ b/cpp_src/net/connectinstatscollector.h @@ -32,7 +32,7 @@ class connection_stats_collector { std::shared_ptr get_stat() const noexcept { return stat_; } - void attach(ev::dynamic_loop &loop) noexcept; + void attach(ev::dynamic_loop& loop) noexcept; void detach() noexcept; void restart(); void stop() noexcept; @@ -51,7 +51,7 @@ class connection_stats_collector { void update_send_buf_size(size_t size) noexcept { stat_->send_buf_bytes.store(size, std::memory_order_relaxed); } protected: - void stats_check_cb(ev::periodic &watcher, int) noexcept; + void stats_check_cb(ev::periodic& watcher, int) noexcept; private: std::shared_ptr stat_; diff --git a/cpp_src/net/connection.cc b/cpp_src/net/connection.cc index 219895efb..c8ee193ac 100644 --- a/cpp_src/net/connection.cc +++ b/cpp_src/net/connection.cc @@ -5,7 +5,7 @@ namespace reindexer { namespace net { template -Connection::Connection(socket &&s, ev::dynamic_loop &loop, bool enableStat, size_t readBufSize, size_t writeBufSize, int idleTimeout) +Connection::Connection(socket&& s, ev::dynamic_loop& loop, bool enableStat, size_t readBufSize, size_t writeBufSize, int idleTimeout) : sock_(std::move(s)), curEvents_(0), wrBuf_(writeBufSize), @@ -22,7 +22,7 @@ Connection::~Connection() { } template -void Connection::restart(socket &&s) { +void Connection::restart(socket&& s) { assertrx(!sock_.valid()); sock_ = std::move(s); wrBuf_.clear(); @@ -36,12 +36,14 @@ void Connection::restart(socket &&s) { } template -void Connection::attach(ev::dynamic_loop &loop) { +void Connection::attach(ev::dynamic_loop& loop) { assertrx(!attached_); io_.set(this); io_.set(loop); if (sock_.valid()) { - if (curEvents_) io_.start(sock_.fd(), curEvents_); + if (curEvents_) { + io_.start(sock_.fd(), curEvents_); + } clientAddr_ = sock_.addr(); } timeout_.set(this); @@ -81,15 +83,19 @@ void Connection::closeConn() { } timeout_.stop(); async_.stop(); - if (stats_) stats_->stop(); + if (stats_) { + stats_->stop(); + } onClose(); closeConn_ = false; } // Generic callback template -void Connection::callback(ev::io & /*watcher*/, int revents) { - if (ev::ERROR & revents) return; +void Connection::callback(ev::io& /*watcher*/, int revents) { + if (ev::ERROR & revents) { + return; + } ++rwCounter_; if (revents & ev::READ) { @@ -124,7 +130,9 @@ void Connection::write_cb() { ssize_t written = sock_.send(chunks); int err = sock_.last_error(); - if (written < 0 && err == EINTR) continue; + if (written < 0 && err == EINTR) { + continue; + } if (written < 0) { if (!socket::would_block(err)) { @@ -135,12 +143,18 @@ void Connection::write_cb() { } ssize_t toWrite = 0; - for (auto &chunk : chunks) toWrite += chunk.size(); + for (auto& chunk : chunks) { + toWrite += chunk.size(); + } wrBuf_.erase(written); - if (stats_) stats_->update_write_stats(written, wrBuf_.data_size()); + if (stats_) { + stats_->update_write_stats(written, wrBuf_.data_size()); + } - if (written < toWrite) return; + if (written < toWrite) { + return; + } } if (closeConn_) { closeConn(); @@ -155,7 +169,9 @@ typename Connection::ReadResT Connection::read_cb() { ssize_t nread = sock_.recv(it); int err = sock_.last_error(); - if (nread < 0 && err == EINTR) continue; + if (nread < 0 && err == EINTR) { + continue; + } if ((nread < 0 && !socket::would_block(err)) || nread == 0) { // Setting SO_LINGER with 0 timeout to avoid TIME_WAIT state on client @@ -173,12 +189,14 @@ typename Connection::ReadResT Connection::read_cb() { } } } - if (nread < ssize_t(it.size()) || !rdBuf_.available()) return ReadResT::Default; + if (nread < ssize_t(it.size()) || !rdBuf_.available()) { + return ReadResT::Default; + } } return ReadResT::Default; } template -void Connection::timeout_cb(ev::periodic & /*watcher*/, int /*time*/) { +void Connection::timeout_cb(ev::periodic& /*watcher*/, int /*time*/) { const bool isActive = lastCheckRWCounter_ != rwCounter_; lastCheckRWCounter_ = rwCounter_; if (isActive) { @@ -196,7 +214,7 @@ void Connection::timeout_cb(ev::periodic & /*watcher*/, int /*time*/) { closeConn(); } template -void Connection::async_cb(ev::async &) { +void Connection::async_cb(ev::async&) { callback(io_, ev::WRITE); } diff --git a/cpp_src/net/connection.h b/cpp_src/net/connection.h index e877d2d06..928395cad 100644 --- a/cpp_src/net/connection.h +++ b/cpp_src/net/connection.h @@ -35,7 +35,7 @@ using reindexer::cbuf; template class Connection { public: - Connection(socket &&s, ev::dynamic_loop &loop, bool enableStat, size_t readBufSize = kConnReadbufSize, + Connection(socket&& s, ev::dynamic_loop& loop, bool enableStat, size_t readBufSize = kConnReadbufSize, size_t writeBufSize = kConnWriteBufSize, int idleTimeout = -1); virtual ~Connection(); @@ -47,18 +47,16 @@ class Connection { virtual void onClose() = 0; // Generic callback - void callback(ev::io &watcher, int revents); + void callback(ev::io& watcher, int revents); void write_cb(); ReadResT read_cb(); - void async_cb(ev::async &watcher); - void timeout_cb(ev::periodic &watcher, int); + void async_cb(ev::async& watcher); + void timeout_cb(ev::periodic& watcher, int); void closeConn(); - void attach(ev::dynamic_loop &loop); + void attach(ev::dynamic_loop& loop); void detach(); - void restart(socket &&s); - - ssize_t async_read(); + void restart(socket&& s); socket sock_; ev::io io_; diff --git a/cpp_src/net/cproto/args.cc b/cpp_src/net/cproto/args.cc index efa7394bf..af5736e44 100644 --- a/cpp_src/net/cproto/args.cc +++ b/cpp_src/net/cproto/args.cc @@ -6,7 +6,7 @@ namespace reindexer { namespace net { namespace cproto { -void Args::Unpack(Serializer &ser) { +void Args::Unpack(Serializer& ser) { resize(0); unsigned count = ser.GetVarUint(); @@ -15,16 +15,16 @@ void Args::Unpack(Serializer &ser) { } } -void Args::Pack(WrSerializer &ser) const { +void Args::Pack(WrSerializer& ser) const { ser.PutVarUint(size()); - for (auto &arg : *this) { + for (auto& arg : *this) { ser.PutVariant(arg); } } -void Args::Dump(WrSerializer &wrser) const { +void Args::Dump(WrSerializer& wrser) const { wrser << '{'; - for (const auto &arg : *this) { + for (const auto& arg : *this) { if (&arg != &at(0)) { wrser << ", "; } diff --git a/cpp_src/net/cproto/args.h b/cpp_src/net/cproto/args.h index dfcbe3e8e..2035a9ada 100644 --- a/cpp_src/net/cproto/args.h +++ b/cpp_src/net/cproto/args.h @@ -11,9 +11,9 @@ using Arg = Variant; class Args : public h_vector { public: using h_vector::h_vector; - void Unpack(Serializer &ser); - void Pack(WrSerializer &ser) const; - void Dump(WrSerializer &wrser) const; + void Unpack(Serializer& ser); + void Pack(WrSerializer& ser) const; + void Dump(WrSerializer& wrser) const; }; } // namespace cproto } // namespace net diff --git a/cpp_src/net/cproto/clientconnection.cc b/cpp_src/net/cproto/clientconnection.cc index 241cb1caa..96977412c 100644 --- a/cpp_src/net/cproto/clientconnection.cc +++ b/cpp_src/net/cproto/clientconnection.cc @@ -18,7 +18,7 @@ bool ClientConnection::ConnectData::ThereAreReconnectOptions() const { return en bool ClientConnection::ConnectData::CurrDsnFailed(int failedDsnIdx) const { return failedDsnIdx == validEntryIdx; } int ClientConnection::ConnectData::GetNextDsnIndex() const { return (validEntryIdx.load(std::memory_order_acquire) + 1) % entries.size(); } -ClientConnection::ClientConnection(ev::dynamic_loop &loop, ConnectData *connectData, ConnectionFailCallback connectionFailCallback) +ClientConnection::ClientConnection(ev::dynamic_loop& loop, ConnectData* connectData, ConnectionFailCallback connectionFailCallback) : ConnectionMT(socket(), loop, false), state_(ConnInit), completions_(kMaxCompletions), @@ -38,7 +38,7 @@ ClientConnection::ClientConnection(ev::dynamic_loop &loop, ConnectData *connectD deadlineTimer_.set(this); deadlineTimer_.set(loop); reconnect_.set(loop); - reconnect_.set([this](ev::async &sig) { + reconnect_.set([this](ev::async& sig) { disconnect(); sig.loop.break_loop(); }); @@ -65,15 +65,17 @@ void ClientConnection::connectInternal() noexcept { mtx_.unlock(); assertrx(connectData_->validEntryIdx < int(connectData_->entries.size())); - ConnectData::Entry &connectEntry = connectData_->entries[actualDsnIdx_]; + ConnectData::Entry& connectEntry = connectData_->entries[actualDsnIdx_]; std::string port = connectEntry.uri.port().length() ? connectEntry.uri.port() : std::string("6534"); std::string dbName = connectEntry.uri.path(); std::string userName = connectEntry.uri.username(); std::string password = connectEntry.uri.password(); - if (dbName[0] == '/') dbName = dbName.substr(1); + if (dbName[0] == '/') { + dbName = dbName.substr(1); + } enableCompression_ = connectEntry.opts.enableCompression; - auto completion = [this](const RPCAnswer &ans, ClientConnection *) { + auto completion = [this](const RPCAnswer& ans, ClientConnection*) { std::unique_lock lck(mtx_); lastError_ = ans.Status(); state_ = ans.Status().ok() ? ConnConnected : ConnFailed; @@ -106,16 +108,18 @@ void ClientConnection::connectInternal() noexcept { } } -void ClientConnection::failInternal(const Error &error) { +void ClientConnection::failInternal(const Error& error) { std::unique_lock lck(mtx_); - if (lastError_.ok()) lastError_ = error; + if (lastError_.ok()) { + lastError_ = error; + } closeConn_ = true; } int ClientConnection::PendingCompletions() { int ret = 0; - for (auto &c : completions_) { - for (RPCCompletion *cc = &c; cc; cc = cc->next.get()) { + for (auto& c : completions_) { + for (RPCCompletion* cc = &c; cc; cc = cc->next.get()) { if (cc->used) { ret++; } @@ -148,10 +152,12 @@ Error ClientConnection::CheckConnection() { return lastError_; } -void ClientConnection::keep_alive_cb(ev::periodic &, int) { - if (terminate_.load(std::memory_order_acquire)) return; +void ClientConnection::keep_alive_cb(ev::periodic&, int) { + if (terminate_.load(std::memory_order_acquire)) { + return; + } call( - [this](RPCAnswer &&ans, ClientConnection *) { + [this](RPCAnswer&& ans, ClientConnection*) { if (!ans.Status().ok()) { failInternal(ans.Status()); closeConn(); @@ -161,11 +167,13 @@ void ClientConnection::keep_alive_cb(ev::periodic &, int) { callback(io_, ev::WRITE); } -void ClientConnection::deadline_check_cb(ev::timer &, int) { +void ClientConnection::deadline_check_cb(ev::timer&, int) { now_ += kDeadlineCheckInterval; - for (auto &c : completions_) { - for (RPCCompletion *cc = &c; cc; cc = cc->next.get()) { - if (!cc->used) continue; + for (auto& c : completions_) { + for (RPCCompletion* cc = &c; cc; cc = cc->next.get()) { + if (!cc->used) { + continue; + } bool expired = (cc->deadline.count() && cc->deadline.count() <= now_); if (expired || (cc->cancelCtx && cc->cancelCtx->IsCancelable() && (cc->cancelCtx->GetCancelType() == CancelType::Explicit))) { Error err(expired ? errTimeout : errCanceled, expired ? "Request deadline exceeded" : "Canceled"); @@ -216,11 +224,12 @@ void ClientConnection::onClose() { std::unique_lock lck(mtx_); wrBuf_.clear(); - if (lastError_.ok()) + if (lastError_.ok()) { lastError_ = Error(errNetwork, "Socket connection to %s closed", connectData_ && actualDsnIdx_ < int(connectData_->entries.size()) ? connectData_->entries[actualDsnIdx_].uri.hostname() : ""); + } closeConn_ = false; State prevState = state_; state_ = ConnClosing; @@ -230,16 +239,19 @@ void ClientConnection::onClose() { keep_alive_.stop(); deadlineTimer_.stop(); - for (auto &c : tmpCompletions) { - for (RPCCompletion *cc = &c; cc; cc = cc->next.get()) + for (auto& c : tmpCompletions) { + for (RPCCompletion* cc = &c; cc; cc = cc->next.get()) { if (cc->used && cc->cmd != kCmdLogin && cc->cmd != kCmdPing) { cc->cmpl(RPCAnswer(lastError_), this); } + } } std::unique_ptr tmpUpdatesHandler(updatesHandler_.release(std::memory_order_acq_rel)); - if (tmpUpdatesHandler) (*tmpUpdatesHandler)(RPCAnswer(lastError_), this); + if (tmpUpdatesHandler) { + (*tmpUpdatesHandler)(RPCAnswer(lastError_), this); + } lck.lock(); bufCond_.notify_all(); lck.unlock(); @@ -264,8 +276,10 @@ ClientConnection::ReadResT ClientConnection::onRead() { std::string uncompressed; while (!closeConn_) { - auto len = rdBuf_.peek(reinterpret_cast(&hdr), sizeof(hdr)); - if (len < sizeof(hdr)) return ReadResT::Default; + auto len = rdBuf_.peek(reinterpret_cast(&hdr), sizeof(hdr)); + if (len < sizeof(hdr)) { + return ReadResT::Default; + } if (hdr.magic != kCprotoMagic) { failInternal(Error(errNetwork, "Invalid cproto magic=%08x", hdr.magic)); @@ -283,7 +297,9 @@ ClientConnection::ReadResT ClientConnection::onRead() { rdBuf_.reserve(size_t(hdr.len) + sizeof(hdr) + 0x1000); } - if ((rdBuf_.size() - sizeof(hdr)) < size_t(hdr.len)) return ReadResT::Default; + if ((rdBuf_.size() - sizeof(hdr)) < size_t(hdr.len)) { + return ReadResT::Default; + } rdBuf_.erase(sizeof(hdr)); @@ -311,7 +327,7 @@ ClientConnection::ReadResT ClientConnection::onRead() { ans.status_ = Error(static_cast(errCode), std::string{errMsg}); } ans.data_ = span(ser.Buf() + ser.Pos(), ser.Len() - ser.Pos()); - } catch (const Error &err) { + } catch (const Error& err) { failInternal(err); return ReadResT::Default; } @@ -320,14 +336,14 @@ ClientConnection::ReadResT ClientConnection::onRead() { auto handler = updatesHandler_.release(std::memory_order_acq_rel); if (handler) { (*handler)(std::move(ans), this); - Completion *expected = nullptr; + Completion* expected = nullptr; if (!updatesHandler_.compare_exchange_strong(expected, handler, std::memory_order_acq_rel)) { delete handler; } } } else { auto complPtr = completions_.data(); - RPCCompletion *completion = &completions_[hdr.seq % completions_.size()]; + RPCCompletion* completion = &completions_[hdr.seq % completions_.size()]; for (; completion; completion = completion->next.get()) { if (!completion->used || completion->seq != hdr.seq) { @@ -380,7 +396,7 @@ Args RPCAnswer::GetArgs(int minArgs) const { Error RPCAnswer::Status() const { return status_; } -chunk ClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args &args, const Args &ctxArgs) { +chunk ClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args& args, const Args& ctxArgs) { CProtoHeader hdr; hdr.len = 0; hdr.magic = kCprotoMagic; @@ -392,7 +408,7 @@ chunk ClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args &args, con WrSerializer ser(wrBuf_.get_chunk()); - ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); + ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); args.Pack(ser); ctxArgs.Pack(ser); if (hdr.compressed) { @@ -403,12 +419,12 @@ chunk ClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args &args, con ser.Write(compressed); } assertrx(ser.Len() < size_t(std::numeric_limits::max())); - reinterpret_cast(ser.Buf())->len = ser.Len() - sizeof(hdr); + reinterpret_cast(ser.Buf())->len = ser.Len() - sizeof(hdr); return ser.DetachChunk(); } -ClientConnection::CallReturn ClientConnection::call(const Completion &cmpl, const CommandParams &opts, const Args &args) { +ClientConnection::CallReturn ClientConnection::call(const Completion& cmpl, const CommandParams& opts, const Args& args) { if (opts.cancelCtx) { switch (opts.cancelCtx->GetCancelType()) { case CancelType::Explicit: @@ -481,7 +497,7 @@ ClientConnection::CallReturn ClientConnection::call(const Completion &cmpl, cons CounterGuardIR32 cg(bufWait_); struct { uint32_t seq; - RPCCompletion *cmpl; + RPCCompletion* cmpl; } arg = {seq, completion}; bufCond_.wait(lck, [this, &arg]() { @@ -504,7 +520,9 @@ ClientConnection::CallReturn ClientConnection::call(const Completion &cmpl, cons completion = &completions_[seq % completions_.size()]; } while (completion->used) { - if (!completion->next) completion->next.reset(new RPCCompletion); + if (!completion->next) { + completion->next.reset(new RPCCompletion); + } completion = completion->next.get(); } } @@ -518,7 +536,7 @@ ClientConnection::CallReturn ClientConnection::call(const Completion &cmpl, cons try { wrBuf_.write(std::move(data)); - } catch (Error &e) { + } catch (Error& e) { fprintf(stderr, "RxClientConnection::wrBuf_.write exception: '%s'\n", e.what().c_str()); completion->used = false; lck.unlock(); diff --git a/cpp_src/net/cproto/clientconnection.h b/cpp_src/net/cproto/clientconnection.h index 05040b2d7..eeef53050 100644 --- a/cpp_src/net/cproto/clientconnection.h +++ b/cpp_src/net/cproto/clientconnection.h @@ -28,17 +28,21 @@ class RPCAnswer { public: Error Status() const; Args GetArgs(int minArgs = 0) const; - RPCAnswer(const Error &error) : status_(error) {} + RPCAnswer(const Error& error) : status_(error) {} ~RPCAnswer() { - if (hold_) delete[] data_.data(); + if (hold_) { + delete[] data_.data(); + } } - RPCAnswer(const RPCAnswer &other) = delete; - RPCAnswer(RPCAnswer &&other) : status_(std::move(other.status_)), data_(std::move(other.data_)), hold_(other.hold_) { + RPCAnswer(const RPCAnswer& other) = delete; + RPCAnswer(RPCAnswer&& other) : status_(std::move(other.status_)), data_(std::move(other.data_)), hold_(other.hold_) { other.hold_ = false; } - RPCAnswer &operator=(RPCAnswer &&other) { + RPCAnswer& operator=(RPCAnswer&& other) { if (this != &other) { - if (hold_) delete[] data_.data(); + if (hold_) { + delete[] data_.data(); + } status_ = std::move(other.status_); data_ = std::move(other.data_); hold_ = other.hold_; @@ -46,10 +50,10 @@ class RPCAnswer { } return *this; } - RPCAnswer &operator=(const RPCAnswer &other) = delete; + RPCAnswer& operator=(const RPCAnswer& other) = delete; void EnsureHold() { if (!hold_) { - uint8_t *data = new uint8_t[data_.size()]; + uint8_t* data = new uint8_t[data_.size()]; memcpy(data, data_.data(), data_.size()); data_ = {data, data_.size()}; hold_ = true; @@ -65,17 +69,17 @@ class RPCAnswer { }; struct CommandParams { - CommandParams(CmdCode c, seconds n, milliseconds e, const IRdxCancelContext *ctx) + CommandParams(CmdCode c, seconds n, milliseconds e, const IRdxCancelContext* ctx) : cmd(c), netTimeout(n), execTimeout(e), cancelCtx(ctx) {} CmdCode cmd; seconds netTimeout; milliseconds execTimeout; - const IRdxCancelContext *cancelCtx; + const IRdxCancelContext* cancelCtx; }; class ClientConnection : public ConnectionMT { public: - typedef std::function Completion; + typedef std::function Completion; typedef std::function ConnectionFailCallback; struct Options { Options() @@ -120,26 +124,26 @@ class ClientConnection : public ConnectionMT { int lastFailedEntryIdx = {-1}; }; - ClientConnection(ev::dynamic_loop &loop, ConnectData *connectData, + ClientConnection(ev::dynamic_loop& loop, ConnectData* connectData, ConnectionFailCallback connectionFailCallback = ConnectionFailCallback()); ~ClientConnection(); template - void Call(const Completion &cmpl, const CommandParams &opts, Argss... argss) { + void Call(const Completion& cmpl, const CommandParams& opts, Argss... argss) { Args args; args.reserve(sizeof...(argss)); call(cmpl, opts, args, argss...); } template - RPCAnswer Call(const CommandParams &opts, Argss... argss) { + RPCAnswer Call(const CommandParams& opts, Argss... argss) { Args args; args.reserve(sizeof...(argss)); RPCAnswer ret; std::atomic_bool set(false); auto callRet = call( - [&ret, &set](RPCAnswer &&ans, ClientConnection * /*conn*/) { + [&ret, &set](RPCAnswer&& ans, ClientConnection* /*conn*/) { ret = std::move(ans); ret.EnsureHold(); set = true; @@ -184,12 +188,12 @@ class ClientConnection : public ConnectionMT { protected: enum State { ConnInit, ConnConnecting, ConnConnected, ConnFailed, ConnClosing }; - void connect_async_cb(ev::async &) { connectInternal(); } - void keep_alive_cb(ev::periodic &, int); - void deadline_check_cb(ev::timer &, int); + void connect_async_cb(ev::async&) { connectInternal(); } + void keep_alive_cb(ev::periodic&, int); + void deadline_check_cb(ev::timer&, int); void connectInternal() noexcept; - void failInternal(const Error &error); + void failInternal(const Error& error); void disconnect(); struct RPCCompletion { @@ -200,32 +204,32 @@ class ClientConnection : public ConnectionMT { atomic_unique_ptr next; std::atomic used; seconds deadline; - const reindexer::IRdxCancelContext *cancelCtx; + const reindexer::IRdxCancelContext* cancelCtx; }; struct CallReturn { - explicit CallReturn(RPCCompletion *c = nullptr, uint32_t s = 0) noexcept : cmpl(c), seq(s) {} + explicit CallReturn(RPCCompletion* c = nullptr, uint32_t s = 0) noexcept : cmpl(c), seq(s) {} - RPCCompletion *cmpl; + RPCCompletion* cmpl; uint32_t seq; }; template - inline CallReturn call(const Completion &cmpl, const CommandParams &opts, Args &args, const std::string_view &val, Argss... argss) { + inline CallReturn call(const Completion& cmpl, const CommandParams& opts, Args& args, const std::string_view& val, Argss... argss) { args.emplace_back(p_string(&val)); return call(cmpl, opts, args, argss...); } template - inline CallReturn call(const Completion &cmpl, const CommandParams &opts, Args &args, const std::string &val, Argss... argss) { + inline CallReturn call(const Completion& cmpl, const CommandParams& opts, Args& args, const std::string& val, Argss... argss) { args.emplace_back(p_string(&val)); return call(cmpl, opts, args, argss...); } template - inline CallReturn call(const Completion &cmpl, const CommandParams &opts, Args &args, const T &val, Argss... argss) { + inline CallReturn call(const Completion& cmpl, const CommandParams& opts, Args& args, const T& val, Argss... argss) { args.emplace_back(val); return call(cmpl, opts, args, argss...); } - CallReturn call(const Completion &cmpl, const CommandParams &opts, const Args &args); - chunk packRPC(CmdCode cmd, uint32_t seq, const Args &args, const Args &ctxArgs); + CallReturn call(const Completion& cmpl, const CommandParams& opts, const Args& args); + chunk packRPC(CmdCode cmd, uint32_t seq, const Args& args, const Args& ctxArgs); ReadResT onRead() override; void onClose() override; @@ -246,7 +250,7 @@ class ClientConnection : public ConnectionMT { std::atomic now_; std::atomic terminate_; ConnectionFailCallback onConnectionFailed_; - ConnectData *connectData_; + ConnectData* connectData_; int currDsnIdx_, actualDsnIdx_; ev::async reconnect_; std::atomic enableSnappy_; diff --git a/cpp_src/net/cproto/coroclientconnection.cc b/cpp_src/net/cproto/coroclientconnection.cc index 51f17a789..38c2bf3da 100644 --- a/cpp_src/net/cproto/coroclientconnection.cc +++ b/cpp_src/net/cproto/coroclientconnection.cc @@ -41,7 +41,7 @@ CoroClientConnection::CoroClientConnection() CoroClientConnection::~CoroClientConnection() { Stop(); } -void CoroClientConnection::Start(ev::dynamic_loop &loop, ConnectData &&connectData) { +void CoroClientConnection::Start(ev::dynamic_loop& loop, ConnectData&& connectData) { if (!isRunning_) { // Don't allow to call Start, while error handling is in progress errSyncCh_.pop(); @@ -110,14 +110,14 @@ void CoroClientConnection::Stop() { } } -Error CoroClientConnection::Status(std::chrono::seconds netTimeout, std::chrono::milliseconds execTimeout, const IRdxCancelContext *ctx) { +Error CoroClientConnection::Status(std::chrono::seconds netTimeout, std::chrono::milliseconds execTimeout, const IRdxCancelContext* ctx) { if (loggedIn_) { return errOK; } return call({kCmdPing, netTimeout, execTimeout, ctx}, {}).Status(); } -CoroRPCAnswer CoroClientConnection::call(const CommandParams &opts, const Args &args) { +CoroRPCAnswer CoroClientConnection::call(const CommandParams& opts, const Args& args) { if (opts.cancelCtx) { switch (opts.cancelCtx->GetCancelType()) { case CancelType::Explicit: @@ -142,7 +142,7 @@ CoroRPCAnswer CoroClientConnection::call(const CommandParams &opts, const Args & errSyncCh_.pop(); uint32_t seq = seqp.first; - auto &call = rpcCalls_[seq % rpcCalls_.size()]; + auto& call = rpcCalls_[seq % rpcCalls_.size()]; call.seq = seq; call.used = true; call.deadline = deadline; @@ -165,7 +165,7 @@ CoroRPCAnswer CoroClientConnection::call(const CommandParams &opts, const Args & return ans; } -Error CoroClientConnection::callNoReply(const CommandParams &opts, uint32_t seq, const Args &args) { +Error CoroClientConnection::callNoReply(const CommandParams& opts, uint32_t seq, const Args& args) { if (opts.cancelCtx) { switch (opts.cancelCtx->GetCancelType()) { case CancelType::Explicit: @@ -191,7 +191,7 @@ Error CoroClientConnection::callNoReply(const CommandParams &opts, uint32_t seq, return errOK; } -CoroClientConnection::MarkedChunk CoroClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args &args, const Args &ctxArgs) { +CoroClientConnection::MarkedChunk CoroClientConnection::packRPC(CmdCode cmd, uint32_t seq, const Args& args, const Args& ctxArgs) { CProtoHeader hdr; hdr.len = 0; hdr.magic = kCprotoMagic; @@ -204,7 +204,7 @@ CoroClientConnection::MarkedChunk CoroClientConnection::packRPC(CmdCode cmd, uin chunk ch = getChunk(); WrSerializer ser(std::move(ch)); - ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); + ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); args.Pack(ser); ctxArgs.Pack(ser); if (hdr.compressed) { @@ -215,19 +215,19 @@ CoroClientConnection::MarkedChunk CoroClientConnection::packRPC(CmdCode cmd, uin ser.Write(compressed); } assertrx(ser.Len() < size_t(std::numeric_limits::max())); - reinterpret_cast(ser.Buf())->len = ser.Len() - sizeof(hdr); + reinterpret_cast(ser.Buf())->len = ser.Len() - sizeof(hdr); return {seq, ser.DetachChunk()}; } -void CoroClientConnection::appendChunck(std::vector &buf, chunk &&ch) { +void CoroClientConnection::appendChunck(std::vector& buf, chunk&& ch) { auto oldBufSize = buf.size(); buf.resize(buf.size() + ch.size()); memcpy(buf.data() + oldBufSize, ch.data(), ch.size()); recycleChunk(std::move(ch)); } -Error CoroClientConnection::login(std::vector &buf) { +Error CoroClientConnection::login(std::vector& buf) { assertrx(conn_.state() != manual_connection::conn_state::connecting); if (conn_.state() == manual_connection::conn_state::init) { readWg_.wait(); @@ -256,7 +256,9 @@ Error CoroClientConnection::login(std::vector &buf) { std::string userName = connectData_.uri.username(); std::string password = connectData_.uri.password(); - if (dbName[0] == '/') dbName = dbName.substr(1); + if (dbName[0] == '/') { + dbName = dbName.substr(1); + } enableCompression_ = connectData_.opts.enableCompression; requestDedicatedThread_ = connectData_.opts.requestDedicatedThread; Args args = {Arg{p_string(&userName)}, @@ -292,19 +294,19 @@ Error CoroClientConnection::login(std::vector &buf) { return errOK; } -void CoroClientConnection::closeConn(const Error &err) noexcept { +void CoroClientConnection::closeConn(const Error& err) noexcept { errSyncCh_.reopen(); lastError_ = err; conn_.close_conn(k_sock_closed_err); handleFatalError(err); } -void CoroClientConnection::handleFatalError(const Error &err) noexcept { +void CoroClientConnection::handleFatalError(const Error& err) noexcept { if (!errSyncCh_.opened()) { errSyncCh_.reopen(); } loggedIn_ = false; - for (auto &c : rpcCalls_) { + for (auto& c : rpcCalls_) { if (c.used && c.rspCh.opened() && !c.rspCh.full()) { c.rspCh.push(err); } @@ -325,7 +327,7 @@ chunk CoroClientConnection::getChunk() noexcept { return ch; } -void CoroClientConnection::recycleChunk(chunk &&ch) noexcept { +void CoroClientConnection::recycleChunk(chunk&& ch) noexcept { if (ch.capacity() <= kMaxChunckSizeToRecycle && recycledChuncks_.size() < kMaxRecycledChuncks) { recycledChuncks_.emplace_back(std::move(ch)); } @@ -430,7 +432,7 @@ void CoroClientConnection::readerRoutine() { ans.status_ = Error(static_cast(errCode), std::string{errMsg}); } ans.data_ = span(ser.Buf() + ser.Pos(), ser.Len() - ser.Pos()); - } catch (const Error &err) { + } catch (const Error& err) { // disconnect closeConn(err); break; @@ -449,7 +451,7 @@ void CoroClientConnection::readerRoutine() { closeConn(ans.Status()); } } else { - auto &rpcData = rpcCalls_[hdr.seq % rpcCalls_.size()]; + auto& rpcData = rpcCalls_[hdr.seq % rpcCalls_.size()]; if (!rpcData.used || rpcData.seq != hdr.seq) { auto cmdSv = CmdName(hdr.cmd); fprintf(stderr, "Unexpected RPC answer seq=%d cmd=%d(%.*s)\n", int(hdr.seq), hdr.cmd, int(cmdSv.size()), cmdSv.data()); @@ -466,7 +468,7 @@ void CoroClientConnection::readerRoutine() { } while (loggedIn_ && !terminate_); } -void CoroClientConnection::sendCloseResults(CProtoHeader const &hdr, CoroRPCAnswer const &ans) { +void CoroClientConnection::sendCloseResults(const CProtoHeader& hdr, const CoroRPCAnswer& ans) { if (!ans.Status().ok()) { return; } @@ -511,8 +513,10 @@ void CoroClientConnection::deadlineRoutine() { loop_->granular_sleep(kDeadlineCheckInterval, kCoroSleepGranularity, [this] { return terminate_; }); now_ += std::chrono::duration_cast(kDeadlineCheckInterval).count(); - for (auto &c : rpcCalls_) { - if (!c.used) continue; + for (auto& c : rpcCalls_) { + if (!c.used) { + continue; + } bool expired = (c.deadline.count() && c.deadline.count() <= now_); bool canceled = (c.cancelCtx && c.cancelCtx->IsCancelable() && (c.cancelCtx->GetCancelType() == CancelType::Explicit)); if (expired || canceled) { diff --git a/cpp_src/net/cproto/coroclientconnection.h b/cpp_src/net/cproto/coroclientconnection.h index 832fd2ea9..2236cd3b4 100644 --- a/cpp_src/net/cproto/coroclientconnection.h +++ b/cpp_src/net/cproto/coroclientconnection.h @@ -36,14 +36,14 @@ class CoroRPCAnswer { return ret; } CoroRPCAnswer() = default; - CoroRPCAnswer(const Error &error) : status_(error) {} - CoroRPCAnswer(const CoroRPCAnswer &other) = delete; - CoroRPCAnswer(CoroRPCAnswer &&other) = default; - CoroRPCAnswer &operator=(CoroRPCAnswer &&other) = default; - CoroRPCAnswer &operator=(const CoroRPCAnswer &other) = delete; - - void EnsureHold(chunk &&ch) { - ch.append(std::string_view(reinterpret_cast(data_.data()), data_.size())); + CoroRPCAnswer(const Error& error) : status_(error) {} + CoroRPCAnswer(const CoroRPCAnswer& other) = delete; + CoroRPCAnswer(CoroRPCAnswer&& other) = default; + CoroRPCAnswer& operator=(CoroRPCAnswer&& other) = default; + CoroRPCAnswer& operator=(const CoroRPCAnswer& other) = delete; + + void EnsureHold(chunk&& ch) { + ch.append(std::string_view(reinterpret_cast(data_.data()), data_.size())); storage_ = std::move(ch); data_ = {storage_.data(), storage_.size()}; } @@ -56,18 +56,18 @@ class CoroRPCAnswer { }; struct CommandParams { - CommandParams(CmdCode c, seconds n, milliseconds e, const IRdxCancelContext *ctx) + CommandParams(CmdCode c, seconds n, milliseconds e, const IRdxCancelContext* ctx) : cmd(c), netTimeout(n), execTimeout(e), cancelCtx(ctx) {} CmdCode cmd; seconds netTimeout; milliseconds execTimeout; - const IRdxCancelContext *cancelCtx; + const IRdxCancelContext* cancelCtx; }; class CoroClientConnection { public: - using UpdatesHandlerT = std::function; - using FatalErrorHandlerT = std::function; + using UpdatesHandlerT = std::function; + using FatalErrorHandlerT = std::function; struct Options { Options() @@ -109,16 +109,16 @@ class CoroClientConnection { CoroClientConnection(); ~CoroClientConnection(); - void Start(ev::dynamic_loop &loop, ConnectData &&connectData); + void Start(ev::dynamic_loop& loop, ConnectData&& connectData); void Stop(); bool IsRunning() const noexcept { return isRunning_; } - Error Status(seconds netTimeout, milliseconds execTimeout, const IRdxCancelContext *ctx); + Error Status(seconds netTimeout, milliseconds execTimeout, const IRdxCancelContext* ctx); seconds Now() const noexcept { return seconds(now_); } void SetUpdatesHandler(UpdatesHandlerT handler) noexcept { updatesHandler_ = std::move(handler); } void SetFatalErrorHandler(FatalErrorHandlerT handler) noexcept { fatalErrorHandler_ = std::move(handler); } template - CoroRPCAnswer Call(const CommandParams &opts, const Argss &...argss) { + CoroRPCAnswer Call(const CommandParams& opts, const Argss&... argss) { Args args; args.reserve(sizeof...(argss)); return call(opts, args, argss...); @@ -130,7 +130,7 @@ class CoroClientConnection { uint32_t seq; bool used; seconds deadline; - const reindexer::IRdxCancelContext *cancelCtx; + const reindexer::IRdxCancelContext* cancelCtx; coroutine::channel rspCh; }; @@ -140,32 +140,32 @@ class CoroClientConnection { }; template - inline CoroRPCAnswer call(const CommandParams &opts, Args &args, const std::string_view &val, const Argss &...argss) { + inline CoroRPCAnswer call(const CommandParams& opts, Args& args, const std::string_view& val, const Argss&... argss) { args.push_back(Variant(p_string(&val))); return call(opts, args, argss...); } template - inline CoroRPCAnswer call(const CommandParams &opts, Args &args, const std::string &val, const Argss &...argss) { + inline CoroRPCAnswer call(const CommandParams& opts, Args& args, const std::string& val, const Argss&... argss) { args.push_back(Variant(p_string(&val))); return call(opts, args, argss...); } template - inline CoroRPCAnswer call(const CommandParams &opts, Args &args, const T &val, const Argss &...argss) { + inline CoroRPCAnswer call(const CommandParams& opts, Args& args, const T& val, const Argss&... argss) { args.push_back(Variant(val)); return call(opts, args, argss...); } - CoroRPCAnswer call(const CommandParams &opts, const Args &args); - Error callNoReply(const CommandParams &opts, uint32_t seq, const Args &args); + CoroRPCAnswer call(const CommandParams& opts, const Args& args); + Error callNoReply(const CommandParams& opts, uint32_t seq, const Args& args); - MarkedChunk packRPC(CmdCode cmd, uint32_t seq, const Args &args, const Args &ctxArgs); - void appendChunck(std::vector &buf, chunk &&ch); - Error login(std::vector &buf); - void closeConn(const Error &err) noexcept; - void handleFatalError(const Error &err) noexcept; + MarkedChunk packRPC(CmdCode cmd, uint32_t seq, const Args& args, const Args& ctxArgs); + void appendChunck(std::vector& buf, chunk&& ch); + Error login(std::vector& buf); + void closeConn(const Error& err) noexcept; + void handleFatalError(const Error& err) noexcept; chunk getChunk() noexcept; - void recycleChunk(chunk &&) noexcept; - void sendCloseResults(CProtoHeader const &, CoroRPCAnswer const &); + void recycleChunk(chunk&&) noexcept; + void sendCloseResults(const CProtoHeader&, const CoroRPCAnswer&); void writerRoutine(); void readerRoutine(); @@ -176,7 +176,7 @@ class CoroClientConnection { uint32_t now_; bool terminate_ = false; bool isRunning_ = false; - ev::dynamic_loop *loop_ = nullptr; + ev::dynamic_loop* loop_ = nullptr; // seq -> rpc data std::vector rpcCalls_; diff --git a/cpp_src/net/cproto/dispatcher.h b/cpp_src/net/cproto/dispatcher.h index 97b7674c8..bf9c69cf9 100644 --- a/cpp_src/net/cproto/dispatcher.h +++ b/cpp_src/net/cproto/dispatcher.h @@ -33,28 +33,28 @@ struct ClientData { struct Context; struct IRPCCall { - void (*Get)(IRPCCall *, CmdCode &, std::string_view &nsName, Args &); + void (*Get)(IRPCCall*, CmdCode&, std::string_view& nsName, Args&); intrusive_ptr> data_; }; class Writer { public: virtual ~Writer() = default; - virtual void WriteRPCReturn(Context &ctx, const Args &args, const Error &status) = 0; - virtual void CallRPC(const IRPCCall &call) = 0; - virtual void SetClientData(std::unique_ptr &&data) noexcept = 0; - virtual ClientData *GetClientData() noexcept = 0; + virtual void WriteRPCReturn(Context& ctx, const Args& args, const Error& status) = 0; + virtual void CallRPC(const IRPCCall& call) = 0; + virtual void SetClientData(std::unique_ptr&& data) noexcept = 0; + virtual ClientData* GetClientData() noexcept = 0; virtual std::shared_ptr GetConnectionStat() noexcept = 0; }; struct Context { - void Return(const Args &args, const Error &status = errOK) { writer->WriteRPCReturn(*this, args, status); } - void SetClientData(std::unique_ptr &&data) noexcept { writer->SetClientData(std::move(data)); } - ClientData *GetClientData() noexcept { return writer->GetClientData(); } + void Return(const Args& args, const Error& status = errOK) { writer->WriteRPCReturn(*this, args, status); } + void SetClientData(std::unique_ptr&& data) noexcept { writer->SetClientData(std::move(data)); } + ClientData* GetClientData() noexcept { return writer->GetClientData(); } std::string_view clientAddr; - RPCCall *call; - Writer *writer; + RPCCall* call; + Writer* writer; Stat stat; bool respSent; }; @@ -67,7 +67,7 @@ class Dispatcher { /// @param object - handler class object /// @param func - handler template - void Register(CmdCode cmd, K *object, Error (K::*func)(Context &, Args... args)) { + void Register(CmdCode cmd, K* object, Error (K::*func)(Context&, Args... args)) { handlers_[cmd] = FuncWrapper{object, func}; } @@ -75,7 +75,7 @@ class Dispatcher { /// @param object - handler class object /// @param func - handler template - void Middleware(K *object, Error (K::*func)(Context &)) { + void Middleware(K* object, Error (K::*func)(Context&)) { middlewares_.push_back(FuncWrapper{object, func}); } @@ -83,41 +83,41 @@ class Dispatcher { /// @param object - logger class object /// @param func - logger template - void Logger(K *object, void (K::*func)(Context &ctx, const Error &err, const Args &ret)) { - logger_ = [=](Context &ctx, const Error &err, const Args &ret) { (static_cast(object)->*func)(ctx, err, ret); }; + void Logger(K* object, void (K::*func)(Context& ctx, const Error& err, const Args& ret)) { + logger_ = [=](Context& ctx, const Error& err, const Args& ret) { (static_cast(object)->*func)(ctx, err, ret); }; } /// Set closer notifier /// @param object close class object /// @param func function, to be called on connecion close template - void OnClose(K *object, void (K::*func)(Context &ctx, const Error &err)) { - onClose_ = [=](Context &ctx, const Error &err) { (static_cast(object)->*func)(ctx, err); }; + void OnClose(K* object, void (K::*func)(Context& ctx, const Error& err)) { + onClose_ = [=](Context& ctx, const Error& err) { (static_cast(object)->*func)(ctx, err); }; } /// Set response sent notifier /// @param object class object /// @param func function, to be called on response sent template - void OnResponse(K *object, void (K::*func)(Context &ctx)) { - onResponse_ = [=](Context &ctx) { (static_cast(object)->*func)(ctx); }; + void OnResponse(K* object, void (K::*func)(Context& ctx)) { + onResponse_ = [=](Context& ctx) { (static_cast(object)->*func)(ctx); }; } /// Get reference to the current logger functor /// @return Log handler reference - const std::function &LoggerRef() const noexcept { return logger_; } + const std::function& LoggerRef() const noexcept { return logger_; } /// Get reference to the current OnClose() functor /// @return OnClose callback reference - const std::function &OnCloseRef() const noexcept { return onClose_; } + const std::function& OnCloseRef() const noexcept { return onClose_; } /// Get reference to the current OnResponse() functor /// @return OnResponse callback reference - const std::function &OnResponseRef() const noexcept { return onResponse_; } + const std::function& OnResponseRef() const noexcept { return onResponse_; } /// Handle RPC fron the context /// @param ctx - RPC context - Error Handle(Context &ctx) { + Error Handle(Context& ctx) { if rx_likely (uint32_t(ctx.call->cmd) < uint32_t(handlers_.size())) { - for (auto &middleware : middlewares_) { + for (auto& middleware : middlewares_) { auto ret = middleware(ctx); if (!ret.ok()) { return ret; @@ -139,41 +139,41 @@ class Dispatcher { struct is_optional> : public std::true_type {}; template ::value, int> = 0> - static T get_arg(const Args &args, size_t index, const Context &ctx) { + static T get_arg(const Args& args, size_t index, const Context& ctx) { if (index >= args.size()) { throw Error(errParams, "Invalid args of %s call; argument %d is not submited", CmdName(ctx.call->cmd), static_cast(index)); } return T(args[index]); } template ::value, int> = 0> - static T get_arg(const Args &args, size_t index, const Context &) { + static T get_arg(const Args& args, size_t index, const Context&) { return index < args.size() ? T(typename T::value_type(args[index])) : T(); } template class FuncWrapper { public: - FuncWrapper(K *o, Error (K::*f)(Context &, Args...)) noexcept : obj_{o}, func_{f} {} - Error operator()(Context &ctx) const { return impl(ctx, std::index_sequence_for{}); } + FuncWrapper(K* o, Error (K::*f)(Context&, Args...)) noexcept : obj_{o}, func_{f} {} + Error operator()(Context& ctx) const { return impl(ctx, std::index_sequence_for{}); } private: template - Error impl(Context &ctx, std::index_sequence) const { + Error impl(Context& ctx, std::index_sequence) const { return (obj_->*func_)(ctx, get_arg(ctx.call->args, I, ctx)...); } - K *obj_; - Error (K::*func_)(Context &, Args...); + K* obj_; + Error (K::*func_)(Context&, Args...); }; - using Handler = std::function; + using Handler = std::function; std::array handlers_; std::vector middlewares_; - std::function logger_; - std::function onClose_; + std::function logger_; + std::function onClose_; // This should be called from the connection thread only to prevet access to other connection's ClientData - std::function onResponse_; + std::function onResponse_; }; } // namespace cproto } // namespace net diff --git a/cpp_src/net/cproto/serverconnection.cc b/cpp_src/net/cproto/serverconnection.cc index de8ce207e..5b71ef973 100644 --- a/cpp_src/net/cproto/serverconnection.cc +++ b/cpp_src/net/cproto/serverconnection.cc @@ -12,7 +12,7 @@ const auto kCProtoTimeoutSec = 300; const auto kUpdatesResendTimeout = 0.1; const auto kMaxUpdatesBufSize = 1024 * 1024 * 8; -ServerConnection::ServerConnection(socket &&s, ev::dynamic_loop &loop, Dispatcher &dispatcher, bool enableStat, size_t maxUpdatesSize, +ServerConnection::ServerConnection(socket&& s, ev::dynamic_loop& loop, Dispatcher& dispatcher, bool enableStat, size_t maxUpdatesSize, bool enableCustomBalancing) : ConnectionST(std::move(s), loop, enableStat, kConnReadbufSize, kConnWriteBufSize, kCProtoTimeoutSec), dispatcher_(dispatcher), @@ -33,14 +33,14 @@ ServerConnection::ServerConnection(socket &&s, ev::dynamic_loop &loop, Dispatche ServerConnection::~ServerConnection() { BaseConnT::closeConn(); } -bool ServerConnection::Restart(socket &&s) { +bool ServerConnection::Restart(socket&& s) { BaseConnT::restart(std::move(s)); updates_async_.start(); BaseConnT::callback(BaseConnT::io_, ev::READ); return true; } -void ServerConnection::Attach(ev::dynamic_loop &loop) { +void ServerConnection::Attach(ev::dynamic_loop& loop) { BaseConnT::async_.set(this); if (!BaseConnT::attached_) { BaseConnT::attach(loop); @@ -77,7 +77,7 @@ void ServerConnection::onClose() { } } -void ServerConnection::handleRPC(Context &ctx) { +void ServerConnection::handleRPC(Context& ctx) { Error err = dispatcher_.Handle(ctx); if (!ctx.respSent) { @@ -92,7 +92,7 @@ ServerConnection::BaseConnT::ReadResT ServerConnection::onRead() { Context ctx{BaseConnT::clientAddr_, nullptr, this, {{}, {}}, false}; std::string uncompressed; - auto len = BaseConnT::rdBuf_.peek(reinterpret_cast(&hdr), sizeof(hdr)); + auto len = BaseConnT::rdBuf_.peek(reinterpret_cast(&hdr), sizeof(hdr)); if (len < sizeof(hdr)) { return BaseConnT::ReadResT::Default; } @@ -100,7 +100,7 @@ ServerConnection::BaseConnT::ReadResT ServerConnection::onRead() { if (hdr.magic != kCprotoMagic) { try { responceRPC(ctx, Error(errParams, "Invalid cproto magic %08x", int(hdr.magic)), Args()); - } catch (const Error &err) { + } catch (const Error& err) { fprintf(stderr, "responceRPC unexpected error: %s\n", err.what().c_str()); } BaseConnT::closeConn_ = true; @@ -113,7 +113,7 @@ ServerConnection::BaseConnT::ReadResT ServerConnection::onRead() { ctx, Error(errParams, "Unsupported cproto version %04x. This server expects reindexer client v1.9.8+", int(hdr.version)), Args()); - } catch (const Error &err) { + } catch (const Error& err) { fprintf(stderr, "responceRPC unexpected error: %s\n", err.what().c_str()); } BaseConnT::closeConn_ = true; @@ -182,9 +182,9 @@ ServerConnection::BaseConnT::ReadResT ServerConnection::onRead() { } handleRPC(ctx); - } catch (const Error &err) { + } catch (const Error& err) { handleException(ctx, err); - } catch (const std::exception &err) { + } catch (const std::exception& err) { handleException(ctx, Error(errLogic, err.what())); } catch (...) { handleException(ctx, Error(errLogic, "Unknown exception")); @@ -195,7 +195,7 @@ ServerConnection::BaseConnT::ReadResT ServerConnection::onRead() { return BaseConnT::ReadResT::Default; } -static void packRPC(WrSerializer &ser, Context &ctx, const Error &status, const Args &args, bool enableSnappy) { +static void packRPC(WrSerializer& ser, Context& ctx, const Error& status, const Args& args, bool enableSnappy) { CProtoHeader hdr; hdr.len = 0; hdr.magic = kCprotoMagic; @@ -211,7 +211,7 @@ static void packRPC(WrSerializer &ser, Context &ctx, const Error &status, const } size_t savePos = ser.Len(); - ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); + ser.Write(std::string_view(reinterpret_cast(&hdr), sizeof(hdr))); ser.PutVarUint(status.code()); ser.PutVString(status.what()); @@ -227,22 +227,22 @@ static void packRPC(WrSerializer &ser, Context &ctx, const Error &status, const if (ser.Len() - savePos >= size_t(std::numeric_limits::max())) { throw Error(errNetwork, "Too large RPC message(%d), size: %d bytes", hdr.cmd, ser.Len()); } - reinterpret_cast(ser.Buf() + savePos)->len = ser.Len() - savePos - sizeof(hdr); + reinterpret_cast(ser.Buf() + savePos)->len = ser.Len() - savePos - sizeof(hdr); } -static chunk packRPC(chunk chunk, Context &ctx, const Error &status, const Args &args, bool enableSnappy) { +static chunk packRPC(chunk chunk, Context& ctx, const Error& status, const Args& args, bool enableSnappy) { WrSerializer ser(std::move(chunk)); packRPC(ser, ctx, status, args, enableSnappy); return ser.DetachChunk(); } -void ServerConnection::responceRPC(Context &ctx, const Error &status, const Args &args) { +void ServerConnection::responceRPC(Context& ctx, const Error& status, const Args& args) { if rx_unlikely (ctx.respSent) { fprintf(stderr, "Warning - RPC responce already sent\n"); return; } - auto &&chunk = packRPC(BaseConnT::wrBuf_.get_chunk(), ctx, status, args, enableSnappy_); + auto&& chunk = packRPC(BaseConnT::wrBuf_.get_chunk(), ctx, status, args, enableSnappy_); auto len = chunk.len(); BaseConnT::wrBuf_.write(std::move(chunk)); if (BaseConnT::stats_) { @@ -264,7 +264,7 @@ void ServerConnection::responceRPC(Context &ctx, const Error &status, const Args } } -void ServerConnection::CallRPC(const IRPCCall &call) { +void ServerConnection::CallRPC(const IRPCCall& call) { std::lock_guard lck(updates_mtx_); updates_.emplace_back(call); updatesSize_ += call.data_->capacity(); @@ -279,7 +279,7 @@ void ServerConnection::CallRPC(const IRPCCall &call) { WrSerializer ser; ser.PutVString(nsName); - IRPCCall callLost = {[](IRPCCall *callLost, CmdCode &cmd, std::string_view &ns, Args &args) { + IRPCCall callLost = {[](IRPCCall* callLost, CmdCode& cmd, std::string_view& ns, Args& args) { Serializer s(callLost->data_->data(), callLost->data_->size()); cmd = kCmdUpdates; args = {Arg(std::string(s.GetVString()))}; @@ -381,7 +381,9 @@ void ServerConnection::sendUpdates() { updatesSize_ += updatesSizeCopy - updatesSizeBuffered; } - if (BaseConnT::stats_) stats_->update_pended_updates(updates.size()); + if (BaseConnT::stats_) { + stats_->update_pended_updates(updates.size()); + } } else if (BaseConnT::stats_) { if (auto stat = BaseConnT::stats_->get_stat(); stat) { std::lock_guard lck(updates_mtx_); @@ -401,16 +403,16 @@ void ServerConnection::sendUpdates() { BaseConnT::callback(BaseConnT::io_, ev::WRITE); } -void ServerConnection::handleException(Context &ctx, const Error &err) noexcept { +void ServerConnection::handleException(Context& ctx, const Error& err) noexcept { // Exception occurs on unrecoverable error. Send responce, and drop connection fprintf(stderr, "Dropping RPC-connection. Reason: %s\n", err.what().c_str()); try { if (!ctx.respSent) { responceRPC(ctx, err, Args()); } - } catch (const Error &e) { + } catch (const Error& e) { fprintf(stderr, "responceRPC unexpected error: %s\n", e.what().c_str()); - } catch (const std::exception &e) { + } catch (const std::exception& e) { fprintf(stderr, "responceRPC unexpected error (std::exception): %s\n", e.what()); } catch (...) { fprintf(stderr, "responceRPC unexpected error (unknow exception)\n"); diff --git a/cpp_src/net/cproto/serverconnection.h b/cpp_src/net/cproto/serverconnection.h index c035af899..133fcf2f1 100644 --- a/cpp_src/net/cproto/serverconnection.h +++ b/cpp_src/net/cproto/serverconnection.h @@ -16,20 +16,20 @@ class ServerConnection final : public ConnectionST, public IServerConnection, pu public: using BaseConnT = ConnectionST; - ServerConnection(socket &&s, ev::dynamic_loop &loop, Dispatcher &dispatcher, bool enableStat, size_t maxUpdatesSize, + ServerConnection(socket&& s, ev::dynamic_loop& loop, Dispatcher& dispatcher, bool enableStat, size_t maxUpdatesSize, bool enableCustomBalancing); ~ServerConnection() override; // IServerConnection interface implementation - static ConnectionFactory NewFactory(Dispatcher &dispatcher, bool enableStat, size_t maxUpdatesSize) { - return [&dispatcher, enableStat, maxUpdatesSize](ev::dynamic_loop &loop, socket &&s, bool allowCustomBalancing) { + static ConnectionFactory NewFactory(Dispatcher& dispatcher, bool enableStat, size_t maxUpdatesSize) { + return [&dispatcher, enableStat, maxUpdatesSize](ev::dynamic_loop& loop, socket&& s, bool allowCustomBalancing) { return new ServerConnection(std::move(s), loop, dispatcher, enableStat, maxUpdatesSize, allowCustomBalancing); }; } bool IsFinished() const noexcept override final { return !BaseConnT::sock_.valid(); } BalancingType GetBalancingType() const noexcept override final { return balancingType_; } - void SetRebalanceCallback(std::function cb) override final { + void SetRebalanceCallback(std::function cb) override final { assertrx(!rebalance_); rebalance_ = std::move(cb); } @@ -41,15 +41,15 @@ class ServerConnection final : public ConnectionST, public IServerConnection, pu } BaseConnT::callback(BaseConnT::io_, ev::READ); } - bool Restart(socket &&s) override final; + bool Restart(socket&& s) override final; void Detach() override final; - void Attach(ev::dynamic_loop &loop) override final; + void Attach(ev::dynamic_loop& loop) override final; // Writer iterface implementation - void WriteRPCReturn(Context &ctx, const Args &args, const Error &status) override final { responceRPC(ctx, status, args); } - void CallRPC(const IRPCCall &call) override final; - void SetClientData(std::unique_ptr &&data) noexcept override final { clientData_ = std::move(data); } - ClientData *GetClientData() noexcept override final { return clientData_.get(); } + void WriteRPCReturn(Context& ctx, const Args& args, const Error& status) override final { responceRPC(ctx, status, args); } + void CallRPC(const IRPCCall& call) override final; + void SetClientData(std::unique_ptr&& data) noexcept override final { clientData_ = std::move(data); } + ClientData* GetClientData() noexcept override final { return clientData_.get(); } std::shared_ptr GetConnectionStat() noexcept override final { return BaseConnT::stats_ ? BaseConnT::stats_->get_stat() : std::shared_ptr(); } @@ -57,14 +57,14 @@ class ServerConnection final : public ConnectionST, public IServerConnection, pu protected: typename BaseConnT::ReadResT onRead() override; void onClose() override; - void handleRPC(Context &ctx); - void responceRPC(Context &ctx, const Error &error, const Args &args); - void async_cb(ev::async &) { sendUpdates(); } - void timeout_cb(ev::periodic &, int) { sendUpdates(); } + void handleRPC(Context& ctx); + void responceRPC(Context& ctx, const Error& error, const Args& args); + void async_cb(ev::async&) { sendUpdates(); } + void timeout_cb(ev::periodic&, int) { sendUpdates(); } void sendUpdates(); - void handleException(Context &ctx, const Error &err) noexcept; + void handleException(Context& ctx, const Error& err) noexcept; - Dispatcher &dispatcher_; + Dispatcher& dispatcher_; std::unique_ptr clientData_; // keep here to prevent allocs RPCCall call_; @@ -80,7 +80,7 @@ class ServerConnection final : public ConnectionST, public IServerConnection, pu bool enableSnappy_; bool hasPendingData_ = false; BalancingType balancingType_ = BalancingType::NotSet; - std::function rebalance_; + std::function rebalance_; }; } // namespace cproto diff --git a/cpp_src/net/ev/ev.cc b/cpp_src/net/ev/ev.cc index 089ce2987..47f72a377 100644 --- a/cpp_src/net/ev/ev.cc +++ b/cpp_src/net/ev/ev.cc @@ -105,7 +105,7 @@ class loop_select_backend_private { loop_select_backend::loop_select_backend() : private_(new loop_select_backend_private) {} loop_select_backend::~loop_select_backend() = default; -void loop_select_backend::init(dynamic_loop *owner) noexcept { +void loop_select_backend::init(dynamic_loop* owner) noexcept { owner_ = owner; private_->maxfd_ = -1; FD_ZERO(&private_->rfds_); @@ -115,7 +115,9 @@ void loop_select_backend::init(dynamic_loop *owner) noexcept { void loop_select_backend::set(int fd, int events, int /*oldevents*/) noexcept { assertrx(fd < capacity()); - if (fd > private_->maxfd_) private_->maxfd_ = fd; + if (fd > private_->maxfd_) { + private_->maxfd_ = fd; + } if (events & READ) { FD_SET(fd, &private_->rfds_); @@ -134,7 +136,9 @@ void loop_select_backend::stop(int fd) noexcept { FD_CLR(fd, &private_->rfds_); FD_CLR(fd, &private_->wfds_); - if (fd == private_->maxfd_) private_->maxfd_--; + if (fd == private_->maxfd_) { + private_->maxfd_--; + } } int loop_select_backend::runonce(int64_t t) { @@ -147,12 +151,16 @@ int loop_select_backend::runonce(int64_t t) { memcpy(&wfds, &private_->wfds_, 1 + (private_->maxfd_ / 8)); int ret = select(private_->maxfd_ + 1, &rfds, &wfds, nullptr, t != -1 ? &tv : nullptr); - if (ret < 0) return ret; + if (ret < 0) { + return ret; + } for (int fd = 0; fd < private_->maxfd_ + 1; fd++) { int events = (FD_ISSET(fd, &rfds) ? READ : 0) | (FD_ISSET(fd, &wfds) ? WRITE : 0); if (events) { - if (!check_async(fd)) owner_->io_callback(fd, events); + if (!check_async(fd)) { + owner_->io_callback(fd, events); + } } } return ret; @@ -172,7 +180,7 @@ class loop_poll_backend_private { loop_poll_backend::loop_poll_backend() : private_(new loop_poll_backend_private) {} loop_poll_backend::~loop_poll_backend() {} -void loop_poll_backend::init(dynamic_loop *owner) { +void loop_poll_backend::init(dynamic_loop* owner) { owner_ = owner; private_->fds_.reserve(2048); private_->fds_.resize(0); @@ -180,7 +188,7 @@ void loop_poll_backend::init(dynamic_loop *owner) { void loop_poll_backend::set(int fd, int events, int /*oldevents*/) { short ev = ((events & READ) ? (POLLRDNORM | POLLIN) : 0) | ((events & WRITE) ? (POLLWRNORM | POLLOUT) : 0); - int &idx = owner_->fds_[fd].idx; + int& idx = owner_->fds_[fd].idx; if (idx < 0) { private_->fds_.push_back({fd, ev, 0}); @@ -193,7 +201,7 @@ void loop_poll_backend::set(int fd, int events, int /*oldevents*/) { } void loop_poll_backend::stop(int fd) { - int &idx = owner_->fds_[fd].idx; + int& idx = owner_->fds_[fd].idx; assertrx(idx >= 0 && !private_->fds_.empty()); if (static_cast(idx) < private_->fds_.size() - 1) { @@ -209,20 +217,28 @@ void loop_poll_backend::stop(int fd) { int loop_poll_backend::runonce(int64_t t) { int ret = poll(&private_->fds_[0], private_->fds_.size(), t != -1 ? t / 1000 : -1); - if (ret < 1) return ret; + if (ret < 1) { + return ret; + } for (size_t i = 0; i < private_->fds_.size();) { - pollfd &pfd = private_->fds_[i]; + pollfd& pfd = private_->fds_[i]; private_->wasErased_ = false; if (pfd.revents != 0) { int events = ((pfd.revents & (POLLRDNORM | POLLIN | POLLHUP)) ? READ : 0) | ((pfd.revents & (POLLWRNORM | POLLOUT)) ? WRITE : 0); if (events) { - if (!check_async(pfd.fd)) owner_->io_callback(pfd.fd, events); - if (!private_->wasErased_) pfd.revents = 0; + if (!check_async(pfd.fd)) { + owner_->io_callback(pfd.fd, events); + } + if (!private_->wasErased_) { + pfd.revents = 0; + } } } - if (!private_->wasErased_) ++i; + if (!private_->wasErased_) { + ++i; + } } return ret; } @@ -246,7 +262,7 @@ loop_epoll_backend::~loop_epoll_backend() { private_->ctlfd_ = -1; } -void loop_epoll_backend::init(dynamic_loop *owner) { +void loop_epoll_backend::init(dynamic_loop* owner) { owner_ = owner; private_->ctlfd_ = epoll_create1(EPOLL_CLOEXEC); if (private_->ctlfd_ < 0) { @@ -285,10 +301,12 @@ int loop_epoll_backend::runonce(int64_t t) { std::swap(private_->events_, private_->eventsTmp_); private_->events_.resize(private_->eventsTmp_.size()); for (int i = 0; i < ret; i++) { - auto &eventRef = private_->eventsTmp_[i]; + auto& eventRef = private_->eventsTmp_[i]; int events = ((eventRef.events & (EPOLLIN | EPOLLHUP)) ? READ : 0) | ((eventRef.events & EPOLLOUT) ? WRITE : 0); int fd = eventRef.data.fd; - if (!check_async(fd)) owner_->io_callback(fd, events); + if (!check_async(fd)) { + owner_->io_callback(fd, events); + } } return ret; } @@ -316,7 +334,7 @@ loop_wsa_backend::loop_wsa_backend() : private_(new loop_wsa_backend_private) { } loop_wsa_backend::~loop_wsa_backend() { - for (auto &fd : private_->wfds_) { + for (auto& fd : private_->wfds_) { CloseHandle(fd.hEvent); fd.hEvent = INVALID_HANDLE_VALUE; } @@ -325,10 +343,10 @@ loop_wsa_backend::~loop_wsa_backend() { } } -void loop_wsa_backend::init(dynamic_loop *owner) { owner_ = owner; } +void loop_wsa_backend::init(dynamic_loop* owner) { owner_ = owner; } void loop_wsa_backend::set(int fd, int events, int oldevents) { - auto it = std::find_if(private_->wfds_.begin(), private_->wfds_.end(), [&](const win_fd &wfd) { return wfd.fd == fd; }); + auto it = std::find_if(private_->wfds_.begin(), private_->wfds_.end(), [&](const win_fd& wfd) { return wfd.fd == fd; }); if (it == private_->wfds_.end()) { assertrx(int(private_->wfds_.size()) < capacity()); win_fd new_wfd; @@ -344,7 +362,7 @@ void loop_wsa_backend::set(int fd, int events, int oldevents) { } void loop_wsa_backend::stop(int fd) { - auto it = std::find_if(private_->wfds_.begin(), private_->wfds_.end(), [&](const win_fd &wfd) { return wfd.fd == fd; }); + auto it = std::find_if(private_->wfds_.begin(), private_->wfds_.end(), [&](const win_fd& wfd) { return wfd.fd == fd; }); if (it == private_->wfds_.end()) { return; } @@ -355,7 +373,9 @@ void loop_wsa_backend::stop(int fd) { int loop_wsa_backend::runonce(int64_t t) { HANDLE objs[WSA_MAXIMUM_WAIT_EVENTS]; unsigned ecount = private_->wfds_.size(); - for (unsigned i = 0; i < ecount; i++) objs[i] = private_->wfds_[i].hEvent; + for (unsigned i = 0; i < ecount; i++) { + objs[i] = private_->wfds_[i].hEvent; + } if (private_->hAsyncEvent != INVALID_HANDLE_VALUE) { objs[ecount] = private_->hAsyncEvent; @@ -467,7 +487,9 @@ void dynamic_loop::run() { if (!gEnableBusyLoop && timers_.size()) { tv = std::chrono::duration_cast(timers_.front()->deadline_ - now).count(); - if (tv < 0) tv = 0; + if (tv < 0) { + tv = 0; + } } int ret = backend_.runonce(tv); @@ -499,7 +521,7 @@ void dynamic_loop::run() { remove_coro_cb(); } -void dynamic_loop::set(int fd, io *watcher, int events) { +void dynamic_loop::set(int fd, io* watcher, int events) { if (fd < 0) { return; } @@ -522,7 +544,7 @@ void dynamic_loop::stop(int fd) { backend_.stop(fd); } -void dynamic_loop::set(timer *watcher, double t) { +void dynamic_loop::set(timer* watcher, double t) { auto it = std::find(timers_.begin(), timers_.end(), watcher); if (it != timers_.end()) { timers_.erase(it); @@ -531,18 +553,18 @@ void dynamic_loop::set(timer *watcher, double t) { watcher->deadline_ = steady_clock_w::now(); watcher->deadline_ += std::chrono::duration>(int64_t(t * 1000000)); it = std::lower_bound(timers_.begin(), timers_.end(), watcher, - [](const timer *lhs, const timer *rhs) { return lhs->deadline_ < rhs->deadline_; }); + [](const timer* lhs, const timer* rhs) { return lhs->deadline_ < rhs->deadline_; }); timers_.insert(it, watcher); } -void dynamic_loop::stop(timer *watcher) { +void dynamic_loop::stop(timer* watcher) { auto it = std::find(timers_.begin(), timers_.end(), watcher); if (it != timers_.end()) { timers_.erase(it); } } -void dynamic_loop::set(sig *watcher) { +void dynamic_loop::set(sig* watcher) { auto it = std::find(sigs_.begin(), sigs_.end(), watcher); if (it != sigs_.end()) { fprintf(stderr, "sig %d already set\n", watcher->signum_); @@ -566,7 +588,7 @@ void dynamic_loop::set(sig *watcher) { #endif } -void dynamic_loop::stop(sig *watcher) { +void dynamic_loop::stop(sig* watcher) { auto it = std::find(sigs_.begin(), sigs_.end(), watcher); if (it == sigs_.end()) { fprintf(stderr, "sig %d is not set\n", watcher->signum_); @@ -584,7 +606,7 @@ void dynamic_loop::stop(sig *watcher) { #endif } -void dynamic_loop::set(async *watcher) { +void dynamic_loop::set(async* watcher) { auto it = std::find(asyncs_.begin(), asyncs_.end(), watcher); if (it != asyncs_.end()) { return; @@ -593,7 +615,7 @@ void dynamic_loop::set(async *watcher) { asyncs_.push_back(watcher); } -void dynamic_loop::stop(async *watcher) { +void dynamic_loop::stop(async* watcher) { auto it = std::find(asyncs_.begin(), asyncs_.end(), watcher); if (it == asyncs_.end()) { return; @@ -601,7 +623,7 @@ void dynamic_loop::stop(async *watcher) { asyncs_.erase(it); } -void dynamic_loop::send(async *watcher) { +void dynamic_loop::send(async* watcher) { watcher->sent_ = true; bool was = async_sent_.exchange(true); if (!was) { @@ -609,7 +631,7 @@ void dynamic_loop::send(async *watcher) { } } -bool dynamic_loop::is_active(const timer *watcher) const noexcept { +bool dynamic_loop::is_active(const timer* watcher) const noexcept { return std::find(timers_.begin(), timers_.end(), watcher) != timers_.end(); } @@ -630,8 +652,9 @@ void dynamic_loop::async_callback() { (*async)->sent_ = false; (*async)->callback(); async = asyncs_.begin(); - } else + } else { async++; + } } } diff --git a/cpp_src/net/ev/ev.h b/cpp_src/net/ev/ev.h index 2c26539d9..337708975 100644 --- a/cpp_src/net/ev/ev.h +++ b/cpp_src/net/ev/ev.h @@ -51,7 +51,7 @@ class loop_posix_base { bool check_async(int fd); int async_fd_ = -1; - dynamic_loop *owner_ = nullptr; + dynamic_loop* owner_ = nullptr; }; #else // HAVE_EVENT_FD class loop_posix_base { @@ -65,7 +65,7 @@ class loop_posix_base { bool check_async(int fd); int async_fds_[2] = {-1, -1}; - dynamic_loop *owner_ = nullptr; + dynamic_loop* owner_ = nullptr; }; #endif // HAVE_EVENT_FD @@ -74,7 +74,7 @@ class loop_poll_backend : public loop_posix_base { public: loop_poll_backend(); ~loop_poll_backend(); - void init(dynamic_loop *owner); + void init(dynamic_loop* owner); void set(int fd, int events, int oldevents); void stop(int fd); int runonce(int64_t tv); @@ -89,7 +89,7 @@ class loop_select_backend : public loop_posix_base { public: loop_select_backend(); ~loop_select_backend(); - void init(dynamic_loop *owner) noexcept; + void init(dynamic_loop* owner) noexcept; void set(int fd, int events, int oldevents) noexcept; void stop(int fd) noexcept; int runonce(int64_t tv); @@ -106,7 +106,7 @@ class loop_epoll_backend : public loop_posix_base { public: loop_epoll_backend(); ~loop_epoll_backend(); - void init(dynamic_loop *owner); + void init(dynamic_loop* owner); void set(int fd, int events, int oldevents); void stop(int fd); int runonce(int64_t tv); @@ -123,7 +123,7 @@ class loop_wsa_backend { public: loop_wsa_backend(); ~loop_wsa_backend(); - void init(dynamic_loop *owner); + void init(dynamic_loop* owner); void set(int fd, int events, int oldevents); void stop(int fd); int runonce(int64_t tv); @@ -133,7 +133,7 @@ class loop_wsa_backend { static int capacity(); protected: - dynamic_loop *owner_; + dynamic_loop* owner_; std::unique_ptr private_; }; #endif @@ -170,19 +170,19 @@ class dynamic_loop { void sleep(std::chrono::duration dur); template void granular_sleep(std::chrono::duration dur, std::chrono::duration granularity, - Terminater const &terminate); + const Terminater& terminate); protected: - void set(int fd, io *watcher, int events); - void set(timer *watcher, double t); - void set(async *watcher); - void set(sig *watcher); + void set(int fd, io* watcher, int events); + void set(timer* watcher, double t); + void set(async* watcher); + void set(sig* watcher); void stop(int fd); - void stop(timer *watcher); - void stop(async *watcher); - void stop(sig *watcher); - void send(async *watcher); - bool is_active(const timer *watcher) const noexcept; + void stop(timer* watcher); + void stop(async* watcher); + void stop(sig* watcher); + void send(async* watcher); + bool is_active(const timer* watcher) const noexcept; void io_callback(int fd, int events); void async_callback(); @@ -193,13 +193,13 @@ class dynamic_loop { struct fd_handler { int emask_ = 0; int idx = -1; - io *watcher_ = nullptr; + io* watcher_ = nullptr; }; std::vector fds_; - std::vector timers_; - std::vector asyncs_; - std::vector sigs_; + std::vector timers_; + std::vector asyncs_; + std::vector sigs_; bool break_ = false; bool coro_cb_is_set_ = false; std::atomic async_sent_; @@ -230,35 +230,49 @@ class loop_ref { public: void break_loop() noexcept { - if (loop_) loop_->break_loop(); + if (loop_) { + loop_->break_loop(); + } } void run() { - if (loop_) loop_->run(); + if (loop_) { + loop_->run(); + } } void enable_asyncs() { - if (loop_) loop_->backend_.enable_asyncs(); + if (loop_) { + loop_->backend_.enable_asyncs(); + } } bool is_valid() const noexcept { return loop_; } protected: template void set(Args... args) { - if (loop_) loop_->set(args...); + if (loop_) { + loop_->set(args...); + } } template void stop(Args... args) { - if (loop_) loop_->stop(args...); + if (loop_) { + loop_->stop(args...); + } } template void send(Args... args) { - if (loop_) loop_->send(args...); + if (loop_) { + loop_->send(args...); + } } template bool is_active(Args... args) const noexcept { - if (loop_) return loop_->is_active(args...); + if (loop_) { + return loop_->is_active(args...); + } return false; } - dynamic_loop *loop_ = nullptr; + dynamic_loop* loop_ = nullptr; }; class io { @@ -266,10 +280,10 @@ class io { public: io() = default; - io(const io &) = delete; + io(const io&) = delete; ~io() { stop(); } - void set(dynamic_loop &loop_) noexcept { loop.loop_ = &loop_; } + void set(dynamic_loop& loop_) noexcept { loop.loop_ = &loop_; } void set(int events) { loop.set(fd, this, events); } void start(int _fd, int events) { fd = _fd; @@ -281,11 +295,11 @@ class io { } void reset() noexcept { loop.loop_ = nullptr; } - template - void set(K *object) { - func_ = [object](io &watcher, int events) { (static_cast(object)->*func)(watcher, events); }; + template + void set(K* object) { + func_ = [object](io& watcher, int events) { (static_cast(object)->*func)(watcher, events); }; } - void set(std::function func) noexcept { func_ = std::move(func); } + void set(std::function func) noexcept { func_ = std::move(func); } int fd = -1; loop_ref loop; @@ -295,19 +309,19 @@ class io { assertrx(func_ != nullptr); func_(*this, events); } - std::function func_ = nullptr; + std::function func_ = nullptr; }; class timer { friend class dynamic_loop; public: timer() = default; - timer(const timer &) = delete; - timer(timer &&) = default; - timer &operator=(timer &&) = default; + timer(const timer&) = delete; + timer(timer&&) = default; + timer& operator=(timer&&) = default; ~timer() { stop(); } - void set(dynamic_loop &loop_) noexcept { loop.loop_ = &loop_; } + void set(dynamic_loop& loop_) noexcept { loop.loop_ = &loop_; } void start(double t, double p = 0) { period_ = p; loop.set(this, t); @@ -315,11 +329,11 @@ class timer { void stop() { loop.stop(this); } void reset() noexcept { loop.loop_ = nullptr; } - template - void set(K *object) { - func_ = [object](timer &watcher, int t) { (static_cast(object)->*func)(watcher, t); }; + template + void set(K* object) { + func_ = [object](timer& watcher, int t) { (static_cast(object)->*func)(watcher, t); }; } - void set(std::function func) noexcept { func_ = std::move(func); } + void set(std::function func) noexcept { func_ = std::move(func); } bool is_active() const noexcept { return loop.is_active(this); } bool has_period() const noexcept { return period_ > 0.00000001; } @@ -344,7 +358,7 @@ class timer { } } - std::function func_ = nullptr; + std::function func_ = nullptr; double period_ = 0; bool in_coro_storage_ = false; }; @@ -356,7 +370,7 @@ void dynamic_loop::sleep(std::chrono::duration dur) { auto id = coroutine::current(); if (id) { timer tm(timer::coro_t{}); - tm.set([id](timer &, int) { coroutine::resume(id); }); + tm.set([id](timer&, int) { coroutine::resume(id); }); tm.set(*this); double awaitTime = std::chrono::duration_cast(dur).count(); tm.start(awaitTime / 1e6); @@ -371,7 +385,7 @@ void dynamic_loop::sleep(std::chrono::duration dur) { template void dynamic_loop::granular_sleep(std::chrono::duration dur, std::chrono::duration granularity, - Terminater const &terminate) { + const Terminater& terminate) { for (std::chrono::nanoseconds t = dur; t.count() > 0; t -= granularity) { if (terminate()) { return; @@ -385,10 +399,10 @@ class sig { public: sig() = default; // -V730 - sig(const sig &) = delete; + sig(const sig&) = delete; ~sig() { stop(); } - void set(dynamic_loop &loop_) noexcept { loop.loop_ = &loop_; } + void set(dynamic_loop& loop_) noexcept { loop.loop_ = &loop_; } void start(int signum) { signum_ = signum; loop.set(this); @@ -396,11 +410,11 @@ class sig { void stop() { loop.stop(this); } void reset() noexcept { loop.loop_ = nullptr; } - template - void set(K *object) { - func_ = [object](sig &watcher) { (static_cast(object)->*func)(watcher); }; + template + void set(K* object) { + func_ = [object](sig& watcher) { (static_cast(object)->*func)(watcher); }; } - void set(std::function func) noexcept { func_ = std::move(func); } + void set(std::function func) noexcept { func_ = std::move(func); } loop_ref loop; @@ -410,7 +424,7 @@ class sig { func_(*this); } - std::function func_ = nullptr; + std::function func_ = nullptr; #ifndef _WIN32 struct sigaction old_action_; #else @@ -424,10 +438,10 @@ class async { public: async() : sent_(false) {} - async(const async &) = delete; + async(const async&) = delete; ~async() { stop(); } - void set(dynamic_loop &loop_) { + void set(dynamic_loop& loop_) { loop.loop_ = &loop_; loop.enable_asyncs(); } @@ -436,11 +450,11 @@ class async { void reset() noexcept { loop.loop_ = nullptr; } void send() { loop.send(this); } - template - void set(K *object) { - func_ = [object](async &watcher) { (static_cast(object)->*func)(watcher); }; + template + void set(K* object) { + func_ = [object](async& watcher) { (static_cast(object)->*func)(watcher); }; } - void set(std::function func) noexcept { func_ = std::move(func); } + void set(std::function func) noexcept { func_ = std::move(func); } loop_ref loop; @@ -450,7 +464,7 @@ class async { func_(*this); } - std::function func_ = nullptr; + std::function func_ = nullptr; std::atomic sent_; }; diff --git a/cpp_src/net/http/router.cc b/cpp_src/net/http/router.cc index df31b3d6b..faacfc9e6 100644 --- a/cpp_src/net/http/router.cc +++ b/cpp_src/net/http/router.cc @@ -67,7 +67,7 @@ int Context::JSON(int code, std::string_view slice) { return 0; } -int Context::JSON(int code, chunk &&chunk) { +int Context::JSON(int code, chunk&& chunk) { writer->SetContentLength(chunk.len()); writer->SetRespCode(code); writer->SetHeader(http::Header{"Content-Type"sv, "application/json; charset=utf-8"sv}); @@ -75,7 +75,7 @@ int Context::JSON(int code, chunk &&chunk) { return 0; } -int Context::CSV(int code, chunk &&chunk) { +int Context::CSV(int code, chunk&& chunk) { writer->SetRespCode(code); writer->SetHeader(http::Header{"Content-Type"sv, "application/csv; charset=utf-8"sv}); if (auto filename = request->headers.Get("Save-Csv-To"sv); !filename.empty()) { @@ -85,7 +85,7 @@ int Context::CSV(int code, chunk &&chunk) { return 0; } -int Context::MSGPACK(int code, chunk &&chunk) { +int Context::MSGPACK(int code, chunk&& chunk) { writer->SetContentLength(chunk.len()); writer->SetRespCode(code); writer->SetHeader(http::Header{"Content-Type"sv, "application/x-msgpack; charset=utf-8"sv}); @@ -93,7 +93,7 @@ int Context::MSGPACK(int code, chunk &&chunk) { return 0; } -int Context::Protobuf(int code, chunk &&chunk) { +int Context::Protobuf(int code, chunk&& chunk) { writer->SetContentLength(chunk.len()); writer->SetRespCode(code); writer->SetHeader(http::Header{"Content-Type"sv, "application/protobuf; charset=utf-8"sv}); @@ -109,7 +109,7 @@ int Context::String(int code, std::string_view slice) { return 0; } -int Context::String(int code, chunk &&chunk) { +int Context::String(int code, chunk&& chunk) { writer->SetContentLength(chunk.len()); writer->SetRespCode(code); writer->SetHeader(http::Header{"Content-Type"sv, "text/plain; charset=utf-8"sv}); @@ -128,13 +128,27 @@ static std::string_view lookupContentType(std::string_view path) { return "application/octet-stream"sv; } p++; - if (path.substr(p, 4) == "html"sv) return "text/html; charset=utf-8"sv; - if (path.substr(p, 4) == "json"sv) return "application/json; charset=utf-8"sv; - if (path.substr(p, 3) == "yml"sv) return "application/yml; charset=utf-8"sv; - if (path.substr(p, 3) == "css"sv) return "text/css; charset=utf-8"sv; - if (path.substr(p, 2) == "js"sv) return "application/javascript; charset=utf-8"sv; - if (path.substr(p, 4) == "woff"sv) return "font/woff"sv; - if (path.substr(p, 5) == "woff2"sv) return "font/woff2"sv; + if (path.substr(p, 4) == "html"sv) { + return "text/html; charset=utf-8"sv; + } + if (path.substr(p, 4) == "json"sv) { + return "application/json; charset=utf-8"sv; + } + if (path.substr(p, 3) == "yml"sv) { + return "application/yml; charset=utf-8"sv; + } + if (path.substr(p, 3) == "css"sv) { + return "text/css; charset=utf-8"sv; + } + if (path.substr(p, 2) == "js"sv) { + return "application/javascript; charset=utf-8"sv; + } + if (path.substr(p, 4) == "woff"sv) { + return "font/woff"sv; + } + if (path.substr(p, 5) == "woff2"sv) { + return "font/woff2"sv; + } return "application/octet-stream"sv; } @@ -166,19 +180,22 @@ int Context::File(int code, std::string_view path, std::string_view data, bool i std::vector methodNames = {"GET"sv, "POST"sv, "OPTIONS"sv, "HEAD"sv, "PUT"sv, "DELETE"sv, "PATCH"sv}; HttpMethod lookupMethod(std::string_view method) { - for (auto &cm : methodNames) - if (method == cm) return HttpMethod(&cm - &methodNames[0]); + for (auto& cm : methodNames) { + if (method == cm) { + return HttpMethod(&cm - &methodNames[0]); + } + } return HttpMethod(kMethodUnknown); } -int Router::handle(Context &ctx) { +int Router::handle(Context& ctx) { auto method = lookupMethod(ctx.request->method); if (method < 0) { return ctx.String(StatusBadRequest, "Invalid method"sv); } int res = 0; - for (auto &r : routes_[method]) { + for (auto& r : routes_[method]) { std::string_view url = ctx.request->path; std::string_view route = r.path; ctx.request->urlParams.clear(); @@ -187,9 +204,11 @@ int Router::handle(Context &ctx) { auto patternPos = route.find(':'); auto asteriskPos = route.find('*'); if (patternPos == std::string_view::npos || asteriskPos != std::string_view::npos) { - if (url.substr(0, asteriskPos) != route.substr(0, asteriskPos)) break; + if (url.substr(0, asteriskPos) != route.substr(0, asteriskPos)) { + break; + } - for (auto &mw : middlewares_) { + for (auto& mw : middlewares_) { res = mw.func(mw.object, ctx); if (res != 0) { return res; @@ -198,7 +217,9 @@ int Router::handle(Context &ctx) { return r.h.func(r.h.object, ctx); } - if (url.substr(0, patternPos) != route.substr(0, patternPos)) break; + if (url.substr(0, patternPos) != route.substr(0, patternPos)) { + break; + } url = url.substr(patternPos); route = route.substr(patternPos); diff --git a/cpp_src/net/http/router.h b/cpp_src/net/http/router.h index b25d12d56..8ea390ca9 100644 --- a/cpp_src/net/http/router.h +++ b/cpp_src/net/http/router.h @@ -66,7 +66,7 @@ typedef std::string_view UrlParam; struct HttpStatus { HttpStatus() noexcept : code(StatusOK) {} HttpStatus(HttpStatusCode httpcode, std::string httpwhat) : code(httpcode), what(std::move(httpwhat)) {} - explicit HttpStatus(const Error &err) : what(err.what()) { code = errCodeToHttpStatus(err.code()); } + explicit HttpStatus(const Error& err) : what(err.what()) { code = errCodeToHttpStatus(err.code()); } HttpStatusCode code; std::string what; @@ -91,7 +91,7 @@ class Headers : public h_vector { public: using h_vector::h_vector; std::string_view Get(std::string_view name) noexcept { - auto it = std::find_if(begin(), end(), [=](const Header &hdr) { return iequals(name, hdr.name); }); + auto it = std::find_if(begin(), end(), [=](const Header& hdr) { return iequals(name, hdr.name); }); return it != end() ? it->val : std::string_view(); } }; @@ -100,7 +100,7 @@ class Params : public h_vector { public: using h_vector::h_vector; std::string_view Get(const std::string_view name) { - auto it = std::find_if(begin(), end(), [=](const Param ¶m) { return name == param.name; }); + auto it = std::find_if(begin(), end(), [=](const Param& param) { return name == param.name; }); return it != end() ? it->val : std::string_view(); } }; @@ -121,11 +121,11 @@ struct Request { class Writer { public: enum class WriteMode { Default = 0, PreChunkedBody = 1 }; - virtual ssize_t Write(chunk &&ch, WriteMode mode = WriteMode::Default) = 0; + virtual ssize_t Write(chunk&& ch, WriteMode mode = WriteMode::Default) = 0; virtual ssize_t Write(std::string_view data) = 0; virtual chunk GetChunk() = 0; - virtual bool SetHeader(const Header &hdr) = 0; + virtual bool SetHeader(const Header& hdr) = 0; virtual bool SetRespCode(int code) = 0; virtual bool SetContentLength(size_t len) = 0; virtual bool SetConnectionClose() = 0; @@ -137,7 +137,7 @@ class Writer { class Reader { public: - virtual ssize_t Read(void *buf, size_t size) = 0; + virtual ssize_t Read(void* buf, size_t size) = 0; virtual std::string Read(size_t size = INT_MAX) = 0; virtual ssize_t Pending() const = 0; virtual ~Reader() = default; @@ -151,18 +151,18 @@ static constexpr std::string_view kGzSuffix(".gz"); struct Context { int JSON(int code, std::string_view slice); - int JSON(int code, chunk &&chunk); - int CSV(int code, chunk &&chunk); - int MSGPACK(int code, chunk &&chunk); - int Protobuf(int code, chunk &&chunk); + int JSON(int code, chunk&& chunk); + int CSV(int code, chunk&& chunk); + int MSGPACK(int code, chunk&& chunk); + int Protobuf(int code, chunk&& chunk); int String(int code, std::string_view slice); - int String(int code, chunk &&chunk); + int String(int code, chunk&& chunk); int File(int code, std::string_view path, std::string_view data, bool isGzip, bool withCache); int Redirect(std::string_view url); - Request *request; - Writer *writer; - Reader *body; + Request* request; + Writer* writer; + Reader* body; std::unique_ptr clientData; Stat stat; @@ -179,77 +179,77 @@ class Router { /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void POST(const char *path, K *object) { + template + void POST(const char* path, K* object) { addRoute(kMethodPOST, path, object); } /// Add handler for http GET method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void GET(const char *path, K *object) { + template + void GET(const char* path, K* object) { addRoute(kMethodGET, path, object); } /// Add handler for http OPTIONS method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void OPTIONS(const char *path, K *object) { + template + void OPTIONS(const char* path, K* object) { addRoute(kMethodOPTIONS, path, object); } - template + template /// Add handler for http DELETE method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - void DELETE(const char *path, K *object) { + void DELETE(const char* path, K* object) { addRoute(kMethodDELETE, path, object); } /// Add handler for http PUT method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void PUT(const char *path, K *object) { + template + void PUT(const char* path, K* object) { addRoute(kMethodPUT, path, object); } /// Add handler for http PATCH method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void PATCH(const char *path, K *object) { + template + void PATCH(const char* path, K* object) { addRoute(kMethodPATCH, path, object); } /// Add handler for http HEAD method. /// @param path - URI pattern /// @param object - handler class object /// @tparam func - handler - template - void HEAD(const char *path, K *object) { + template + void HEAD(const char* path, K* object) { addRoute(kMethodHEAD, path, object); } /// Add middleware /// @param object - handler class object /// @tparam func - handler - template - void Middleware(K *object) { + template + void Middleware(K* object) { middlewares_.emplace_back(func_wrapper, object); } /// Add logger for requests /// @param object - logger class object /// @tparam func - logger - template - void Logger(K *object) { - logger_ = [=](Context &ctx) { (static_cast(object)->*func)(ctx); }; + template + void Logger(K* object) { + logger_ = [=](Context& ctx) { (static_cast(object)->*func)(ctx); }; } /// Add default handler for not found URI's /// @tparam func - handler - template - void NotFound(K *object) { + template + void NotFound(K* object) { notFoundHandler_ = Handler{func_wrapper, object}; } @@ -257,36 +257,38 @@ class Router { /// @param object class object /// @param func function, to be called on response sent template - void OnResponse(K *object, void (K::*func)(Context &ctx)) { - onResponse_ = [=](Context &ctx) { (static_cast(object)->*func)(ctx); }; + void OnResponse(K* object, void (K::*func)(Context& ctx)) { + onResponse_ = [=](Context& ctx) { (static_cast(object)->*func)(ctx); }; } protected: - int handle(Context &ctx); - void log(Context &ctx) { - if (logger_) logger_(ctx); + int handle(Context& ctx); + void log(Context& ctx) { + if (logger_) { + logger_(ctx); + } } - template - void addRoute(HttpMethod method, const char *path, K *object) { + template + void addRoute(HttpMethod method, const char* path, K* object) { routes_[method].emplace_back(path, Handler{func_wrapper, object}); } - template - static int func_wrapper(void *obj, Context &ctx) { - return (static_cast(obj)->*func)(ctx); + template + static int func_wrapper(void* obj, Context& ctx) { + return (static_cast(obj)->*func)(ctx); } struct Handler { - using FuncT = std::function; - Handler(FuncT &&f, void *o) noexcept : func(std::move(f)), object(o) {} + using FuncT = std::function; + Handler(FuncT&& f, void* o) noexcept : func(std::move(f)), object(o) {} FuncT func; - void *object; + void* object; }; struct Route { - Route(std::string &&p, Handler &&_h) : path(std::move(p)), h(std::move(_h)) {} + Route(std::string&& p, Handler&& _h) : path(std::move(p)), h(std::move(_h)) {} std::string path; Handler h; @@ -296,8 +298,8 @@ class Router { std::vector middlewares_; Handler notFoundHandler_{{}, nullptr}; - std::function logger_; - std::function onResponse_; + std::function logger_; + std::function onResponse_; }; } // namespace http } // namespace net diff --git a/cpp_src/net/http/serverconnection.cc b/cpp_src/net/http/serverconnection.cc index 5c51b5814..464880c23 100644 --- a/cpp_src/net/http/serverconnection.cc +++ b/cpp_src/net/http/serverconnection.cc @@ -19,14 +19,14 @@ using namespace std::string_view_literals; static const std::string_view kStrEOL = "\r\n"sv; extern std::unordered_map kHTTPCodes; -ServerConnection::ServerConnection(socket &&s, ev::dynamic_loop &loop, Router &router, size_t maxRequestSize) +ServerConnection::ServerConnection(socket&& s, ev::dynamic_loop& loop, Router& router, size_t maxRequestSize) : ConnectionST(std::move(s), loop, false, maxRequestSize < kConnReadbufSize ? maxRequestSize : kConnReadbufSize), router_(router), maxRequestSize_(maxRequestSize) { callback(io_, ev::READ); } -bool ServerConnection::Restart(socket &&s) { +bool ServerConnection::Restart(socket&& s) { restart(std::move(s)); bodyLeft_ = 0; formData_ = false; @@ -36,24 +36,28 @@ bool ServerConnection::Restart(socket &&s) { return true; } -void ServerConnection::Attach(ev::dynamic_loop &loop) { - if (!attached_) attach(loop); +void ServerConnection::Attach(ev::dynamic_loop& loop) { + if (!attached_) { + attach(loop); + } } void ServerConnection::Detach() { - if (attached_) detach(); + if (attached_) { + detach(); + } } void ServerConnection::onClose() {} -void ServerConnection::handleException(Context &ctx, const Error &status) { - auto writer = dynamic_cast(ctx.writer); +void ServerConnection::handleException(Context& ctx, const Error& status) { + auto writer = dynamic_cast(ctx.writer); if (writer && !writer->IsRespSent()) { HttpStatus httpStatus(status); setJsonStatus(ctx, false, httpStatus.code, httpStatus.what); } } -void ServerConnection::setJsonStatus(Context &ctx, bool success, int responseCode, const std::string &status) { +void ServerConnection::setJsonStatus(Context& ctx, bool success, int responseCode, const std::string& status) { WrSerializer ser; JsonBuilder builder(ser); builder.Put("success", success); @@ -63,7 +67,7 @@ void ServerConnection::setJsonStatus(Context &ctx, bool success, int responseCod ctx.JSON(responseCode, ser.Slice()); } -void ServerConnection::handleRequest(Request &req) { +void ServerConnection::handleRequest(Request& req) { ResponseWriter writer(this); BodyReader reader(this); Context ctx; @@ -74,13 +78,13 @@ void ServerConnection::handleRequest(Request &req) { try { router_.handle(ctx); - } catch (const HttpStatus &status) { + } catch (const HttpStatus& status) { if (!writer.IsRespSent()) { setJsonStatus(ctx, false, status.code, status.what); } - } catch (const Error &status) { + } catch (const Error& status) { handleException(ctx, status); - } catch (const std::exception &e) { + } catch (const std::exception& e) { handleException(ctx, Error(errLogic, e.what())); } catch (...) { handleException(ctx, Error(errLogic, "Unknown exception")); @@ -94,7 +98,7 @@ void ServerConnection::handleRequest(Request &req) { } } -void ServerConnection::badRequest(int code, const char *msg) { +void ServerConnection::badRequest(int code, const char* msg) { ResponseWriter writer(this); HandlerStat stat; Context ctx; @@ -113,15 +117,19 @@ void ServerConnection::badRequest(int code, const char *msg) { } void ServerConnection::parseParams(std::string_view str) { - const char *p = str.data(); + const char* p = str.data(); const char *name = nullptr, *value = nullptr; size_t namelen = 0; for (size_t l = 0; l < str.length(); l++) { - if (!name) name = p; + if (!name) { + name = p; + } switch (*p) { case '&': - if (!value) namelen = p - name; + if (!value) { + namelen = p - name; + } if (name) { request_.params.emplace_back(std::string_view(name, namelen), std::string_view(value, value ? p - value : 0)); name = value = nullptr; @@ -140,7 +148,9 @@ void ServerConnection::parseParams(std::string_view str) { p++; } if (name) { - if (!value) namelen = p - name; + if (!value) { + namelen = p - name; + } request_.params.emplace_back(std::string_view(name, namelen), std::string_view(value, value ? p - value : 0)); } } @@ -151,7 +161,9 @@ void ServerConnection::writeHttpResponse(int code) { ser << "HTTP/1.1 "sv << code << ' '; auto it = kHTTPCodes.find(code); - if (it != kHTTPCodes.end()) ser << it->second; + if (it != kHTTPCodes.end()) { + ser << it->second; + } ser << kStrEOL; wrBuf_.write(ser.DetachChunk()); } @@ -279,32 +291,40 @@ ServerConnection::ReadResT ServerConnection::onRead() { break; } } - if (!rdBuf_.size() && !bodyLeft_) rdBuf_.clear(); - } catch (const Error &e) { + if (!rdBuf_.size() && !bodyLeft_) { + rdBuf_.clear(); + } + } catch (const Error& e) { fprintf(stderr, "Dropping HTTP-connection. Reason: %s\n", e.what().c_str()); closeConn_ = true; } return ReadResT::Default; } -bool ServerConnection::ResponseWriter::SetHeader(const Header &hdr) { - if (respSend_) return false; +bool ServerConnection::ResponseWriter::SetHeader(const Header& hdr) { + if (respSend_) { + return false; + } headers_ << hdr.name << ": "sv << hdr.val << kStrEOL; return true; } bool ServerConnection::ResponseWriter::SetRespCode(int code) { - if (respSend_) return false; + if (respSend_) { + return false; + } code_ = code; return true; } bool ServerConnection::ResponseWriter::SetContentLength(size_t length) { - if (respSend_) return false; + if (respSend_) { + return false; + } contentLength_ = length; return true; } -ssize_t ServerConnection::ResponseWriter::Write(chunk &&chunk, Writer::WriteMode mode) { +ssize_t ServerConnection::ResponseWriter::Write(chunk&& chunk, Writer::WriteMode mode) { char szBuf[64], dtBuf[128]; if (!respSend_) { conn_->writeHttpResponse(code_); @@ -361,9 +381,9 @@ bool ServerConnection::ResponseWriter::SetConnectionClose() { return true; } -ssize_t ServerConnection::BodyReader::Read(void *buf, size_t size) { +ssize_t ServerConnection::BodyReader::Read(void* buf, size_t size) { if (conn_->bodyLeft_ > 0) { - size_t readed = conn_->rdBuf_.read(reinterpret_cast(buf), std::min(ssize_t(size), conn_->bodyLeft_)); + size_t readed = conn_->rdBuf_.read(reinterpret_cast(buf), std::min(ssize_t(size), conn_->bodyLeft_)); conn_->bodyLeft_ -= readed; return readed; } diff --git a/cpp_src/net/http/serverconnection.h b/cpp_src/net/http/serverconnection.h index 261dca784..f95d0faa4 100644 --- a/cpp_src/net/http/serverconnection.h +++ b/cpp_src/net/http/serverconnection.h @@ -14,10 +14,10 @@ namespace http { const ssize_t kHttpMaxHeaders = 128; class ServerConnection final : public IServerConnection, public ConnectionST { public: - ServerConnection(socket &&s, ev::dynamic_loop &loop, Router &router, size_t maxRequestSize); + ServerConnection(socket&& s, ev::dynamic_loop& loop, Router& router, size_t maxRequestSize); - static ConnectionFactory NewFactory(Router &router, size_t maxRequestSize) { - return [&router, maxRequestSize](ev::dynamic_loop &loop, socket &&s, bool allowCustomBalancing) { + static ConnectionFactory NewFactory(Router& router, size_t maxRequestSize) { + return [&router, maxRequestSize](ev::dynamic_loop& loop, socket&& s, bool allowCustomBalancing) { (void)allowCustomBalancing; return new ServerConnection(std::move(s), loop, router, maxRequestSize); }; @@ -25,32 +25,32 @@ class ServerConnection final : public IServerConnection, public ConnectionST { bool IsFinished() const noexcept override final { return !sock_.valid(); } BalancingType GetBalancingType() const noexcept override final { return BalancingType::None; } - void SetRebalanceCallback(std::function cb) override final { (void)cb; } + void SetRebalanceCallback(std::function cb) override final { (void)cb; } bool HasPendingData() const noexcept override final { return false; } void HandlePendingData() override final {} - bool Restart(socket &&s) override final; + bool Restart(socket&& s) override final; void Detach() override final; - void Attach(ev::dynamic_loop &loop) override final; + void Attach(ev::dynamic_loop& loop) override final; protected: class BodyReader : public Reader { public: - BodyReader(ServerConnection *conn) : conn_(conn) {} - ssize_t Read(void *buf, size_t size) override final; + BodyReader(ServerConnection* conn) : conn_(conn) {} + ssize_t Read(void* buf, size_t size) override final; std::string Read(size_t size = INT_MAX) override final; ssize_t Pending() const override final; protected: - ServerConnection *conn_; + ServerConnection* conn_; }; class ResponseWriter : public Writer { public: - ResponseWriter(ServerConnection *conn) : headers_(conn->wrBuf_.get_chunk()), conn_(conn) {} - virtual bool SetHeader(const Header &hdr) override final; + ResponseWriter(ServerConnection* conn) : headers_(conn->wrBuf_.get_chunk()), conn_(conn) {} + virtual bool SetHeader(const Header& hdr) override final; virtual bool SetRespCode(int code) override final; virtual bool SetContentLength(size_t len) override final; virtual bool SetConnectionClose() override final; - ssize_t Write(chunk &&chunk, Writer::WriteMode mode = WriteMode::Default) override final; + ssize_t Write(chunk&& chunk, Writer::WriteMode mode = WriteMode::Default) override final; ssize_t Write(std::string_view data) override final; virtual chunk GetChunk() override final; @@ -66,20 +66,20 @@ class ServerConnection final : public IServerConnection, public ConnectionST { WrSerializer headers_; bool respSend_ = false; ssize_t contentLength_ = -1, written_ = 0; - ServerConnection *conn_; + ServerConnection* conn_; }; - void handleRequest(Request &req); - void badRequest(int code, const char *msg); + void handleRequest(Request& req); + void badRequest(int code, const char* msg); ReadResT onRead() override; void onClose() override; - void handleException(Context &ctx, const Error &err); + void handleException(Context& ctx, const Error& err); void parseParams(std::string_view str); void writeHttpResponse(int code); - void setJsonStatus(Context &ctx, bool success, int responseCode, const std::string &status); + void setJsonStatus(Context& ctx, bool success, int responseCode, const std::string& status); - Router &router_; + Router& router_; Request request_; ssize_t bodyLeft_ = 0; bool formData_ = false; diff --git a/cpp_src/net/iserverconnection.h b/cpp_src/net/iserverconnection.h index d51d3b3aa..b005a788c 100644 --- a/cpp_src/net/iserverconnection.h +++ b/cpp_src/net/iserverconnection.h @@ -23,7 +23,7 @@ class IServerConnection { virtual BalancingType GetBalancingType() const noexcept = 0; /// Set callback, which move this connection into separate thread - virtual void SetRebalanceCallback(std::function cb) = 0; + virtual void SetRebalanceCallback(std::function cb) = 0; /// @return true if this connection has pending data virtual bool HasPendingData() const noexcept = 0; @@ -33,10 +33,10 @@ class IServerConnection { /// Restart connection /// @param s - socket of the accepted connection. /// @return true - if successfuly restarted, false - if connection can't be restarted. - virtual bool Restart(socket &&s) = 0; + virtual bool Restart(socket&& s) = 0; /// Attach connection to another listener loop. Must be called from thread of loop /// @param loop - another loop to bind - virtual void Attach(ev::dynamic_loop &loop) = 0; + virtual void Attach(ev::dynamic_loop& loop) = 0; /// Detach connection from listener loop. Must be called from thread of current loop virtual void Detach() = 0; }; @@ -45,7 +45,7 @@ class IServerConnection { /// @param loop - Current loop of Listener's thread. /// @param s - Socket of the accepted connection. /// @param allowCustomBalancing - true, if caller supports custom balancing hints -typedef std::function ConnectionFactory; +typedef std::function ConnectionFactory; } // namespace net } // namespace reindexer diff --git a/cpp_src/net/listener.cc b/cpp_src/net/listener.cc index b574adec5..aa6b3ce6a 100644 --- a/cpp_src/net/listener.cc +++ b/cpp_src/net/listener.cc @@ -16,7 +16,7 @@ static std::atomic_uint_fast64_t counter_; constexpr int kListenCount = 500; template -Listener::Listener(ev::dynamic_loop &loop, std::shared_ptr shared) +Listener::Listener(ev::dynamic_loop& loop, std::shared_ptr shared) : loop_(loop), shared_(std::move(shared)), id_(counter_.fetch_add(1, std::memory_order_relaxed)) { io_.set(this); io_.set(loop); @@ -31,7 +31,7 @@ Listener::Listener(ev::dynamic_loop &loop, std::shared_ptr shared) } template -Listener::Listener(ev::dynamic_loop &loop, ConnectionFactory &&connFactory, int maxListeners) +Listener::Listener(ev::dynamic_loop& loop, ConnectionFactory&& connFactory, int maxListeners) : Listener(loop, std::make_shared(std::move(connFactory), (maxListeners ? maxListeners : std::thread::hardware_concurrency()) + 1)) {} @@ -76,7 +76,7 @@ bool Listener::Bind(std::string addr, socket_domain type) { } template -void Listener::io_accept(ev::io & /*watcher*/, int revents) { +void Listener::io_accept(ev::io& /*watcher*/, int revents) { if (ev::ERROR & revents) { perror("got invalid event"); return; @@ -131,7 +131,7 @@ void Listener::io_accept(ev::io & /*watcher*/, int revents) { auto c = conn.get(); accepted_.emplace(std::move(conn)); c->SetRebalanceCallback( - [this](IServerConnection *c, IServerConnection::BalancingType type) { rebalance_conn(c, type); }); + [this](IServerConnection* c, IServerConnection::BalancingType type) { rebalance_conn(c, type); }); break; } } @@ -149,7 +149,7 @@ void Listener::io_accept(ev::io & /*watcher*/, int revents) { } template -void Listener::timeout_cb(ev::periodic &, int) { +void Listener::timeout_cb(ev::periodic&, int) { const bool enableReuseIdle = !std::getenv("REINDEXER_NOREUSEIDLE"); std::unique_lock lck(shared_->mtx_); @@ -164,7 +164,9 @@ void Listener::timeout_cb(ev::periodic &, int) { connections_[i].reset(); } - if (i != connections_.size() - 1) connections_[i] = std::move(connections_.back()); + if (i != connections_.size() - 1) { + connections_[i] = std::move(connections_.back()); + } connections_.pop_back(); shared_->ts_ = steady_clock_w::now_coarse(); } else { @@ -250,7 +252,7 @@ void Listener::rebalance_from_acceptor() { } template -void Listener::rebalance_conn(IServerConnection *c, IServerConnection::BalancingType type) { +void Listener::rebalance_conn(IServerConnection* c, IServerConnection::BalancingType type) { std::unique_lock lck(shared_->mtx_); auto found = accepted_.find(c); if (found == accepted_.end()) { @@ -273,7 +275,7 @@ void Listener::rebalance_conn(IServerConnection *c, IServerConnection::Balan } template -void Listener::run_dedicated_thread(std::unique_ptr &&conn) { +void Listener::run_dedicated_thread(std::unique_ptr&& conn) { std::thread th([this, conn = std::move(conn)]() mutable { try { #if REINDEX_WITH_GPERFTOOLS @@ -283,7 +285,7 @@ void Listener::run_dedicated_thread(std::unique_ptr &&con #endif ev::dynamic_loop loop; ev::async async; - async.set([](ev::async &a) { a.loop.break_loop(); }); + async.set([](ev::async& a) { a.loop.break_loop(); }); async.set(loop); async.start(); @@ -304,13 +306,13 @@ void Listener::run_dedicated_thread(std::unique_ptr &&con } lck.lock(); const auto it = std::find_if(shared_->dedicatedWorkers_.begin(), shared_->dedicatedWorkers_.end(), - [&pc](const typename Shared::Worker &cw) { return cw.conn.get() == pc; }); + [&pc](const typename Shared::Worker& cw) { return cw.conn.get() == pc; }); assertrx(it != shared_->dedicatedWorkers_.end()); shared_->dedicatedWorkers_.erase(it); logPrintf(LogTrace, "Listener (%s) dedicated thread finished. %d left", shared_->addr_, shared_->dedicatedWorkers_.size()); - } catch (Error &e) { + } catch (Error& e) { logPrintf(LogError, "Unhandled excpetion in listener thread: %s", e.what()); - } catch (std::exception &e) { + } catch (std::exception& e) { logPrintf(LogError, "Unhandled excpetion in listener thread: %s", e.what()); } catch (...) { logPrintf(LogError, "Unhandled excpetion in listener thread"); @@ -333,12 +335,12 @@ void Listener::startup_shared_thread() { } template -void Listener::async_cb(ev::async &watcher) { +void Listener::async_cb(ev::async& watcher) { logPrintf(LogInfo, "Listener(%s) %d async received", shared_->addr_, id_); - h_vector conns; + h_vector conns; { std::lock_guard lck(shared_->mtx_); - for (auto &it : connections_) { + for (auto& it : connections_) { if (!it->IsFinished()) { if constexpr (LT == ListenerType::Mixed) { if (it->HasPendingData()) { @@ -353,7 +355,7 @@ void Listener::async_cb(ev::async &watcher) { } } if constexpr (LT == ListenerType::Mixed) { - for (auto &conn : conns) { + for (auto& conn : conns) { conn->Attach(loop_); conn->HandlePendingData(); } @@ -365,10 +367,10 @@ template void Listener::Stop() { std::unique_lock lck(shared_->mtx_); shared_->terminating_ = true; - for (auto &listener : shared_->listeners_) { + for (auto& listener : shared_->listeners_) { listener->async_.send(); } - for (auto &worker : shared_->dedicatedWorkers_) { + for (auto& worker : shared_->dedicatedWorkers_) { worker.async->send(); } assertrx(this == shared_->listeners_.front()); @@ -382,8 +384,8 @@ void Listener::Stop() { template void Listener::clone(std::unique_ptr d) noexcept { assertrx(d); - auto &shared = d->GetShared(); - const auto &listener = d->GetListener(); + auto& shared = d->GetShared(); + const auto& listener = d->GetListener(); try { #if REINDEX_WITH_GPERFTOOLS @@ -392,9 +394,9 @@ void Listener::clone(std::unique_ptr d) noexcept { } #endif d->Loop(); - } catch (Error &e) { + } catch (Error& e) { logPrintf(LogError, "Unhandled excpetion in listener thread (%s): %s", shared.addr_, e.what()); - } catch (std::exception &e) { + } catch (std::exception& e) { logPrintf(LogError, "Unhandled excpetion in listener thread (%s): %s", shared.addr_, e.what()); } catch (...) { logPrintf(LogError, "Unhandled excpetion in listener thread (%s): ", shared.addr_); @@ -411,11 +413,13 @@ void Listener::clone(std::unique_ptr d) noexcept { template void Listener::reserve_stack() { char placeholder[0x8000]; - for (size_t i = 0; i < sizeof(placeholder); i += 4096) placeholder[i] = i & 0xFF; + for (size_t i = 0; i < sizeof(placeholder); i += 4096) { + placeholder[i] = i & 0xFF; + } } template -Listener::Shared::Shared(ConnectionFactory &&connFactory, int maxListeners) +Listener::Shared::Shared(ConnectionFactory&& connFactory, int maxListeners) : maxListeners_(maxListeners), listenersCount_(1), connFactory_(std::move(connFactory)), terminating_(false) {} template @@ -425,7 +429,7 @@ Listener::Shared::~Shared() { } } -ForkedListener::ForkedListener(ev::dynamic_loop &loop, ConnectionFactory &&connFactory) +ForkedListener::ForkedListener(ev::dynamic_loop& loop, ConnectionFactory&& connFactory) : connFactory_(std::move(connFactory)), loop_(loop) { io_.set(this); io_.set(loop); @@ -464,7 +468,7 @@ bool ForkedListener::Bind(std::string addr, socket_domain type) { return true; } -void ForkedListener::io_accept(ev::io & /*watcher*/, int revents) { +void ForkedListener::io_accept(ev::io& /*watcher*/, int revents) { if (ev::ERROR & revents) { perror("got invalid event"); return; @@ -494,7 +498,7 @@ void ForkedListener::io_accept(ev::io & /*watcher*/, int revents) { #endif ev::dynamic_loop loop; ev::async async; - async.set([](ev::async &a) { a.loop.break_loop(); }); + async.set([](ev::async& a) { a.loop.break_loop(); }); async.set(loop); async.start(); @@ -515,14 +519,14 @@ void ForkedListener::io_accept(ev::io & /*watcher*/, int revents) { } } lck.lock(); - const auto it = std::find_if(workers_.begin(), workers_.end(), [&pc](const Worker &cw) { return cw.conn.get() == pc; }); + const auto it = std::find_if(workers_.begin(), workers_.end(), [&pc](const Worker& cw) { return cw.conn.get() == pc; }); assertrx(it != workers_.end()); workers_.erase(it); logPrintf(LogTrace, "Listener (%s) dedicated thread finished. %d left", addr_, workers_.size()); } - } catch (Error &e) { + } catch (Error& e) { logPrintf(LogError, "Unhandled excpetion in listener thread: %s", e.what()); - } catch (std::exception &e) { + } catch (std::exception& e) { logPrintf(LogError, "Unhandled excpetion in listener thread: %s", e.what()); } catch (...) { logPrintf(LogError, "Unhandled excpetion in listener thread"); @@ -532,7 +536,7 @@ void ForkedListener::io_accept(ev::io & /*watcher*/, int revents) { th.detach(); } -void ForkedListener::async_cb(ev::async &watcher) { +void ForkedListener::async_cb(ev::async& watcher) { logPrintf(LogInfo, "Listener(%s) async received", addr_); watcher.loop.break_loop(); } @@ -541,7 +545,7 @@ void ForkedListener::Stop() { terminating_ = true; async_.send(); std::unique_lock lck(mtx_); - for (auto &worker : workers_) { + for (auto& worker : workers_) { worker.async->send(); } while (runningThreadsCount_ || !workers_.empty()) { diff --git a/cpp_src/net/listener.h b/cpp_src/net/listener.h index 06453907e..ce51a8f28 100644 --- a/cpp_src/net/listener.h +++ b/cpp_src/net/listener.h @@ -28,9 +28,9 @@ class IListener { struct ConnPtrEqual { using is_transparent = void; - bool operator()(const IServerConnection *lhs, const std::unique_ptr &rhs) const noexcept { return lhs == rhs.get(); } - bool operator()(const std::unique_ptr &lhs, const IServerConnection *rhs) const noexcept { return lhs.get() == rhs; } - bool operator()(const std::unique_ptr &lhs, const std::unique_ptr &rhs) const noexcept { + bool operator()(const IServerConnection* lhs, const std::unique_ptr& rhs) const noexcept { return lhs == rhs.get(); } + bool operator()(const std::unique_ptr& lhs, const IServerConnection* rhs) const noexcept { return lhs.get() == rhs; } + bool operator()(const std::unique_ptr& lhs, const std::unique_ptr& rhs) const noexcept { return lhs == rhs; } }; @@ -38,8 +38,8 @@ struct ConnPtrEqual { struct ConnPtrHash { using transparent_key_equal = ConnPtrEqual; - size_t operator()(const IServerConnection *ptr) const noexcept { return std::hash()(uintptr_t(ptr)); } - size_t operator()(const std::unique_ptr &ptr) const noexcept { return std::hash()(uintptr_t(ptr.get())); } + size_t operator()(const IServerConnection* ptr) const noexcept { return std::hash()(uintptr_t(ptr)); } + size_t operator()(const std::unique_ptr& ptr) const noexcept { return std::hash()(uintptr_t(ptr.get())); } }; enum class ListenerType { @@ -65,7 +65,7 @@ class Listener final : public IListener { /// @param loop - ev::loop of caller's thread, listener's socket will be binded to that loop. /// @param connFactory - Connection factory, will create objects with IServerConnection interface implementation. /// @param maxListeners - Maximum number of threads, which listener will utilize. std::thread::hardware_concurrency() by default - Listener(ev::dynamic_loop &loop, ConnectionFactory &&connFactory, int maxListeners = 0); + Listener(ev::dynamic_loop& loop, ConnectionFactory&& connFactory, int maxListeners = 0); ~Listener() override; /// Bind listener to specified host:port /// @param addr - tcp host:port for bind or file path for the unix domain socket @@ -77,22 +77,22 @@ class Listener final : public IListener { protected: void reserve_stack(); - void io_accept(ev::io &watcher, int revents); - void timeout_cb(ev::periodic &watcher, int); - void async_cb(ev::async &watcher); + void io_accept(ev::io& watcher, int revents); + void timeout_cb(ev::periodic& watcher, int); + void async_cb(ev::async& watcher); void rebalance(); void rebalance_from_acceptor(); // Locks shared_->mtx_. Should not be calles under external lock. - void rebalance_conn(IServerConnection *, IServerConnection::BalancingType type); - void run_dedicated_thread(std::unique_ptr &&conn); + void rebalance_conn(IServerConnection*, IServerConnection::BalancingType type); + void run_dedicated_thread(std::unique_ptr&& conn); // May lock shared_->mtx_. Should not be calles under external lock. void startup_shared_thread(); struct Shared { struct Worker { - Worker(std::unique_ptr &&_conn, ev::async &_async) : conn(std::move(_conn)), async(&_async) {} - Worker(Worker &&other) noexcept : conn(std::move(other.conn)), async(other.async) {} - Worker &operator=(Worker &&other) noexcept { + Worker(std::unique_ptr&& _conn, ev::async& _async) : conn(std::move(_conn)), async(&_async) {} + Worker(Worker&& other) noexcept : conn(std::move(other.conn)), async(other.async) {} + Worker& operator=(Worker&& other) noexcept { if (&other != this) { conn = std::move(other.conn); async = other.async; @@ -101,16 +101,16 @@ class Listener final : public IListener { } std::unique_ptr conn; - ev::async *async; + ev::async* async; }; - Shared(ConnectionFactory &&connFactory, int maxListeners); + Shared(ConnectionFactory&& connFactory, int maxListeners); ~Shared(); lst_socket sock_; const int maxListeners_; std::atomic listenersCount_ = {0}; std::atomic connCount_ = {0}; - std::vector listeners_; + std::vector listeners_; std::mutex mtx_; ConnectionFactory connFactory_; std::atomic terminating_; @@ -131,8 +131,8 @@ class Listener final : public IListener { loop_.run(); } } - const Listener &GetListener() const noexcept { return listener_; } - Shared &GetShared() noexcept { return *shared_; } + const Listener& GetListener() const noexcept { return listener_; } + Shared& GetShared() noexcept { return *shared_; } private: ev::dynamic_loop loop_; @@ -140,12 +140,12 @@ class Listener final : public IListener { std::shared_ptr shared_; }; // Locks shared_->mtx_. Should not be calles under external lock. - Listener(ev::dynamic_loop &loop, std::shared_ptr shared); + Listener(ev::dynamic_loop& loop, std::shared_ptr shared); static void clone(std::unique_ptr d) noexcept; ev::io io_; ev::periodic timer_; - ev::dynamic_loop &loop_; + ev::dynamic_loop& loop_; ev::async async_; std::shared_ptr shared_; std::vector> connections_; @@ -159,7 +159,7 @@ class ForkedListener final : public IListener { /// Constructs new listner object. /// @param loop - ev::loop of caller's thread, listener's socket will be binded to that loop. /// @param connFactory - Connection factory, will create objects with IServerConnection interface implementation. - ForkedListener(ev::dynamic_loop &loop, ConnectionFactory &&connFactory); + ForkedListener(ev::dynamic_loop& loop, ConnectionFactory&& connFactory); ~ForkedListener() override; /// Bind listener to specified host:port /// @param addr - tcp host:port for bind or file path for the unix domain socket @@ -170,13 +170,13 @@ class ForkedListener final : public IListener { void Stop() override; protected: - void io_accept(ev::io &watcher, int revents); - void async_cb(ev::async &watcher); + void io_accept(ev::io& watcher, int revents); + void async_cb(ev::async& watcher); struct Worker { - Worker(std::unique_ptr &&conn, ev::async &async) : conn(std::move(conn)), async(&async) {} - Worker(Worker &&other) noexcept : conn(std::move(other.conn)), async(other.async) {} - Worker &operator=(Worker &&other) noexcept { + Worker(std::unique_ptr&& conn, ev::async& async) : conn(std::move(conn)), async(&async) {} + Worker(Worker&& other) noexcept : conn(std::move(other.conn)), async(other.async) {} + Worker& operator=(Worker&& other) noexcept { if (&other != this) { conn = std::move(other.conn); async = other.async; @@ -185,7 +185,7 @@ class ForkedListener final : public IListener { } std::unique_ptr conn; - ev::async *async; + ev::async* async; }; lst_socket sock_; @@ -195,7 +195,7 @@ class ForkedListener final : public IListener { std::string addr_; ev::io io_; - ev::dynamic_loop &loop_; + ev::dynamic_loop& loop_; ev::async async_; std::vector workers_; std::atomic runningThreadsCount_ = {0}; diff --git a/cpp_src/net/manualconnection.cc b/cpp_src/net/manualconnection.cc index bf0cc3fb1..d8f218eb4 100644 --- a/cpp_src/net/manualconnection.cc +++ b/cpp_src/net/manualconnection.cc @@ -7,14 +7,18 @@ namespace net { manual_connection::manual_connection(size_t rd_buf_size, bool enable_stat) : buffered_data_(rd_buf_size), stats_(enable_stat ? new connection_stats_collector : nullptr) {} -void manual_connection::attach(ev::dynamic_loop &loop) noexcept { +void manual_connection::attach(ev::dynamic_loop& loop) noexcept { assertrx(!attached_); io_.set(this); io_.set(loop); connect_timer_.set(this); connect_timer_.set(loop); - if (stats_) stats_->attach(loop); - if (cur_events_) io_.start(sock_.fd(), cur_events_); + if (stats_) { + stats_->attach(loop); + } + if (cur_events_) { + io_.start(sock_.fd(), cur_events_); + } attached_ = true; } @@ -24,7 +28,9 @@ void manual_connection::detach() noexcept { io_.reset(); connect_timer_.stop(); connect_timer_.reset(); - if (stats_) stats_->detach(); + if (stats_) { + stats_->detach(); + } attached_ = false; } @@ -51,13 +57,17 @@ void manual_connection::close_conn(int err) { if (hadWData) { on_async_op_done(w_data_, err); } - if (stats_) stats_->stop(); + if (stats_) { + stats_->stop(); + } } -void manual_connection::restart(socket &&s) { +void manual_connection::restart(socket&& s) { assertrx(!sock_.valid()); sock_ = std::move(s); - if (stats_) stats_->restart(); + if (stats_) { + stats_->restart(); + } } int manual_connection::async_connect(std::string_view addr, socket_domain type) noexcept { @@ -83,7 +93,7 @@ int manual_connection::async_connect(std::string_view addr, socket_domain type) return 0; } -ssize_t manual_connection::write(span wr_buf, transfer_data &transfer, int &err_ref) { +ssize_t manual_connection::write(span wr_buf, transfer_data& transfer, int& err_ref) { err_ref = 0; ssize_t written = -1; auto cur_buf = wr_buf.subspan(transfer.transfered_size()); @@ -109,7 +119,9 @@ ssize_t manual_connection::write(span wr_buf, transfer_data &transfer, int assertrx(wr_buf.size() >= transfer.transfered_size()); auto remaining = wr_buf.size() - transfer.transfered_size(); - if (stats_) stats_->update_write_stats(written, remaining); + if (stats_) { + stats_->update_write_stats(written, remaining); + } if (remaining == 0) { on_async_op_done(w_data_, 0); @@ -117,7 +129,7 @@ ssize_t manual_connection::write(span wr_buf, transfer_data &transfer, int return written; } -ssize_t manual_connection::read(span rd_buf, transfer_data &transfer, int &err_ref) { +ssize_t manual_connection::read(span rd_buf, transfer_data& transfer, int& err_ref) { bool need_read = !transfer.expected_size(); ssize_t nread = 0; ssize_t read_this_time = 0; @@ -133,10 +145,14 @@ ssize_t manual_connection::read(span rd_buf, transfer_data &transfer, int nread = sock_.recv(it); int err = sock_.last_error(); - if (nread < 0 && err == EINTR) continue; + if (nread < 0 && err == EINTR) { + continue; + } if ((nread < 0 && !socket::would_block(err)) || nread == 0) { - if (nread == 0) err = k_sock_closed_err; + if (nread == 0) { + err = k_sock_closed_err; + } err_ref = err; close_conn(err); return -1; @@ -144,7 +160,9 @@ ssize_t manual_connection::read(span rd_buf, transfer_data &transfer, int need_read = false; read_this_time += nread; buffered_data_.advance_head(nread); - if (stats_) stats_->update_read_stats(nread); + if (stats_) { + stats_->update_read_stats(nread); + } if (read_from_buf(rd_buf, transfer, true)) { on_async_op_done(r_data_, 0); return remain_to_transfer; @@ -158,20 +176,26 @@ ssize_t manual_connection::read(span rd_buf, transfer_data &transfer, int return read_this_time; } -void manual_connection::read_to_buf(int &err_ref) { +void manual_connection::read_to_buf(int& err_ref) { auto it = buffered_data_.head(); ssize_t nread = sock_.recv(it); int err = sock_.last_error(); - if (nread < 0 && err == EINTR) return; + if (nread < 0 && err == EINTR) { + return; + } if ((nread < 0 && !socket::would_block(err)) || nread == 0) { - if (nread == 0) err = k_sock_closed_err; + if (nread == 0) { + err = k_sock_closed_err; + } err_ref = err; close_conn(err); } else if (nread > 0) { buffered_data_.advance_head(nread); - if (stats_) stats_->update_read_stats(nread); + if (stats_) { + stats_->update_read_stats(nread); + } } else { err_ref = err; } @@ -200,8 +224,10 @@ void manual_connection::set_io_events(int events) noexcept { } } -void manual_connection::io_callback(ev::io &, int revents) { - if (ev::ERROR & revents) return; +void manual_connection::io_callback(ev::io&, int revents) { + if (ev::ERROR & revents) { + return; + } const auto conn_id = conn_id_; if (revents & ev::READ) { @@ -219,12 +245,14 @@ void manual_connection::io_callback(ev::io &, int revents) { if (sock_.valid()) { int nevents = (r_data_.buf.size() || buffered_data_.available()) ? ev::READ : 0; - if (hadWData || w_data_.buf.size()) nevents |= ev::WRITE; + if (hadWData || w_data_.buf.size()) { + nevents |= ev::WRITE; + } set_io_events(nevents); } } -void manual_connection::connect_timer_cb(ev::timer &, int) { close_conn(k_connect_timeout_err); } +void manual_connection::connect_timer_cb(ev::timer&, int) { close_conn(k_connect_timeout_err); } void manual_connection::write_cb() { if (state_ == conn_state::connecting && sock_.valid()) { @@ -248,7 +276,7 @@ int manual_connection::read_cb() { return err; } -bool manual_connection::read_from_buf(span rd_buf, transfer_data &transfer, bool read_full) noexcept { +bool manual_connection::read_from_buf(span rd_buf, transfer_data& transfer, bool read_full) noexcept { auto cur_buf = rd_buf.subspan(transfer.transfered_size()); const bool will_read_full = read_full && buffered_data_.size() >= cur_buf.size(); const bool will_read_any = !read_full && buffered_data_.size(); diff --git a/cpp_src/net/manualconnection.h b/cpp_src/net/manualconnection.h index aaaba8ce0..5d3415821 100644 --- a/cpp_src/net/manualconnection.h +++ b/cpp_src/net/manualconnection.h @@ -27,16 +27,16 @@ class manual_connection { void set_connect_timeout(std::chrono::milliseconds timeout) noexcept { connect_timeout_ = timeout; } void close_conn(int err); - void attach(ev::dynamic_loop &loop) noexcept; + void attach(ev::dynamic_loop& loop) noexcept; void detach() noexcept; - void restart(socket &&s); + void restart(socket&& s); template - void async_read(buf_t &data, size_t cnt, async_cb_t cb) { + void async_read(buf_t& data, size_t cnt, async_cb_t cb) { async_read_impl(data, cnt, std::move(cb)); } template - size_t async_read(buf_t &data, size_t cnt, int &err) noexcept { + size_t async_read(buf_t& data, size_t cnt, int& err) noexcept { auto co_id = coroutine::current(); auto l = [&err, co_id](int _err, size_t /*cnt*/, span /*buf*/) { err = _err; @@ -45,11 +45,11 @@ class manual_connection { return async_read_impl(data, cnt, std::move(l)); } template - void async_write(buf_t &data, async_cb_t cb, bool send_now = true) { + void async_write(buf_t& data, async_cb_t cb, bool send_now = true) { async_write_impl(data, std::move(cb), send_now); } template - size_t async_write(buf_t &data, int &err, bool send_now = true) noexcept { + size_t async_write(buf_t& data, int& err, bool send_now = true) noexcept { auto co_id = coroutine::current(); auto l = [&err, co_id](int _err, size_t /*cnt*/, span /*buf*/) { err = _err; @@ -95,10 +95,10 @@ class manual_connection { }; struct empty_switch_policy { - void operator()(async_data & /*data*/) {} + void operator()(async_data& /*data*/) {} }; struct suspend_switch_policy { - void operator()(async_data &data) { + void operator()(async_data& data) { while (!data.empty()) { coroutine::suspend(); } @@ -106,10 +106,10 @@ class manual_connection { }; template - size_t async_read_impl(buf_t &data, size_t cnt, cb_t cb) { + size_t async_read_impl(buf_t& data, size_t cnt, cb_t cb) { assertrx(r_data_.empty()); assertrx(data.size() >= cnt); - auto &transfer = r_data_.transfer; + auto& transfer = r_data_.transfer; transfer.set_expected(cnt); int int_err = 0; auto data_span = span(data.data(), cnt); @@ -132,9 +132,20 @@ class manual_connection { } template - size_t async_write_impl(buf_t &data, cb_t cb, bool send_now) { + size_t async_write_impl(buf_t& data, cb_t cb, bool send_now) { +#if _WIN32 + /* + On Windows FD_WRITE network event is recorded when a socket is first connected with a call to the connect, + ConnectEx, WSAConnect, WSAConnectByList, or WSAConnectByName function or when a socket is accepted with accept, AcceptEx, + or WSAAccept function and then after a send fails with WSAEWOULDBLOCK and buffer space becomes available. + + https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaeventselect + */ + + send_now = true; +#endif assertrx(w_data_.empty()); - auto &transfer = w_data_.transfer; + auto& transfer = w_data_.transfer; transfer.set_expected(data.size()); int int_err = 0; if (data.size()) { @@ -156,7 +167,7 @@ class manual_connection { return transfer.transfered_size(); } - void on_async_op_done(async_data &data, int err) { + void on_async_op_done(async_data& data, int err) { if (!data.empty()) { auto cb = std::move(data.cb); auto buf = data.buf; @@ -165,16 +176,16 @@ class manual_connection { cb(err, transfered, buf); } } - ssize_t write(span, transfer_data &transfer, int &err_ref); - ssize_t read(span, transfer_data &transfer, int &err_ref); - void read_to_buf(int &err_ref); + ssize_t write(span, transfer_data& transfer, int& err_ref); + ssize_t read(span, transfer_data& transfer, int& err_ref); + void read_to_buf(int& err_ref); void add_io_events(int events) noexcept; void set_io_events(int events) noexcept; - void io_callback(ev::io &watcher, int revents); - void connect_timer_cb(ev::timer &watcher, int); + void io_callback(ev::io& watcher, int revents); + void connect_timer_cb(ev::timer& watcher, int); void write_cb(); int read_cb(); - bool read_from_buf(span rd_buf, transfer_data &transfer, bool read_full) noexcept; + bool read_from_buf(span rd_buf, transfer_data& transfer, bool read_full) noexcept; ev::io io_; socket sock_; diff --git a/cpp_src/net/socket.cc b/cpp_src/net/socket.cc index a943b0428..60b47d173 100644 --- a/cpp_src/net/socket.cc +++ b/cpp_src/net/socket.cc @@ -21,7 +21,7 @@ int socket::connect(std::string_view addr, socket_domain t) { int ret = 0; type_ = t; if (domain() == socket_domain::tcp) { - struct addrinfo *results = nullptr; + struct addrinfo* results = nullptr; ret = create(addr, &results); if rx_likely (!ret) { assertrx(results != nullptr); @@ -49,7 +49,7 @@ int socket::connect(std::string_view addr, socket_domain t) { memcpy(address.sun_path, addr.data(), addr.size()); address.sun_path[addr.size()] = 0; - if rx_unlikely (::connect(fd_, reinterpret_cast(&address), sizeof(address)) != 0) { // -V595 + if rx_unlikely (::connect(fd_, reinterpret_cast(&address), sizeof(address)) != 0) { // -V595 if rx_unlikely (!would_block(last_error())) { perror("connect error"); close(); @@ -77,7 +77,7 @@ ssize_t socket::send(span chunks) { iov.resize(chunks.size()); for (unsigned i = 0; i < chunks.size(); i++) { - iov[i].buf = reinterpret_cast(chunks[i].data()); + iov[i].buf = reinterpret_cast(chunks[i].data()); iov[i].len = chunks[i].size(); } DWORD numberOfBytesSent; @@ -103,12 +103,12 @@ int socket::setLinger0() { struct linger sl; sl.l_onoff = 1; /* enable linger */ sl.l_linger = 0; /* with 0 seconds timeout */ - return setsockopt(fd(), SOL_SOCKET, SO_LINGER, reinterpret_cast(&sl), sizeof(sl)); + return setsockopt(fd(), SOL_SOCKET, SO_LINGER, reinterpret_cast(&sl), sizeof(sl)); } return -1; } -int socket::create(std::string_view addr, struct addrinfo **presults) { +int socket::create(std::string_view addr, struct addrinfo** presults) { assertrx(!valid()); if (domain() == socket_domain::tcp) { @@ -121,15 +121,17 @@ int socket::create(std::string_view addr, struct addrinfo **presults) { *presults = nullptr; std::string saddr(addr); - char *paddr = &saddr[0]; + char* paddr = &saddr[0]; - char *pport = strchr(paddr, ':'); + char* pport = strchr(paddr, ':'); if (pport == nullptr) { pport = paddr; paddr = nullptr; } else { *pport = 0; - if (*paddr == 0) paddr = nullptr; + if (*paddr == 0) { + paddr = nullptr; + } pport++; } @@ -147,7 +149,7 @@ int socket::create(std::string_view addr, struct addrinfo **presults) { } int enable = 1; - if rx_unlikely (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(enable)) < 0) { + if rx_unlikely (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(enable)) < 0) { perror("setsockopt(SO_REUSEADDR) failed"); } } else { @@ -178,11 +180,11 @@ int socket::create(std::string_view addr, struct addrinfo **presults) { std::string socket::addr() const { if (domain() == socket_domain::tcp) { struct sockaddr_storage saddr; - struct sockaddr *paddr = reinterpret_cast(&saddr); + struct sockaddr* paddr = reinterpret_cast(&saddr); socklen_t len = sizeof(saddr); if rx_likely (::getpeername(fd_, paddr, &len) == 0) { char buf[INET_ADDRSTRLEN] = {}; - auto port = ntohs(reinterpret_cast(paddr)->sin_port); + auto port = ntohs(reinterpret_cast(paddr)->sin_port); if rx_likely (getnameinfo(paddr, len, buf, INET_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST) == 0) { return std::string(buf) + ':' + std::to_string(port); } else { @@ -209,7 +211,7 @@ int socket::set_nonblock() { int socket::set_nodelay() noexcept { if (domain() == socket_domain::tcp) { int flag = 1; - return setsockopt(fd_, SOL_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)); + return setsockopt(fd_, SOL_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)); } else { return 0; } @@ -269,7 +271,7 @@ int lst_socket::bind(std::string_view addr, socket_domain t) { int ret = 0; sock_.domain(t); if (domain() == socket_domain::tcp) { - struct addrinfo *results = nullptr; + struct addrinfo* results = nullptr; ret = sock_.create(addr, &results); if rx_unlikely (!ret) { assertrx(results != nullptr); @@ -321,7 +323,7 @@ int lst_socket::bind(std::string_view addr, socket_domain t) { } unlink(unPath_.c_str()); - if rx_unlikely (::bind(sock_.fd(), reinterpret_cast(&address), sizeof(address)) < 0) { + if rx_unlikely (::bind(sock_.fd(), reinterpret_cast(&address), sizeof(address)) < 0) { perror("bind() error"); close(); return -1; diff --git a/cpp_src/net/socket.h b/cpp_src/net/socket.h index bba398989..92b5b64c5 100644 --- a/cpp_src/net/socket.h +++ b/cpp_src/net/socket.h @@ -17,10 +17,10 @@ class lst_socket; class socket { public: socket() = default; - socket(const socket &&other) = delete; - socket(socket &&other) noexcept : fd_(other.fd_), type_(other.type_) { other.fd_ = -1; } - socket &operator=(const socket &other) = delete; - socket &operator=(socket &&other) noexcept { + socket(const socket&& other) = delete; + socket(socket&& other) noexcept : fd_(other.fd_), type_(other.type_) { other.fd_ = -1; } + socket& operator=(const socket& other) = delete; + socket& operator=(socket&& other) noexcept { if rx_likely (this != &other) { if (valid()) { close(); @@ -59,7 +59,7 @@ class socket { friend class lst_socket; socket(int fd, socket_domain type) noexcept : fd_(fd), type_(type) {} - int create(std::string_view addr, struct addrinfo **pres); + int create(std::string_view addr, struct addrinfo** pres); void domain(socket_domain t) noexcept { type_ = t; } int fd_ = -1; @@ -69,13 +69,13 @@ class socket { class lst_socket { public: lst_socket() = default; - lst_socket(const lst_socket &&other) = delete; - lst_socket(lst_socket &&other) noexcept + lst_socket(const lst_socket&& other) = delete; + lst_socket(lst_socket&& other) noexcept : sock_(std::move(other.sock_)), lockFd_(other.lockFd_), unPath_(std::move(other.unPath_)), unLock_(std::move(other.unLock_)) { other.lockFd_ = -1; } - lst_socket &operator=(const lst_socket &other) = delete; - lst_socket &operator=(lst_socket &&other) noexcept { + lst_socket& operator=(const lst_socket& other) = delete; + lst_socket& operator=(lst_socket&& other) noexcept { if rx_likely (this != &other) { if (valid()) { close(); diff --git a/cpp_src/readme.md b/cpp_src/readme.md index cd760167e..acb9d4a5a 100644 --- a/cpp_src/readme.md +++ b/cpp_src/readme.md @@ -35,6 +35,16 @@ While using docker, you may pass reindexer server config options via envinronmen - `RX_DISABLE_NS_LEAK` - Disables namespaces memory leak on database destruction (will slow down server's termination). - `RX_MAX_HTTP_REQ` - allows to configure max HTTP request size (in bytes). Default value is `2097152` (= 2 MB). `0` means 'unlimited'. +### Image build + +Usually this is not required, but you may also build reindexer's docker image on your own, using this [Dockerfile](#cmd/reindexer_server/contrib/Dockerfile): + +```bash +docker build -t my-reindexer-image -f cpp_src/cmd/reindexer_server/contrib/Dockerfile . +``` + +Build command above must be executed from root project's directory. + ## Linux ### RHEL/Centos/Fedora @@ -298,6 +308,11 @@ If reindexer library was built with rocksdb, it requires Go build tag `rocksdb` Reindexer supports the following data formats to communicate with other applications (mainly via HTTP REST API): JSON, MSGPACK and Protobuf. +## Log rotation + +There are no builtin mechanis for automatic log rotation, however `reindexer server` is able to reopen logfiles on `SIGHUP`. +So, your external log manager (it may be even a simple `cron` script) have to move existing log files somewhere and then send `SIGHUP`-signal to the `reindexer server` process to recreate log files. + #### Protobuf Protocol buffers are language-neutral, platform-neutral, extensible mechanism for serializing structured data. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages (https://developers.google.com/protocol-buffers). diff --git a/cpp_src/replicator/replicator.cc b/cpp_src/replicator/replicator.cc index 7a3e79c53..45a03376c 100644 --- a/cpp_src/replicator/replicator.cc +++ b/cpp_src/replicator/replicator.cc @@ -1,6 +1,7 @@ #include "replicator.h" #include "client/itemimpl.h" #include "client/reindexer.h" +#include "core/formatters/lsn_fmt.h" #include "core/namespace/namespaceimpl.h" #include "core/reindexer_impl/reindexerimpl.h" #include "tools/logger.h" @@ -10,7 +11,7 @@ namespace reindexer { using namespace net; using namespace std::string_view_literals; -Replicator::Replicator(ReindexerImpl *slave) +Replicator::Replicator(ReindexerImpl* slave) : slave_(slave), resyncUpdatesLostFlag_(false), terminate_(false), @@ -33,14 +34,18 @@ Error Replicator::Start() { return Error(errLogic, "Replicator is already started"); } - if (!(config_.role == ReplicationSlave)) return errOK; + if (!(config_.role == ReplicationSlave)) { + return errOK; + } master_.reset(new client::Reindexer( client::ReindexerConfig(config_.connPoolSize, config_.workerThreads, 10000, 0, std::chrono::seconds(config_.timeoutSec), std::chrono::seconds(config_.timeoutSec), config_.enableCompression, false, config_.appName))); auto err = master_->Connect(config_.masterDSN, client::ConnectOpts().WithExpectedClusterID(config_.clusterID)); - if (err.ok()) err = master_->Status(); + if (err.ok()) { + err = master_->Status(); + } if (err.code() == errOK || err.code() == errNetwork) { err = errOK; terminate_ = false; @@ -58,7 +63,7 @@ Error Replicator::Start() { return err; } -bool Replicator::Configure(const ReplicationConfigData &config) { +bool Replicator::Configure(const ReplicationConfigData& config) { if (!enabled_.load(std::memory_order_acquire)) { return false; } @@ -66,7 +71,9 @@ bool Replicator::Configure(const ReplicationConfigData &config) { bool changed = (config_ != config); if (changed) { - if (master_) stop(); + if (master_) { + stop(); + } config_ = config; } @@ -94,7 +101,7 @@ void Replicator::stop() { } void Replicator::run() { - stop_.set([&](ev::async &sig) { sig.loop.break_loop(); }); + stop_.set([&](ev::async& sig) { sig.loop.break_loop(); }); stop_.start(); logPrintf(LogInfo, "[repl] Replicator with %s started", config_.masterDSN); @@ -117,16 +124,16 @@ void Replicator::run() { state_.store(StateInit, std::memory_order_release); } - resync_.set([this](ev::async &) { + resync_.set([this](ev::async&) { auto err = syncDatabase("Resync"); (void)err; // ignore }); resync_.start(); - resyncTimer_.set([this](ev::timer &, int) { + resyncTimer_.set([this](ev::timer&, int) { auto err = syncDatabase("Reconnect"); (void)err; // ignore }); - walSyncAsync_.set([this](ev::async &) { + walSyncAsync_.set([this](ev::async&) { // check status of namespace NamespaceDef nsDef; bool forced; @@ -145,7 +152,7 @@ void Replicator::run() { } }); walSyncAsync_.start(); - resyncUpdatesLostAsync_.set([this](ev::async &) { + resyncUpdatesLostAsync_.set([this](ev::async&) { auto err = syncDatabase("UpdateLost"); (void)err; // ignore }); @@ -169,7 +176,7 @@ void Replicator::run() { logPrintf(LogInfo, "[repl] Replicator with %s stopped", config_.masterDSN); } -static bool errorIsFatal(const Error &err) { +static bool errorIsFatal(const Error& err) { switch (err.code()) { case errOK: case errNetwork: @@ -216,8 +223,10 @@ static bool errorIsFatal(const Error &err) { } } -bool Replicator::retryIfNetworkError(const Error &err) { - if (err.ok()) return false; +bool Replicator::retryIfNetworkError(const Error& err) { + if (err.ok()) { + return false; + } if (!errorIsFatal(err)) { state_.store(StateInit, std::memory_order_release); resyncTimer_.start(config_.retrySyncIntervalSec); @@ -227,7 +236,7 @@ bool Replicator::retryIfNetworkError(const Error &err) { return false; } -void Replicator::subscribeUpdatesIfRequired(const std::string &nsName) { +void Replicator::subscribeUpdatesIfRequired(const std::string& nsName) { if (config_.namespaces.find(nsName) != config_.namespaces.end()) { UpdatesFilters filters; filters.AddFilter(nsName, UpdatesFilters::Filter()); @@ -238,15 +247,15 @@ void Replicator::subscribeUpdatesIfRequired(const std::string &nsName) { } } -static bool shouldUpdateLsn(const WALRecord &wrec) { +static bool shouldUpdateLsn(const WALRecord& wrec) { return wrec.type != WalNamespaceDrop && (!wrec.inTransaction || wrec.type == WalCommitTransaction); } -Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef &ns, std::string_view forceSyncReason, SyncQueue *sourceQueue, +Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef& ns, std::string_view forceSyncReason, SyncQueue* sourceQueue, std::string_view initiator) { Error err = errOK; logPrintf(LogInfo, "[repl:%s:%s] ===Starting WAL synchronization. (initiated by %s)====", ns.name, slave_->storagePath_, initiator); - auto onPendedUpdatesApplied = [this, sourceQueue](std::string_view nsName, const std::unique_lock &lck) noexcept { + auto onPendedUpdatesApplied = [this, sourceQueue](std::string_view nsName, const std::unique_lock& lck) noexcept { pendedUpdates_.erase(nsName); if (sourceQueue) { sourceQueue->Pop(nsName, lck); @@ -283,9 +292,9 @@ Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef &ns, std:: logPrintf(LogTrace, "[repl:%s:%s]: %d new updates", ns.name, slave_->storagePath_, walUpdates.size()); if (walUpdates.empty()) { onPendedUpdatesApplied(ns.name, lck); - if (replState.replicatorEnabled) + if (replState.replicatorEnabled) { slaveNs->SetSlaveReplStatus(ReplicationState::Status::Idle, errOK, dummyCtx_); - else { + } else { logPrintf( LogError, "[repl:%s:%s]:%d Sync namespace logical error. Set status Idle. Replication not allowed for namespace.", @@ -298,13 +307,13 @@ Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef &ns, std:: lck.unlock(); WrSerializer ser; stat.Dump(ser) << "lsn #" << int64_t(lastLsn.upstreamLSN_); - logPrintf(!stat.lastError.ok() ? LogError : LogInfo, "[repl:%s:%s]:%d Updates applying done: %s", ns.name, + logPrintf((!stat.lastError.ok() ? LogError : LogInfo), "[repl:%s:%s]:%d Updates applying done: %s", ns.name, slave_->storagePath_, config_.serverId, ser.Slice()); break; } } try { - for (auto &rec : walUpdates) { + for (auto& rec : walUpdates) { bool forceApply = lastLsn.upstreamLSN_.isEmpty() ? replState.lastUpstreamLSN.isEmpty() || rec.first.upstreamLSN_.Counter() > replState.lastUpstreamLSN.Counter() @@ -328,7 +337,7 @@ Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef &ns, std:: config_.serverId, rec.first.upstreamLSN_.Counter(), lastLsn.upstreamLSN_.Counter()); } } - } catch (const Error &e) { + } catch (const Error& e) { err = e; } walUpdates.clear(); @@ -353,7 +362,7 @@ Replicator::SyncNsResult Replicator::syncNamespace(const NamespaceDef &ns, std:: Error Replicator::syncDatabase(std::string_view initiator) { std::vector nses; logPrintf(LogInfo, "[repl:%s]:%d Starting sync from '%s' state=%d, initiated by %s", slave_->storagePath_, config_.serverId, - config_.masterDSN, state_.load(), initiator); + config_.masterDSN, int(state_.load()), initiator); { std::lock_guard lck(syncMtx_); @@ -401,14 +410,20 @@ Error Replicator::syncDatabase(std::string_view initiator) { resyncTimer_.stop(); // Loop for all master namespaces - for (auto &ns : nses) { + for (auto& ns : nses) { logPrintf(LogTrace, "[repl:%s:%s]:%d Loop for all master namespaces state=%d", ns.name, slave_->storagePath_, config_.serverId, - state_.load()); + int(state_.load())); // skip system & non enabled namespaces - if (!isSyncEnabled(ns.name)) continue; + if (!isSyncEnabled(ns.name)) { + continue; + } // skip temporary namespaces (namespace from upstream slave node) - if (ns.isTemporary) continue; - if (terminate_) break; + if (ns.isTemporary) { + continue; + } + if (terminate_) { + break; + } subscribeUpdatesIfRequired(ns.name); @@ -422,9 +437,9 @@ Error Replicator::syncDatabase(std::string_view initiator) { auto slaveNs = slave_->getNamespaceNoThrow(ns.name, dummyCtx_); if (err.ok() && slaveNs) { replState = slaveNs->GetReplState(dummyCtx_); - if (replState.replicatorEnabled) + if (replState.replicatorEnabled) { slaveNs->SetSlaveReplStatus(ReplicationState::Status::Syncing, errOK, dummyCtx_); - else { + } else { logPrintf(LogError, "[repl:%s:%s]:%d Sync namespace logical error. Set status Syncing. Replication not allowed for namespace.", ns.name, slave_->storagePath_, config_.serverId); @@ -454,16 +469,19 @@ Error Replicator::syncDatabase(std::string_view initiator) { slaveNs = slave_->getNamespaceNoThrow(ns.name, dummyCtx_); if (slaveNs) { replState = slaveNs->GetReplState(dummyCtx_); - if (replState.replicatorEnabled) + if (replState.replicatorEnabled) { slaveNs->SetSlaveReplStatus(errorIsFatal(err) ? ReplicationState::Status::Fatal : ReplicationState::Status::Error, err, dummyCtx_); - else + } else { logPrintf( LogError, "[repl:%s:%s]:%d Sync namespace logical error. Set status Fatal. Replication not allowed for namespace. Err= %s", ns.name, slave_->storagePath_, config_.serverId, err.what()); + } + } + if (retryIfNetworkError(err)) { + return err; } - if (retryIfNetworkError(err)) return err; } } state_.store(StateIdle, std::memory_order_release); @@ -471,9 +489,11 @@ Error Replicator::syncDatabase(std::string_view initiator) { return err; } -Error Replicator::syncNamespaceByWAL(const NamespaceDef &nsDef) { +Error Replicator::syncNamespaceByWAL(const NamespaceDef& nsDef) { auto slaveNs = slave_->getNamespaceNoThrow(nsDef.name, dummyCtx_); - if (!slaveNs) return Error(errNotFound, "Namespace %s not found", nsDef.name); + if (!slaveNs) { + return Error(errNotFound, "Namespace %s not found", nsDef.name); + } lsn_t lsn = slaveNs->GetReplState(dummyCtx_).lastUpstreamLSN; @@ -482,7 +502,7 @@ Error Replicator::syncNamespaceByWAL(const NamespaceDef &nsDef) { } logPrintf(LogTrace, "[repl:%s:%s]:%d Start sync items, Query lsn = %s", nsDef.name, slave_->storagePath_, config_.serverId, lsn); - // Make query to master's WAL + // Make query to master's WAL client::QueryResults qr(kResultsWithPayloadTypes | kResultsCJson | kResultsWithItemID | kResultsWithRaw); Error err = master_->Select(Query(nsDef.name).Where("#lsn", CondGt, int64_t(lsn)), qr); @@ -492,7 +512,9 @@ Error Replicator::syncNamespaceByWAL(const NamespaceDef &nsDef) { return syncNamespaceForced(nsDef, err.what()); case errOK: err = applyWAL(slaveNs, qr); - if (err.ok()) err = slave_->syncDownstream(nsDef.name, false); + if (err.ok()) { + err = slave_->syncDownstream(nsDef.name, false); + } return err; case errNoWAL: terminate_ = true; @@ -541,7 +563,7 @@ Error Replicator::syncNamespaceByWAL(const NamespaceDef &nsDef) { // Forced namespace sync // This will completely drop slave namespace // read all indexes and data from master, then apply to slave -Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view reason) { +Error Replicator::syncNamespaceForced(const NamespaceDef& ns, std::string_view reason) { logPrintf(LogWarning, "[repl:%s:%s] Start FORCED sync: %s", ns.name, slave_->storagePath_, reason); // Create temporary namespace @@ -558,7 +580,9 @@ Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view r auto tmpNs = slave_->getNamespaceNoThrow(tmpNsDef.name, dummyCtx_); if (tmpNs) { auto dropErr = slave_->closeNamespace(tmpNsDef.name, dummyCtx_, true, true); - if (!dropErr.ok()) logPrintf(LogWarning, "Unable to drop temporary namespace %s: %s", tmpNsDef.name, dropErr.what()); + if (!dropErr.ok()) { + logPrintf(LogWarning, "Unable to drop temporary namespace %s: %s", tmpNsDef.name, dropErr.what()); + } } }; @@ -574,9 +598,9 @@ Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view r return Error(errNotFound, "Namespace %s not found", tmpNsDef.name); } auto replState = tmpNs->GetReplState(dummyCtx_); - if (replState.replicatorEnabled) + if (replState.replicatorEnabled) { tmpNs->SetSlaveReplStatus(ReplicationState::Status::Syncing, errOK, dummyCtx_); - else { + } else { logPrintf(LogError, "[repl:%s:%s] Sync namespace logical error. Set status Syncing tmpNs. Replication not allowed for namespace.", ns.name, slave_->storagePath_); dropTmpNs(); @@ -584,11 +608,15 @@ Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view r } err = syncMetaForced(tmpNs, ns.name); - if (err.ok()) err = syncSchemaForced(tmpNs, ns.name); + if (err.ok()) { + err = syncSchemaForced(tmpNs, ns.name); + } // Make query to complete master's namespace data client::QueryResults qr(kResultsWithPayloadTypes | kResultsCJson | kResultsWithItemID | kResultsWithRaw); - if (err.ok()) err = master_->Select(Query(ns.name).Where("#lsn", CondAny, VariantArray{}), qr); + if (err.ok()) { + err = master_->Select(Query(ns.name).Where("#lsn", CondAny, VariantArray{}), qr); + } if (err.ok()) { ForceSyncContext fsyncCtx{.nsDef = ns, .replaceTagsMatcher = [&] { if (auto err = tmpNs->ReplaceTagsMatcher(qr.getTagsMatcher(0), dummyCtx_); !err.ok()) { @@ -601,8 +629,12 @@ Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view r err = errOK; } } - if (err.ok()) err = slave_->renameNamespace(tmpNsDef.name, ns.name, true); - if (err.ok()) err = slave_->syncDownstream(ns.name, true); + if (err.ok()) { + err = slave_->renameNamespace(tmpNsDef.name, ns.name, true); + } + if (err.ok()) { + err = slave_->syncDownstream(ns.name, true); + } if (!err.ok()) { logPrintf(LogError, "[repl:%s] FORCED sync error: %s", ns.name, err.what()); @@ -612,7 +644,7 @@ Error Replicator::syncNamespaceForced(const NamespaceDef &ns, std::string_view r return err; } -Error Replicator::applyWAL(Namespace::Ptr &slaveNs, client::QueryResults &qr, const ForceSyncContext *fsyncCtx) { +Error Replicator::applyWAL(Namespace::Ptr& slaveNs, client::QueryResults& qr, const ForceSyncContext* fsyncCtx) { Error err; SyncStat stat; WrSerializer ser; @@ -634,7 +666,9 @@ Error Replicator::applyWAL(Namespace::Ptr &slaveNs, client::QueryResults &qr, co } if (err.ok()) { for (auto it : qr) { - if (terminate_) break; + if (terminate_) { + break; + } if (qr.Status().ok()) { try { if (it.IsRaw()) { @@ -662,7 +696,7 @@ Error Replicator::applyWAL(Namespace::Ptr &slaveNs, client::QueryResults &qr, co } } } - } catch (const Error &e) { + } catch (const Error& e) { err = e; } if (!err.ok()) { @@ -699,33 +733,39 @@ Error Replicator::applyWAL(Namespace::Ptr &slaveNs, client::QueryResults &qr, co if (stat.lastError.ok() && !terminate_) { logPrintf(LogTrace, "[repl:%s]:%d applyWal SetReplLSNs upstreamLsn = %s originLsn = %s", nsName, config_.serverId, stat.masterState.lastLsn, stat.masterState.originLSN); - // counters from the upstream node (from WalReplState) + // counters from the upstream node (from WalReplState) slaveNs->SetReplLSNs(LSNPair(stat.masterState.lastLsn, stat.masterState.originLSN), dummyCtx_); } ser.Reset(); stat.Dump(ser) << "lsn #" << int64_t(slaveState.lastLsn); - logPrintf(!stat.lastError.ok() ? LogError : LogInfo, "[repl:%s:%s]:%d Sync %s: %s", nsName, slave_->storagePath_, config_.serverId, + logPrintf((!stat.lastError.ok() ? LogError : LogInfo), "[repl:%s:%s]:%d Sync %s: %s", nsName, slave_->storagePath_, config_.serverId, terminate_ ? "terminated" : "done", ser.Slice()); - if (terminate_) return Error(errCanceled, "terminated"); + if (terminate_) { + return Error(errCanceled, "terminated"); + } return stat.lastError; } -Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr &slaveNs, const WALRecord &rec, SyncStat &stat) { +Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr& slaveNs, const WALRecord& rec, SyncStat& stat) { switch (rec.type) { // Modify item case WalItemModify: { std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (tx.IsFree()) return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (tx.IsFree()) { + return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + } Item item = tx.NewItem(); Error err = unpackItem(item, LSNs.upstreamLSN_, rec.itemModify.itemCJson, master_->NewItem(nsName).impl_->tagsMatcher()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } try { tx.Modify(std::move(item), static_cast(rec.itemModify.modifyMode)); - } catch (Error &e) { + } catch (Error& e) { return e; } } break; @@ -734,18 +774,22 @@ Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namesp QueryResults result; Query q = Query::FromSQL(rec.data); std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (tx.IsFree()) return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (tx.IsFree()) { + return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + } try { tx.Modify(std::move(q)); - } catch (Error &e) { + } catch (Error& e) { return e; } } break; case WalInitTransaction: { std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (!tx.IsFree()) logPrintf(LogError, "[repl:%s]:%d Init transaction befor commit of previous one.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (!tx.IsFree()) { + logPrintf(LogError, "[repl:%s]:%d Init transaction befor commit of previous one.", nsName, config_.serverId); + } RdxContext rdxContext(true, LSNs); tx = slaveNs->NewTransaction(rdxContext); if (!tx.Status().ok()) { @@ -756,8 +800,10 @@ Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namesp case WalCommitTransaction: { QueryResults res; std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (tx.IsFree()) return Error(errLogic, "[repl:%s]:%d Commit of transaction befor initiate it.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (tx.IsFree()) { + return Error(errLogic, "[repl:%s]:%d Commit of transaction befor initiate it.", nsName, config_.serverId); + } RdxContext rdxContext(true, LSNs); slaveNs->CommitTransaction(tx, res, rdxContext); stat.txEnds++; @@ -773,22 +819,26 @@ Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namesp config_.serverId, stateToken, version); std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (tx.IsFree()) return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (tx.IsFree()) { + return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + } try { tx.MergeTagsMatcher(std::move(tm)); - } catch (Error &e) { + } catch (Error& e) { return e; } } break; case WalPutMeta: { std::lock_guard lck(syncMtx_); - Transaction &tx = transactions_[slaveNs.get()]; - if (tx.IsFree()) return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + Transaction& tx = transactions_[slaveNs.get()]; + if (tx.IsFree()) { + return Error(errLogic, "[repl:%s]:%d Transaction was not initiated.", nsName, config_.serverId); + } try { tx.PutMeta(std::string(rec.itemMeta.key), rec.itemMeta.value); - } catch (Error &e) { + } catch (Error& e) { return e; } } break; @@ -813,7 +863,7 @@ Error Replicator::applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namesp return {}; } -void Replicator::checkNoOpenedTransaction(std::string_view nsName, Namespace::Ptr &slaveNs) { +void Replicator::checkNoOpenedTransaction(std::string_view nsName, Namespace::Ptr& slaveNs) { std::lock_guard lck(syncMtx_); auto txIt = transactions_.find(slaveNs.get()); if (txIt != transactions_.end() && !txIt->second.IsFree()) { @@ -822,7 +872,7 @@ void Replicator::checkNoOpenedTransaction(std::string_view nsName, Namespace::Pt } } -Error Replicator::applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr &slaveNs, const WALRecord &rec, SyncStat &stat) { +Error Replicator::applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr& slaveNs, const WALRecord& rec, SyncStat& stat) { Error err; IndexDef iDef; @@ -836,10 +886,12 @@ Error Replicator::applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespac checkNoOpenedTransaction(nsName, slaveNs); - auto sendSyncAsync = [this](const WALRecord &rec, bool forced) { + auto sendSyncAsync = [this](const WALRecord& rec, bool forced) { NamespaceDef nsDef; Error err = nsDef.FromJSON(giftStr(rec.data)); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } syncQueue_.Push(nsDef.name, std::move(nsDef), forced); walSyncAsync_.send(); return err; @@ -854,19 +906,25 @@ Error Replicator::applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespac // Index added case WalIndexAdd: err = iDef.FromJSON(giftStr(rec.data)); - if (err.ok()) slaveNs->AddIndex(iDef, rdxContext); + if (err.ok()) { + slaveNs->AddIndex(iDef, rdxContext); + } stat.updatedIndexes++; break; // Index dropped case WalIndexDrop: err = iDef.FromJSON(giftStr(rec.data)); - if (err.ok()) slaveNs->DropIndex(iDef, rdxContext); + if (err.ok()) { + slaveNs->DropIndex(iDef, rdxContext); + } stat.deletedIndexes++; break; // Index updated case WalIndexUpdate: err = iDef.FromJSON(giftStr(rec.data)); - if (err.ok()) slaveNs->UpdateIndex(iDef, rdxContext); + if (err.ok()) { + slaveNs->UpdateIndex(iDef, rdxContext); + } stat.updatedIndexes++; break; // Metadata updated @@ -961,7 +1019,7 @@ Error Replicator::applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespac return err; } -Error Replicator::unpackItem(Item &item, lsn_t lsn, std::string_view cjson, const TagsMatcher &tm) { +Error Replicator::unpackItem(Item& item, lsn_t lsn, std::string_view cjson, const TagsMatcher& tm) { if (item.impl_->tagsMatcher().size() < tm.size()) { const bool res = item.impl_->tagsMatcher().try_merge(tm); if (!res) { @@ -972,7 +1030,7 @@ Error Replicator::unpackItem(Item &item, lsn_t lsn, std::string_view cjson, cons return item.FromCJSON(cjson); } -void Replicator::pushPendingUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec) { +void Replicator::pushPendingUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec) { PackedWALRecord pwrec; pwrec.Pack(wrec); auto updatesIt = pendedUpdates_.find(nsName); @@ -981,13 +1039,13 @@ void Replicator::pushPendingUpdate(LSNPair LSNs, std::string_view nsName, const updates.container.emplace_back(std::make_pair(LSNs, std::move(pwrec))); pendedUpdates_.emplace(std::string(nsName), std::move(updates)); } else { - auto &updates = updatesIt.value().container; + auto& updates = updatesIt.value().container; updates.emplace_back(std::make_pair(LSNs, std::move(pwrec))); } } -Error Replicator::modifyItem(LSNPair LSNs, Namespace::Ptr &slaveNs, std::string_view cjson, int modifyMode, const TagsMatcher &tm, - SyncStat &stat) { +Error Replicator::modifyItem(LSNPair LSNs, Namespace::Ptr& slaveNs, std::string_view cjson, int modifyMode, const TagsMatcher& tm, + SyncStat& stat) { Item item = slaveNs->NewItem(dummyCtx_); Error err = unpackItem(item, LSNs.upstreamLSN_, cjson, tm); @@ -1017,8 +1075,8 @@ Error Replicator::modifyItem(LSNPair LSNs, Namespace::Ptr &slaveNs, std::string_ return err; } -Error Replicator::modifyItemTx(LSNPair LSNs, Transaction &tx, std::string_view cjson, int modifyMode, const TagsMatcher &tm, - SyncStat &stat) { +Error Replicator::modifyItemTx(LSNPair LSNs, Transaction& tx, std::string_view cjson, int modifyMode, const TagsMatcher& tm, + SyncStat& stat) { Item item = tx.NewItem(); Error err = unpackItem(item, LSNs.upstreamLSN_, cjson, tm); @@ -1047,29 +1105,49 @@ Error Replicator::modifyItemTx(LSNPair LSNs, Transaction &tx, std::string_view c return err; } -WrSerializer &Replicator::SyncStat::Dump(WrSerializer &ser) { - if (updated) ser << updated << " items updated; "; - if (deleted) ser << deleted << " items deleted; "; - if (updatedIndexes) ser << updatedIndexes << " indexes updated; "; - if (deletedIndexes) ser << deletedIndexes << " indexes deleted; "; - if (updatedMeta) ser << updatedMeta << " meta updated; "; - if (schemasSet) ser << "New schema was set; "; - if (txStarts || txEnds) ser << " started " << txStarts << ", completed " << txEnds << " transactions; "; - if (errors || !lastError.ok()) ser << errors << " errors (" << lastError.what() << ") "; - if (!ser.Len()) ser << "Up to date; "; - if (processed) ser << "processed " << processed << " WAL records "; +WrSerializer& Replicator::SyncStat::Dump(WrSerializer& ser) { + if (updated) { + ser << updated << " items updated; "; + } + if (deleted) { + ser << deleted << " items deleted; "; + } + if (updatedIndexes) { + ser << updatedIndexes << " indexes updated; "; + } + if (deletedIndexes) { + ser << deletedIndexes << " indexes deleted; "; + } + if (updatedMeta) { + ser << updatedMeta << " meta updated; "; + } + if (schemasSet) { + ser << "New schema was set; "; + } + if (txStarts || txEnds) { + ser << " started " << txStarts << ", completed " << txEnds << " transactions; "; + } + if (errors || !lastError.ok()) { + ser << errors << " errors (" << lastError.what() << ") "; + } + if (!ser.Len()) { + ser << "Up to date; "; + } + if (processed) { + ser << "processed " << processed << " WAL records "; + } return ser; } -Error Replicator::syncIndexesForced(Namespace::Ptr &slaveNs, const ForceSyncContext &fsyncCtx) { - const std::string &nsName = fsyncCtx.nsDef.name; +Error Replicator::syncIndexesForced(Namespace::Ptr& slaveNs, const ForceSyncContext& fsyncCtx) { + const std::string& nsName = fsyncCtx.nsDef.name; Error err; - for (auto &idx : fsyncCtx.nsDef.indexes) { + for (auto& idx : fsyncCtx.nsDef.indexes) { logPrintf(LogTrace, "[repl:%s] Updating index '%s'", nsName, idx.name_); try { slaveNs->AddIndex(idx, dummyCtx_); - } catch (const Error &e) { + } catch (const Error& e) { logPrintf(LogError, "[repl:%s] Error add index '%s': %s", nsName, idx.name_, err.what()); err = e; } @@ -1077,7 +1155,7 @@ Error Replicator::syncIndexesForced(Namespace::Ptr &slaveNs, const ForceSyncCont try { assertrx(fsyncCtx.replaceTagsMatcher); fsyncCtx.replaceTagsMatcher(); - } catch (const Error &e) { + } catch (const Error& e) { logPrintf(LogError, "[repl:%s] Error on TagsMatcher replace call: %s", nsName, err.what()); err = e; } @@ -1085,14 +1163,14 @@ Error Replicator::syncIndexesForced(Namespace::Ptr &slaveNs, const ForceSyncCont return err; } -Error Replicator::syncSchemaForced(Namespace::Ptr &slaveNs, const NamespaceDef &masterNsDef) { - const std::string &nsName = masterNsDef.name; +Error Replicator::syncSchemaForced(Namespace::Ptr& slaveNs, const NamespaceDef& masterNsDef) { + const std::string& nsName = masterNsDef.name; Error err = errOK; logPrintf(LogTrace, "[repl:%s] Setting schema", nsName); try { slaveNs->SetSchema(masterNsDef.schemaJson, dummyCtx_); - } catch (const Error &e) { + } catch (const Error& e) { logPrintf(LogError, "[repl:%s] Error in set schema: %s", nsName, err.what()); err = e; } @@ -1100,11 +1178,11 @@ Error Replicator::syncSchemaForced(Namespace::Ptr &slaveNs, const NamespaceDef & return err; } -Error Replicator::syncMetaForced(Namespace::Ptr &slaveNs, std::string_view nsName) { +Error Replicator::syncMetaForced(Namespace::Ptr& slaveNs, std::string_view nsName) { std::vector keys; auto err = master_->EnumMeta(nsName, keys); - for (auto &key : keys) { + for (auto& key : keys) { std::string data; err = master_->GetMeta(nsName, key, data); if (!err.ok()) { @@ -1113,7 +1191,7 @@ Error Replicator::syncMetaForced(Namespace::Ptr &slaveNs, std::string_view nsNam } try { slaveNs->PutMeta(key, data, dummyCtx_); - } catch (const Error &e) { + } catch (const Error& e) { logPrintf(LogError, "[repl:%s]:%d Error set meta '%s': %s", slaveNs->GetName(dummyCtx_), config_.serverId, key, e.what()); } } @@ -1121,14 +1199,14 @@ Error Replicator::syncMetaForced(Namespace::Ptr &slaveNs, std::string_view nsNam } // Callback from WAL updates pusher -void Replicator::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec) { +void Replicator::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec) { try { onWALUpdateImpl(LSNs, nsName, wrec); - } catch (Error &e) { + } catch (Error& e) { logPrintf(LogError, "[repl:%s]:%d Exception on WAL update: %s", nsName, config_.serverId, e.what()); assertrx_dbg(false); resync_.send(); - } catch (std::exception &e) { + } catch (std::exception& e) { logPrintf(LogError, "[repl:%s]:%d Exception on WAL update (std::exception): %s", nsName, config_.serverId, e.what()); assertrx_dbg(false); resync_.send(); @@ -1139,7 +1217,7 @@ void Replicator::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRec } } -void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec) { +void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec) { auto sId = LSNs.originLSN_.Server(); if (sId != 0) { // sId = 0 for configurations without specifying a server id if (sId == config_.serverId) { @@ -1149,8 +1227,10 @@ void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WA } } logPrintf(LogTrace, "[repl:%s:%s]:%d OnWALUpdate state = %d upstreamLSN = %s", nsName, slave_->storagePath_, config_.serverId, - state_.load(std::memory_order_acquire), LSNs.upstreamLSN_); - if (!canApplyUpdate(LSNs, nsName, wrec)) return; + int(state_.load(std::memory_order_acquire)), LSNs.upstreamLSN_); + if (!canApplyUpdate(LSNs, nsName, wrec)) { + return; + } Error err; auto slaveNs = slave_->getNamespaceNoThrow(nsName, dummyCtx_); @@ -1160,8 +1240,8 @@ void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WA if (!replState.lastUpstreamLSN.isEmpty()) { if (replState.lastUpstreamLSN.Counter() >= LSNs.upstreamLSN_.Counter()) { logPrintf(LogTrace, - "[repl:%s:%s]:%d OnWALUpdate old record state = %d upstreamLSN = %s replState.lastUpstreamLSN=%d wrec.type = %d", - nsName, slave_->storagePath_, config_.serverId, state_.load(std::memory_order_acquire), LSNs.upstreamLSN_, + "[repl:%s:%s]:%d OnWALUpdate old record state = %d upstreamLSN = %s replState.lastUpstreamLSN=%s wrec.type = %d", + nsName, slave_->storagePath_, config_.serverId, int(state_.load(std::memory_order_acquire)), LSNs.upstreamLSN_, replState.lastUpstreamLSN, wrec.type); return; } @@ -1171,7 +1251,7 @@ void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WA SyncStat stat; try { err = applyWALRecord(LSNs, nsName, slaveNs, wrec, stat); - } catch (const Error &e) { + } catch (const Error& e) { err = e; } if (err.ok()) { @@ -1182,18 +1262,19 @@ void Replicator::onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WA if (slaveNs) { auto replState = slaveNs->GetReplState(dummyCtx_); if (replState.status != ReplicationState::Status::Fatal) { - if (replState.replicatorEnabled) + if (replState.replicatorEnabled) { slaveNs->SetSlaveReplStatus(ReplicationState::Status::Fatal, err, dummyCtx_); - else + } else { logPrintf(LogError, "[repl:%s:%s]:%d OnWALUpdate logical error. Replication not allowed for nanespace. Err = %s", nsName, slave_->storagePath_, config_.serverId, err.what()); + } } } auto lastErrIt = lastNsErrMsg_.find(nsName); if (lastErrIt == lastNsErrMsg_.end()) { lastErrIt = lastNsErrMsg_.emplace(std::string(nsName), NsErrorMsg{}).first; } - auto &lastErr = lastErrIt->second; + auto& lastErr = lastErrIt->second; bool isDifferentError = lastErr.err.what() != err.what(); if (isDifferentError || lastErr.count == static_cast(config_.onlineReplErrorsThreshold)) { if (!lastErr.err.ok() && lastErr.count > 1) { @@ -1233,7 +1314,7 @@ void Replicator::OnUpdatesLost(std::string_view nsName) { resyncUpdatesLostAsync_.send(); } -void Replicator::OnConnectionState(const Error &err) { +void Replicator::OnConnectionState(const Error& err) { if (err.ok()) { logPrintf(LogInfo, "[repl:] OnConnectionState connected"); } else { @@ -1244,8 +1325,10 @@ void Replicator::OnConnectionState(const Error &err) { resync_.send(); } -bool Replicator::canApplyUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec) { - if (!isSyncEnabled(nsName)) return false; +bool Replicator::canApplyUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec) { + if (!isSyncEnabled(nsName)) { + return false; + } if (terminate_.load(std::memory_order_acquire)) { logPrintf(LogTrace, "[repl:%s]:%d Skipping update due to replicator shutdown is in progress upstreamLSN %s (%d)", nsName, @@ -1327,7 +1410,9 @@ bool Replicator::canApplyUpdate(LSNPair LSNs, std::string_view nsName, const WAL bool Replicator::isSyncEnabled(std::string_view nsName) { // SKip system ns - if (isSystemNamespaceNameFast(nsName)) return false; + if (isSystemNamespaceNameFast(nsName)) { + return false; + } // skip non enabled namespaces if (config_.namespaces.size() && config_.namespaces.find(nsName) == config_.namespaces.end()) { @@ -1336,14 +1421,14 @@ bool Replicator::isSyncEnabled(std::string_view nsName) { return true; } -void Replicator::SyncQueue::Push(const std::string &nsName, NamespaceDef &&nsDef, bool forced) { +void Replicator::SyncQueue::Push(const std::string& nsName, NamespaceDef&& nsDef, bool forced) { std::lock_guard lock(mtx_); - auto &val = queue_[nsName]; + auto& val = queue_[nsName]; val = recordData(std::move(nsDef), val.forced || forced); size_.fetch_add(1, std::memory_order_release); } -bool Replicator::SyncQueue::Get(NamespaceDef &def, bool &forced) const { +bool Replicator::SyncQueue::Get(NamespaceDef& def, bool& forced) const { std::lock_guard lock(mtx_); if (!queue_.empty()) { auto it = queue_.begin(); @@ -1354,7 +1439,7 @@ bool Replicator::SyncQueue::Get(NamespaceDef &def, bool &forced) const { return false; } -bool Replicator::SyncQueue::Pop(std::string_view nsName, const std::unique_lock &replicatorLock) noexcept { +bool Replicator::SyncQueue::Pop(std::string_view nsName, const std::unique_lock& replicatorLock) noexcept { std::lock_guard lock(mtx_); // Pop() must be called under top level replicator's sync mutex assertrx(replicatorLock.owns_lock()); diff --git a/cpp_src/replicator/replicator.h b/cpp_src/replicator/replicator.h index 1c0ba9ddf..c91540abd 100644 --- a/cpp_src/replicator/replicator.h +++ b/cpp_src/replicator/replicator.h @@ -13,9 +13,9 @@ class ReindexerImpl; class Replicator : public IUpdatesObserver { public: - Replicator(ReindexerImpl *slave); + Replicator(ReindexerImpl* slave); ~Replicator(); - bool Configure(const ReplicationConfigData &config); + bool Configure(const ReplicationConfigData& config); Error Start(); void Stop(); void Enable() { enabled_.store(true, std::memory_order_release); } @@ -26,7 +26,7 @@ class Replicator : public IUpdatesObserver { Error lastError; int updated = 0, deleted = 0, errors = 0, updatedIndexes = 0, deletedIndexes = 0, updatedMeta = 0, processed = 0, schemasSet = 0, txStarts = 0, txEnds = 0; - WrSerializer &Dump(WrSerializer &ser); + WrSerializer& Dump(WrSerializer& ser); }; struct NsErrorMsg { Error err; @@ -34,10 +34,10 @@ class Replicator : public IUpdatesObserver { }; class SyncQueue { public: - SyncQueue(const std::mutex &replicatorMtx) noexcept : replicatorMtx_(replicatorMtx) {} - void Push(const std::string &nsName, NamespaceDef &&nsDef, bool force); - bool Get(NamespaceDef &def, bool &force) const; - bool Pop(std::string_view nsName, const std::unique_lock &replicatorLock) noexcept; + SyncQueue(const std::mutex& replicatorMtx) noexcept : replicatorMtx_(replicatorMtx) {} + void Push(const std::string& nsName, NamespaceDef&& nsDef, bool force); + bool Get(NamespaceDef& def, bool& force) const; + bool Pop(std::string_view nsName, const std::unique_lock& replicatorLock) noexcept; size_t Size() const noexcept { return size_.load(std::memory_order_acquire); } bool Contains(std::string_view nsName) noexcept; void Clear() noexcept; @@ -45,7 +45,7 @@ class Replicator : public IUpdatesObserver { private: struct recordData { recordData() = default; - recordData(NamespaceDef &&_def, bool _forced) : def(std::move(_def)), forced(_forced) {} + recordData(NamespaceDef&& _def, bool _forced) : def(std::move(_def)), forced(_forced) {} NamespaceDef def; bool forced = false; @@ -53,11 +53,11 @@ class Replicator : public IUpdatesObserver { fast_hash_map queue_; std::atomic size_ = {0}; mutable std::mutex mtx_; - const std::mutex &replicatorMtx_; + const std::mutex& replicatorMtx_; }; struct ForceSyncContext { - const NamespaceDef &nsDef; + const NamespaceDef& nsDef; std::function replaceTagsMatcher; }; @@ -69,47 +69,47 @@ class Replicator : public IUpdatesObserver { std::string_view forceSyncReason; }; // Sync single namespace - SyncNsResult syncNamespace(const NamespaceDef &ns, std::string_view forceSyncReason, SyncQueue *sourceQueue, + SyncNsResult syncNamespace(const NamespaceDef& ns, std::string_view forceSyncReason, SyncQueue* sourceQueue, std::string_view initiator); // Sync database Error syncDatabase(std::string_view initiator); // Read and apply WAL from master - Error syncNamespaceByWAL(const NamespaceDef &ns); + Error syncNamespaceByWAL(const NamespaceDef& ns); // Apply WAL from master to namespace - Error applyWAL(Namespace::Ptr &slaveNs, client::QueryResults &qr, const ForceSyncContext *fsyncCtx = nullptr); + Error applyWAL(Namespace::Ptr& slaveNs, client::QueryResults& qr, const ForceSyncContext* fsyncCtx = nullptr); // Sync indexes of namespace - Error syncIndexesForced(Namespace::Ptr &slaveNs, const ForceSyncContext &fsyncCtx); + Error syncIndexesForced(Namespace::Ptr& slaveNs, const ForceSyncContext& fsyncCtx); // Sync namespace schema - Error syncSchemaForced(Namespace::Ptr &slaveNs, const NamespaceDef &masterNsDef); + Error syncSchemaForced(Namespace::Ptr& slaveNs, const NamespaceDef& masterNsDef); // Forced sync of namespace - Error syncNamespaceForced(const NamespaceDef &ns, std::string_view reason); + Error syncNamespaceForced(const NamespaceDef& ns, std::string_view reason); // Sync metadata - Error syncMetaForced(Namespace::Ptr &slaveNs, std::string_view nsName); + Error syncMetaForced(Namespace::Ptr& slaveNs, std::string_view nsName); // Apply single WAL record - Error applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr &ns, const WALRecord &wrec, SyncStat &stat); + Error applyWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr& ns, const WALRecord& wrec, SyncStat& stat); // Apply single transaction WAL record - Error applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr &ns, const WALRecord &wrec, SyncStat &stat); - void checkNoOpenedTransaction(std::string_view nsName, Namespace::Ptr &slaveNs); + Error applyTxWALRecord(LSNPair LSNs, std::string_view nsName, Namespace::Ptr& ns, const WALRecord& wrec, SyncStat& stat); + void checkNoOpenedTransaction(std::string_view nsName, Namespace::Ptr& slaveNs); // Apply single cjson item - Error modifyItem(LSNPair LSNs, Namespace::Ptr &ns, std::string_view cjson, int modifyMode, const TagsMatcher &tm, SyncStat &stat); + Error modifyItem(LSNPair LSNs, Namespace::Ptr& ns, std::string_view cjson, int modifyMode, const TagsMatcher& tm, SyncStat& stat); // Add single cjson item into tx - Error modifyItemTx(LSNPair LSNs, Transaction &tx, std::string_view cjson, int modifyMode, const TagsMatcher &tm, SyncStat &stat); - static Error unpackItem(Item &, lsn_t, std::string_view cjson, const TagsMatcher &tm); + Error modifyItemTx(LSNPair LSNs, Transaction& tx, std::string_view cjson, int modifyMode, const TagsMatcher& tm, SyncStat& stat); + static Error unpackItem(Item&, lsn_t, std::string_view cjson, const TagsMatcher& tm); // Push update to the queue to apply it later - void pushPendingUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec); + void pushPendingUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec); - void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec) override final; - void onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec); + void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec) override final; + void onWALUpdateImpl(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec); void OnUpdatesLost(std::string_view nsName) override final; - void OnConnectionState(const Error &err) override final; + void OnConnectionState(const Error& err) override final; - bool canApplyUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &wrec); + bool canApplyUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& wrec); bool isSyncEnabled(std::string_view nsName); - bool retryIfNetworkError(const Error &err); - void subscribeUpdatesIfRequired(const std::string &nsName); + bool retryIfNetworkError(const Error& err); + void subscribeUpdatesIfRequired(const std::string& nsName); std::unique_ptr master_; - ReindexerImpl *slave_; + ReindexerImpl* slave_; net::ev::dynamic_loop loop_; std::thread thread_; @@ -141,7 +141,7 @@ class Replicator : public IUpdatesObserver { std::atomic enabled_; const RdxContext dummyCtx_; - std::unordered_map transactions_; + std::unordered_map transactions_; fast_hash_map lastNsErrMsg_; SyncQueue syncQueue_; }; diff --git a/cpp_src/replicator/updatesobserver.cc b/cpp_src/replicator/updatesobserver.cc index 62e07f98e..b0e6ba47f 100644 --- a/cpp_src/replicator/updatesobserver.cc +++ b/cpp_src/replicator/updatesobserver.cc @@ -8,7 +8,7 @@ using namespace std::string_view_literals; namespace reindexer { -void UpdatesFilters::Merge(const UpdatesFilters &rhs) { +void UpdatesFilters::Merge(const UpdatesFilters& rhs) { if (filters_.empty()) { return; } @@ -16,13 +16,13 @@ void UpdatesFilters::Merge(const UpdatesFilters &rhs) { filters_.clear(); return; } - for (auto &rhsFilter : rhs.filters_) { + for (auto& rhsFilter : rhs.filters_) { auto foundNs = filters_.find(rhsFilter.first); if (foundNs == filters_.end()) { filters_.emplace(rhsFilter.first, rhsFilter.second); } else { - auto &nsFilters = foundNs.value(); - for (auto &filter : rhsFilter.second) { + auto& nsFilters = foundNs.value(); + for (auto& filter : rhsFilter.second) { const auto foundFilter = std::find(nsFilters.cbegin(), nsFilters.cend(), filter); if (foundFilter == nsFilters.cend()) { nsFilters.emplace_back(filter); @@ -39,7 +39,7 @@ void UpdatesFilters::AddFilter(std::string_view ns, UpdatesFilters::Filter filte lst.emplace_back(std::move(filter)); // NOLINT(performance-move-const-arg) filters_.emplace(std::string(ns), std::move(lst)); } else { - auto &nsFilters = foundNs.value(); + auto& nsFilters = foundNs.value(); const auto foundFilter = std::find(nsFilters.cbegin(), nsFilters.cend(), filter); if (foundFilter == nsFilters.cend()) { nsFilters.emplace_back(std::move(filter)); // NOLINT(performance-move-const-arg) @@ -57,7 +57,7 @@ bool UpdatesFilters::Check(std::string_view ns) const { return false; } - for (auto &filter : found.value()) { + for (auto& filter : found.value()) { if (filter.Check()) { return true; } @@ -68,18 +68,18 @@ bool UpdatesFilters::Check(std::string_view ns) const { Error UpdatesFilters::FromJSON(span json) { try { FromJSON(gason::JsonParser().Parse(json)); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "UpdatesFilter: %s", ex.what()); - } catch (const Error &err) { + } catch (const Error& err) { return err; } return errOK; } -void UpdatesFilters::FromJSON(const gason::JsonNode &root) { - for (const auto &ns : root["namespaces"sv]) { +void UpdatesFilters::FromJSON(const gason::JsonNode& root) { + for (const auto& ns : root["namespaces"sv]) { auto name = ns["name"sv].As(); - for (const auto &f : ns["filters"sv]) { + for (const auto& f : ns["filters"sv]) { Filter filter; filter.FromJSON(f); AddFilter(name, std::move(filter)); // NOLINT(performance-move-const-arg) @@ -87,15 +87,15 @@ void UpdatesFilters::FromJSON(const gason::JsonNode &root) { } } -void UpdatesFilters::GetJSON(WrSerializer &ser) const { +void UpdatesFilters::GetJSON(WrSerializer& ser) const { JsonBuilder builder(ser); { auto arr = builder.Array("namespaces"sv); - for (const auto &nsFilters : filters_) { + for (const auto& nsFilters : filters_) { auto obj = arr.Object(); obj.Put("name"sv, nsFilters.first); auto arrFilters = obj.Array("filters"sv); - for (const auto &filter : nsFilters.second) { + for (const auto& filter : nsFilters.second) { auto filtersObj = arrFilters.Object(); filter.GetJSON(filtersObj); } @@ -103,12 +103,12 @@ void UpdatesFilters::GetJSON(WrSerializer &ser) const { } } -bool UpdatesFilters::operator==(const UpdatesFilters &rhs) const { +bool UpdatesFilters::operator==(const UpdatesFilters& rhs) const { if (filters_.size() != rhs.filters_.size()) { return false; } - for (const auto &nsFilters : filters_) { + for (const auto& nsFilters : filters_) { const auto rhsNsFilters = rhs.filters_.find(nsFilters.first); if (rhsNsFilters == rhs.filters_.cend()) { return false; @@ -116,7 +116,7 @@ bool UpdatesFilters::operator==(const UpdatesFilters &rhs) const { if (rhsNsFilters.value().size() != nsFilters.second.size()) { return false; } - for (const auto &filter : nsFilters.second) { + for (const auto& filter : nsFilters.second) { const auto rhsFilter = std::find(rhsNsFilters.value().cbegin(), rhsNsFilters.value().cend(), filter); if (rhsFilter == rhsNsFilters.value().cend()) { return false; @@ -127,9 +127,9 @@ bool UpdatesFilters::operator==(const UpdatesFilters &rhs) const { return true; } -void UpdatesObservers::Add(IUpdatesObserver *observer, const UpdatesFilters &filters, SubscriptionOpts opts) { +void UpdatesObservers::Add(IUpdatesObserver* observer, const UpdatesFilters& filters, SubscriptionOpts opts) { std::unique_lock lck(mtx_); - auto it = std::find_if(observers_.begin(), observers_.end(), [observer](const ObserverInfo &info) { return info.ptr == observer; }); + auto it = std::find_if(observers_.begin(), observers_.end(), [observer](const ObserverInfo& info) { return info.ptr == observer; }); if (it != observers_.end()) { if (opts.IsIncrementSubscription()) { it->filters.Merge(filters); @@ -141,9 +141,9 @@ void UpdatesObservers::Add(IUpdatesObserver *observer, const UpdatesFilters &fil } } -Error UpdatesObservers::Delete(IUpdatesObserver *observer) { +Error UpdatesObservers::Delete(IUpdatesObserver* observer) { std::unique_lock lck(mtx_); - auto it = std::find_if(observers_.begin(), observers_.end(), [observer](const ObserverInfo &info) { return info.ptr == observer; }); + auto it = std::find_if(observers_.begin(), observers_.end(), [observer](const ObserverInfo& info) { return info.ptr == observer; }); if (it == observers_.end()) { return Error(errParams, "Observer was not added"); } @@ -156,7 +156,7 @@ std::vector UpdatesObservers::Get() const { return observers_; } -void UpdatesObservers::OnModifyItem(LSNPair LSNs, std::string_view nsName, ItemImpl *impl, int modifyMode, bool inTransaction) { +void UpdatesObservers::OnModifyItem(LSNPair LSNs, std::string_view nsName, ItemImpl* impl, int modifyMode, bool inTransaction) { WrSerializer ser; WALRecord walRec(WalItemModify, impl->tagsMatcher().isUpdated() ? impl->GetCJSON(ser, true) : impl->GetCJSON(), impl->tagsMatcher().version(), modifyMode, inTransaction); @@ -164,9 +164,11 @@ void UpdatesObservers::OnModifyItem(LSNPair LSNs, std::string_view nsName, ItemI OnWALUpdate(LSNs, nsName, walRec); } -void UpdatesObservers::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &walRec) { +void UpdatesObservers::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& walRec) { // Disable updates of system namespaces (it may cause recursive lock) - if (isSystemNamespaceNameFast(nsName)) return; + if (isSystemNamespaceNameFast(nsName)) { + return; + } bool skipFilters = walRec.type == WalNamespaceAdd || walRec.type == WalNamespaceDrop || walRec.type == WalNamespaceRename || walRec.type == WalForceSync || nsName.empty(); @@ -191,9 +193,9 @@ void UpdatesObservers::OnUpdatesLost(std::string_view nsName) { } } -void UpdatesObservers::OnConnectionState(const Error &err) { +void UpdatesObservers::OnConnectionState(const Error& err) { shared_lock lck(mtx_); - for (auto &observer : observers_) { + for (auto& observer : observers_) { observer.ptr->OnConnectionState(err); } } @@ -201,13 +203,13 @@ void UpdatesObservers::OnConnectionState(const Error &err) { UpdatesFilters UpdatesObservers::GetMergedFilter() const { shared_lock lck(mtx_); UpdatesFilters filter = observers_.size() ? observers_.front().filters : UpdatesFilters(); - for (const auto &observer : observers_) { + for (const auto& observer : observers_) { filter.Merge(observer.filters); } return filter; } -std::ostream &operator<<(std::ostream &o, const reindexer::UpdatesFilters &filters) { +std::ostream& operator<<(std::ostream& o, const reindexer::UpdatesFilters& filters) { reindexer::WrSerializer ser; filters.GetJSON(ser); o << ser.Slice(); diff --git a/cpp_src/replicator/updatesobserver.h b/cpp_src/replicator/updatesobserver.h index dc3f5c6cb..05f58f777 100644 --- a/cpp_src/replicator/updatesobserver.h +++ b/cpp_src/replicator/updatesobserver.h @@ -23,10 +23,10 @@ class UpdatesFilters { public: // TODO: Any additional condition check should be added here bool Check() const { return true; } - void FromJSON(const gason::JsonNode &) {} - void GetJSON(JsonBuilder &) const {} + void FromJSON(const gason::JsonNode&) {} + void GetJSON(JsonBuilder&) const {} - bool operator==(const Filter &) const { return true; } + bool operator==(const Filter&) const { return true; } }; /// Merge two filters sets @@ -34,7 +34,7 @@ class UpdatesFilters { /// If one of the filters set contains some conditions for specific namespace, /// then result filters set will also contain this conditions /// @param rhs - Another filters set - void Merge(const UpdatesFilters &rhs); + void Merge(const UpdatesFilters& rhs); /// Add new filter for specified namespace. Doesn't merge filters, just concatenates it into disjunction sequence /// @param ns - Namespace /// @param filter - Filter to add @@ -45,10 +45,10 @@ class UpdatesFilters { bool Check(std::string_view ns) const; Error FromJSON(span json); - void FromJSON(const gason::JsonNode &root); - void GetJSON(WrSerializer &ser) const; + void FromJSON(const gason::JsonNode& root); + void GetJSON(WrSerializer& ser) const; - bool operator==(const UpdatesFilters &rhs) const; + bool operator==(const UpdatesFilters& rhs) const; private: using FiltersList = h_vector; @@ -59,29 +59,29 @@ class UpdatesFilters { class IUpdatesObserver { public: virtual ~IUpdatesObserver() = default; - virtual void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &rec) = 0; + virtual void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& rec) = 0; virtual void OnUpdatesLost(std::string_view nsName) = 0; - virtual void OnConnectionState(const Error &err) = 0; + virtual void OnConnectionState(const Error& err) = 0; }; class UpdatesObservers { public: struct ObserverInfo { - IUpdatesObserver *ptr; + IUpdatesObserver* ptr; UpdatesFilters filters; }; - void Add(IUpdatesObserver *observer, const UpdatesFilters &filter, SubscriptionOpts opts); - Error Delete(IUpdatesObserver *observer); + void Add(IUpdatesObserver* observer, const UpdatesFilters& filter, SubscriptionOpts opts); + Error Delete(IUpdatesObserver* observer); std::vector Get() const; - void OnModifyItem(LSNPair LSNs, std::string_view nsName, ItemImpl *item, int modifyMode, bool inTransaction); + void OnModifyItem(LSNPair LSNs, std::string_view nsName, ItemImpl* item, int modifyMode, bool inTransaction); - void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &rec); + void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& rec); void OnUpdatesLost(std::string_view nsName); - void OnConnectionState(const Error &err); + void OnConnectionState(const Error& err); bool Empty() { shared_lock lck(mtx_); return observers_.empty(); @@ -93,6 +93,6 @@ class UpdatesObservers { mutable shared_timed_mutex mtx_; }; -std::ostream &operator<<(std::ostream &o, const reindexer::UpdatesFilters &sv); +std::ostream& operator<<(std::ostream& o, const reindexer::UpdatesFilters& sv); } // namespace reindexer diff --git a/cpp_src/replicator/walrecord.cc b/cpp_src/replicator/walrecord.cc index f70831b19..a65b879e9 100644 --- a/cpp_src/replicator/walrecord.cc +++ b/cpp_src/replicator/walrecord.cc @@ -6,17 +6,19 @@ namespace reindexer { -enum { TxBit = (1 << 7) }; +constexpr unsigned kTxBit = (1 << 7); -void PackedWALRecord::Pack(const WALRecord &rec) { +void PackedWALRecord::Pack(const WALRecord& rec) { WrSerializer ser; rec.Pack(ser); assign(ser.Buf(), ser.Buf() + ser.Len()); } -void WALRecord::Pack(WrSerializer &ser) const { - if (type == WalEmpty) return; - ser.PutVarUint(inTransaction ? (type | TxBit) : type); +void WALRecord::Pack(WrSerializer& ser) const { + if (type == WalEmpty) { + return; + } + ser.PutVarUint(inTransaction ? (unsigned(type) | kTxBit) : unsigned(type)); switch (type) { case WalItemUpdate: case WalShallowItem: @@ -69,9 +71,9 @@ WALRecord::WALRecord(span packed) { } Serializer ser(packed.data(), packed.size()); const unsigned unpackedType = ser.GetVarUint(); - if (unpackedType & TxBit) { + if (unpackedType & kTxBit) { inTransaction = true; - type = static_cast(unpackedType ^ TxBit); + type = static_cast(unpackedType ^ kTxBit); } else { inTransaction = false; type = static_cast(unpackedType); @@ -171,9 +173,11 @@ static std::string_view wrecType2Str(WALRecType t) { return ""sv; } -WrSerializer &WALRecord::Dump(WrSerializer &ser, const std::function &cjsonViewer) const { +WrSerializer& WALRecord::Dump(WrSerializer& ser, const std::function& cjsonViewer) const { ser << wrecType2Str(type); - if (inTransaction) ser << " InTransaction"; + if (inTransaction) { + ser << " InTransaction"; + } switch (type) { case WalEmpty: case WalNamespaceAdd: @@ -210,7 +214,7 @@ WrSerializer &WALRecord::Dump(WrSerializer &ser, const std::function &cjsonViewer) const { +void WALRecord::GetJSON(JsonBuilder& jb, const std::function& cjsonViewer) const { jb.Put("type", wrecType2Str(type)); jb.Put("in_transaction", inTransaction); @@ -270,7 +274,7 @@ void WALRecord::GetJSON(JsonBuilder &jb, const std::function(reinterpret_cast(data.data()), data.size())) {} +WALRecord::WALRecord(std::string_view data) : WALRecord(span(reinterpret_cast(data.data()), data.size())) {} SharedWALRecord WALRecord::GetShared(int64_t lsn, int64_t upstreamLSN, std::string_view nsName) const { if (!shared_.packed_) { @@ -278,7 +282,7 @@ SharedWALRecord WALRecord::GetShared(int64_t lsn, int64_t upstreamLSN, std::stri } return shared_; } -SharedWALRecord::SharedWALRecord(int64_t lsn, int64_t originLSN, std::string_view nsName, const WALRecord &rec) { +SharedWALRecord::SharedWALRecord(int64_t lsn, int64_t originLSN, std::string_view nsName, const WALRecord& rec) { const size_t kCapToSizeRelation = 4; WrSerializer ser; ser.PutVarint(lsn); diff --git a/cpp_src/replicator/walrecord.h b/cpp_src/replicator/walrecord.h index cee75b29d..a7bcf3595 100644 --- a/cpp_src/replicator/walrecord.h +++ b/cpp_src/replicator/walrecord.h @@ -12,7 +12,7 @@ namespace reindexer { -enum WALRecType { +enum WALRecType : unsigned { WalEmpty = 0, WalReplState = 1, WalItemUpdate = 2, @@ -36,6 +36,7 @@ enum WALRecType { WalShallowItem = 20, WalDeleteMeta = 21, }; +inline constexpr int format_as(WALRecType v) noexcept { return int(v); } class WrSerializer; class JsonBuilder; @@ -48,7 +49,7 @@ struct SharedWALRecord { p_string nsName, pwalRec; }; SharedWALRecord(intrusive_ptr> packed = nullptr) : packed_(std::move(packed)) {} - SharedWALRecord(int64_t upstreamLSN, int64_t originLSN, std::string_view nsName, const WALRecord &rec); + SharedWALRecord(int64_t upstreamLSN, int64_t originLSN, std::string_view nsName, const WALRecord& rec); Unpacked Unpack(); intrusive_ptr> packed_; @@ -62,9 +63,9 @@ struct WALRecord { explicit WALRecord(WALRecType _type, std::string_view key, std::string_view value) : type(_type), itemMeta{key, value} {} explicit WALRecord(WALRecType _type, std::string_view cjson, int tmVersion, int modifyMode, bool inTx = false) : type(_type), itemModify{cjson, tmVersion, modifyMode}, inTransaction(inTx) {} - WrSerializer &Dump(WrSerializer &ser, const std::function &cjsonViewer) const; - void GetJSON(JsonBuilder &jb, const std::function &cjsonViewer) const; - void Pack(WrSerializer &ser) const; + WrSerializer& Dump(WrSerializer& ser, const std::function& cjsonViewer) const; + void GetJSON(JsonBuilder& jb, const std::function& cjsonViewer) const; + void Pack(WrSerializer& ser) const; SharedWALRecord GetShared(int64_t lsn, int64_t upstreamLSN, std::string_view nsName) const; WALRecType type; @@ -91,6 +92,6 @@ struct WALRecord { struct PackedWALRecord : public h_vector { using h_vector::h_vector; - void Pack(const WALRecord &rec); + void Pack(const WALRecord& rec); }; } // namespace reindexer diff --git a/cpp_src/replicator/walselecter.cc b/cpp_src/replicator/walselecter.cc index 5356051ed..9be4d3248 100644 --- a/cpp_src/replicator/walselecter.cc +++ b/cpp_src/replicator/walselecter.cc @@ -1,5 +1,6 @@ #include "walselecter.h" #include "core/cjson/jsonbuilder.h" +#include "core/formatters/lsn_fmt.h" #include "core/namespace/namespaceimpl.h" #include "core/nsselecter/nsselecter.h" #include "core/rdxcontext.h" @@ -9,11 +10,11 @@ namespace reindexer { const SemVersion kMinUnknownReplSupportRxVersion("2.6.0"); -WALSelecter::WALSelecter(const NamespaceImpl *ns) : ns_(ns) {} +WALSelecter::WALSelecter(const NamespaceImpl* ns) : ns_(ns) {} -void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { +void WALSelecter::operator()(QueryResults& result, SelectCtx& params) { using namespace std::string_view_literals; - const Query &q = params.query; + const Query& q = params.query; int count = q.Limit(); int start = q.Offset(); result.totalCount = 0; @@ -29,7 +30,7 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { for (size_t i = 0; i < q.Entries().Size(); ++i) { q.Entries().Visit( i, - [&lsnIdx, &versionIdx, i] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntry &qe) RX_POST_LMBD_ALWAYS_INLINE { + [&lsnIdx, &versionIdx, i] RX_PRE_LMBD_ALWAYS_INLINE(const QueryEntry& qe) RX_POST_LMBD_ALWAYS_INLINE { if ("#lsn"sv == qe.FieldName()) { lsnIdx = i; } else if ("#slave_version"sv == qe.FieldName()) { @@ -38,29 +39,32 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { throw Error(errLogic, "Unexpected index in WAL select query: %s", qe.FieldName()); } }, - [&q] RX_PRE_LMBD_ALWAYS_INLINE(const auto &) + [&q] RX_PRE_LMBD_ALWAYS_INLINE(const auto&) RX_POST_LMBD_ALWAYS_INLINE { throw Error(errLogic, "Unexpected WAL select query: %s", q.GetSQL()); }); } auto slaveVersion = versionIdx < 0 ? SemVersion() : SemVersion(q.Entries().Get(versionIdx).Values()[0].As()); - auto &lsnEntry = q.Entries().Get(lsnIdx); + auto& lsnEntry = q.Entries().Get(lsnIdx); if (lsnEntry.Values().size() == 1 && lsnEntry.Condition() == CondGt) { lsn_t fromLSN = lsn_t(std::min(lsnEntry.Values()[0].As(), std::numeric_limits::max() - 1)); - if (ns_->wal_.LSNCounter() != (fromLSN.Counter() + 1) && ns_->wal_.is_outdated(fromLSN.Counter() + 1) && count) + if (ns_->wal_.LSNCounter() != (fromLSN.Counter() + 1) && ns_->wal_.is_outdated(fromLSN.Counter() + 1) && count) { throw Error(errOutdatedWAL, "Query to WAL with outdated LSN %ld, LSN counter %ld walSize = %d count = %d", int64_t(fromLSN.Counter()), ns_->wal_.LSNCounter(), ns_->wal_.size(), count); + } const auto walEnd = ns_->wal_.end(); for (auto it = ns_->wal_.upper_bound(fromLSN.Counter()); count && it != walEnd; ++it) { WALRecord rec = *it; switch (rec.type) { case WalItemUpdate: - if (ns_->items_[rec.id].IsFree()) break; + if (ns_->items_[rec.id].IsFree()) { + break; + } if (start) { start--; } else if (count) { // Put as usual ItemRef [[maybe_unused]] const auto iLSN = lsn_t(ns_->items_[rec.id].GetLSN()); - assertf(iLSN.Counter() == (lsn_t(it.GetLSN()).Counter()), "lsn %ld != %ld, ns=%s", iLSN, it.GetLSN(), ns_->name_); + assertf(iLSN.Counter() == (lsn_t(it.GetLSN()).Counter()), "lsn %s != %s, ns=%s", iLSN, it.GetLSN(), ns_->name_); result.Add(ItemRef(rec.id, ns_->items_[rec.id])); count--; } @@ -115,7 +119,7 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { } } else if (lsnEntry.Condition() == CondAny) { if (start == 0 && !(slaveVersion < kMinUnknownReplSupportRxVersion)) { - auto addSpRecord = [&result](const WALRecord &wrec) { + auto addSpRecord = [&result](const WALRecord& wrec) { PackedWALRecord wr; wr.Pack(wrec); PayloadValue val(wr.size(), wr.data()); @@ -130,7 +134,7 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { addSpRecord(wrec); } std::vector metaKeys = ns_->enumMeta(); - for (const auto &key : metaKeys) { + for (const auto& key : metaKeys) { auto metaVal = ns_->getMeta(key); WALRecord wrec(WalPutMeta, key, metaVal); addSpRecord(wrec); @@ -143,7 +147,9 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { } } for (size_t id = 0; count && id < ns_->items_.size(); ++id) { - if (ns_->items_[id].IsFree()) continue; + if (ns_->items_[id].IsFree()) { + continue; + } if (start) { start--; } else if (count) { @@ -158,7 +164,7 @@ void WALSelecter::operator()(QueryResults &result, SelectCtx ¶ms) { putReplState(result); } -void WALSelecter::putReplState(QueryResults &result) { +void WALSelecter::putReplState(QueryResults& result) { WrSerializer ser; JsonBuilder jb(ser); // prepare json with replication state diff --git a/cpp_src/replicator/walselecter.h b/cpp_src/replicator/walselecter.h index 0e2c0ec5f..f0ab3faaf 100644 --- a/cpp_src/replicator/walselecter.h +++ b/cpp_src/replicator/walselecter.h @@ -8,12 +8,12 @@ class RdxContext; struct SelectCtx; class WALSelecter { public: - WALSelecter(const NamespaceImpl *ns); - void operator()(QueryResults &result, SelectCtx ¶ms); + WALSelecter(const NamespaceImpl* ns); + void operator()(QueryResults& result, SelectCtx& params); protected: - void putReplState(QueryResults &result); - const NamespaceImpl *ns_; + void putReplState(QueryResults& result); + const NamespaceImpl* ns_; }; } // namespace reindexer diff --git a/cpp_src/replicator/waltracker.cc b/cpp_src/replicator/waltracker.cc index 3273d8eff..159e9b9e8 100644 --- a/cpp_src/replicator/waltracker.cc +++ b/cpp_src/replicator/waltracker.cc @@ -10,7 +10,7 @@ namespace reindexer { WALTracker::WALTracker(int64_t sz) : walSize_(sz) { logPrintf(LogTrace, "[WALTracker] Create LSN=%ld", lsnCounter_); } -WALTracker::WALTracker(const WALTracker &wal, AsyncStorage &storage) +WALTracker::WALTracker(const WALTracker& wal, AsyncStorage& storage) : records_(wal.records_), lsnCounter_(wal.lsnCounter_), walSize_(wal.walSize_), @@ -18,7 +18,7 @@ WALTracker::WALTracker(const WALTracker &wal, AsyncStorage &storage) heapSize_(wal.heapSize_), storage_(&storage) {} -int64_t WALTracker::Add(const WALRecord &rec, lsn_t oldLsn) { +int64_t WALTracker::Add(const WALRecord& rec, lsn_t oldLsn) { int64_t lsn = lsnCounter_++; if (lsnCounter_ > 1 && walOffset_ == (lsnCounter_ - 1) % walSize_) { walOffset_ = lsnCounter_ % walSize_; @@ -34,7 +34,7 @@ int64_t WALTracker::Add(const WALRecord &rec, lsn_t oldLsn) { return lsn; } -bool WALTracker::Set(const WALRecord &rec, int64_t lsn) { +bool WALTracker::Set(const WALRecord& rec, int64_t lsn) { if (!available(lsn)) { return false; } @@ -71,7 +71,7 @@ bool WALTracker::Resize(int64_t sz) { return true; } -void WALTracker::Init(int64_t sz, int64_t minLSN, int64_t maxLSN, AsyncStorage &storage) { +void WALTracker::Init(int64_t sz, int64_t minLSN, int64_t maxLSN, AsyncStorage& storage) { logPrintf(LogTrace, "WALTracker::Init minLSN=%ld, maxLSN=%ld, size=%ld", minLSN, maxLSN, sz); storage_ = &storage; @@ -80,12 +80,12 @@ void WALTracker::Init(int64_t sz, int64_t minLSN, int64_t maxLSN, AsyncStorage & // new table initPositions(sz, minLSN, maxLSN); // Fill records from storage - for (auto &rec : data) { + for (auto& rec : data) { Set(WALRecord(std::string_view(rec.second)), rec.first); } } -void WALTracker::put(int64_t lsn, const WALRecord &rec) { +void WALTracker::put(int64_t lsn, const WALRecord& rec) { int64_t pos = lsn % walSize_; if (pos >= int64_t(records_.size())) { records_.resize(uint64_t(pos + 1)); @@ -103,17 +103,21 @@ void WALTracker::writeToStorage(int64_t lsn) { key << kStorageWALPrefix; key.PutUInt32(pos); data.PutUInt64(lsn); - data.Write(std::string_view(reinterpret_cast(records_[pos].data()), records_[pos].size())); - if (storage_ && storage_->IsValid()) storage_->WriteSync(StorageOpts(), key.Slice(), data.Slice()); + data.Write(std::string_view(reinterpret_cast(records_[pos].data()), records_[pos].size())); + if (storage_ && storage_->IsValid()) { + storage_->WriteSync(StorageOpts(), key.Slice(), data.Slice()); + } } -std::vector> WALTracker::readFromStorage(int64_t &maxLSN) { +std::vector> WALTracker::readFromStorage(int64_t& maxLSN) { std::vector> data; StorageOpts opts; opts.FillCache(false); - if (!storage_ || !storage_->IsValid()) return data; + if (!storage_ || !storage_->IsValid()) { + return data; + } auto dbIter = storage_->GetCursor(opts); for (dbIter->Seek(kStorageWALPrefix); @@ -122,7 +126,7 @@ std::vector> WALTracker::readFromStorage(int64_t std::string_view dataSlice = dbIter->Value(); if (dataSlice.size() >= sizeof(int64_t)) { // Read LSN - const int64_t lsn = *reinterpret_cast(dataSlice.data()); + const int64_t lsn = *reinterpret_cast(dataSlice.data()); assertrx(lsn >= 0); maxLSN = std::max(maxLSN, lsn); dataSlice = dataSlice.substr(sizeof(lsn)); diff --git a/cpp_src/replicator/waltracker.h b/cpp_src/replicator/waltracker.h index 772a34f48..13f3b5497 100644 --- a/cpp_src/replicator/waltracker.h +++ b/cpp_src/replicator/waltracker.h @@ -14,24 +14,24 @@ class AsyncStorage; class WALTracker { public: explicit WALTracker(int64_t sz); - WALTracker(const WALTracker &) = delete; - WALTracker(const WALTracker &wal, AsyncStorage &storage); + WALTracker(const WALTracker&) = delete; + WALTracker(const WALTracker& wal, AsyncStorage& storage); /// Initialize WAL tracker. /// @param sz - Max WAL size /// @param minLSN - Min available LSN number /// @param maxLSN - Current LSN counter value /// @param storage - Storage object for store WAL records - void Init(int64_t sz, int64_t minLSN, int64_t maxLSN, AsyncStorage &storage); + void Init(int64_t sz, int64_t minLSN, int64_t maxLSN, AsyncStorage& storage); /// Add new record to WAL tracker /// @param rec - Record to be added /// @param oldLsn - Optional, previous LSN value of changed object /// @return LSN value of record - int64_t Add(const WALRecord &rec, lsn_t oldLsn = lsn_t()); + int64_t Add(const WALRecord& rec, lsn_t oldLsn = lsn_t()); /// Set record in WAL tracker /// @param rec - Record to be added /// @param lsn - LSN value /// @return true if set successful, false, if lsn is outdated - bool Set(const WALRecord &rec, int64_t lsn); + bool Set(const WALRecord& rec, int64_t lsn); /// Get current LSN counter value /// @return current LSN counter value int64_t LSNCounter() const { return lsnCounter_; } @@ -46,11 +46,11 @@ class WALTracker { /// Iterator for WAL records class iterator { public: - iterator &operator++() noexcept { + iterator& operator++() noexcept { ++idx_; return *this; } - bool operator!=(const iterator &other) const noexcept { return idx_ != other.idx_; } + bool operator!=(const iterator& other) const noexcept { return idx_ != other.idx_; } WALRecord operator*() const { assertf(idx_ % wt_->walSize_ < int(wt_->records_.size()), "idx=%d,wt_->records_.size()=%d,lsnCounter=%d", idx_, wt_->records_.size(), wt_->lsnCounter_); @@ -60,7 +60,7 @@ class WALTracker { span GetRaw() const noexcept { return wt_->records_[idx_ % wt_->walSize_]; } int64_t GetLSN() const noexcept { return idx_; } int64_t idx_; - const WALTracker *wt_; + const WALTracker* wt_; }; /// Get end iterator @@ -96,13 +96,13 @@ class WALTracker { /// put WAL record into lsn position, grow ring buffer, if neccessary /// @param lsn LSN value /// @param rec - Record to be added - void put(int64_t lsn, const WALRecord &rec); + void put(int64_t lsn, const WALRecord& rec); /// check if lsn is available. e.g. in range of ring buffer bool available(int64_t lsn) const { return lsn < lsnCounter_ && lsnCounter_ - lsn <= size(); } /// flushes lsn value to storage /// @param lsn - lsn value void writeToStorage(int64_t lsn); - std::vector> readFromStorage(int64_t &maxLsn); + std::vector> readFromStorage(int64_t& maxLsn); void initPositions(int64_t sz, int64_t minLSN, int64_t maxLSN); /// Ring buffer of WAL records @@ -116,7 +116,7 @@ class WALTracker { /// Cached heap size of WAL object size_t heapSize_ = 0; - AsyncStorage *storage_ = nullptr; + AsyncStorage* storage_ = nullptr; }; } // namespace reindexer diff --git a/cpp_src/server/cbinding/server_c.cc b/cpp_src/server/cbinding/server_c.cc index 252a4ca0a..858b6f494 100644 --- a/cpp_src/server/cbinding/server_c.cc +++ b/cpp_src/server/cbinding/server_c.cc @@ -42,7 +42,9 @@ reindexer_error start_reindexer_server(uintptr_t psvc, reindexer_string _config) auto svc = reinterpret_cast(psvc); if (svc) { err = svc->InitFromYAML(str2c(_config)); - if (!err.ok()) return error2c(err); + if (!err.ok()) { + return error2c(err); + } err = (svc->Start() == 0 ? Error{} : Error(errLogic, "server startup error")); } return error2c(err); diff --git a/cpp_src/server/config.cc b/cpp_src/server/config.cc index ae1e94172..4bf8b12db 100644 --- a/cpp_src/server/config.cc +++ b/cpp_src/server/config.cc @@ -54,29 +54,29 @@ void ServerConfig::Reset() { AllocatorCachePart = -1; } -reindexer::Error ServerConfig::ParseYaml(const std::string &yaml) { +reindexer::Error ServerConfig::ParseYaml(const std::string& yaml) { Error err; try { YAML::Node root = YAML::Load(yaml); err = fromYaml(root); - } catch (const YAML::Exception &ex) { + } catch (const YAML::Exception& ex) { err = Error(errParams, "Error with config string. Reason: '%s'", ex.what()); } return err; } -Error ServerConfig::ParseFile(const std::string &filePath) { +Error ServerConfig::ParseFile(const std::string& filePath) { Error err; try { YAML::Node root = YAML::LoadFile(filePath); err = fromYaml(root); - } catch (const YAML::Exception &ex) { + } catch (const YAML::Exception& ex) { err = Error(errParams, "Error with config file '%s'. Reason: %s", filePath, ex.what()); } return err; } -Error ServerConfig::ParseCmd(int argc, char *argv[]) { +Error ServerConfig::ParseCmd(int argc, char* argv[]) { using reindexer::fs::GetDirPath; #ifndef LINK_RESOURCES WebRoot = GetDirPath(argv[0]); @@ -93,7 +93,7 @@ Error ServerConfig::ParseCmd(int argc, char *argv[]) { args::ValueFlag storageF(dbGroup, "PATH", "path to 'reindexer' storage", {'s', "db"}, StoragePath, args::Options::Single); auto availableStorageTypes = reindexer::datastorage::StorageFactory::getAvailableTypes(); std::string availabledStorages; - for (const auto &type : availableStorageTypes) { + for (const auto& type : availableStorageTypes) { if (!availabledStorages.empty()) { availabledStorages.append(", "); } @@ -192,72 +192,152 @@ Error ServerConfig::ParseCmd(int argc, char *argv[]) { try { parser.ParseCLI(argc, argv); - } catch (const args::Help &) { + } catch (const args::Help&) { return Error(errLogic, parser.Help()); - } catch (const args::Error &e) { + } catch (const args::Error& e) { return Error(errParams, "%s\n%s", e.what(), parser.Help()); } if (configF) { auto err = ParseFile(args::get(configF)); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } - if (storageF) StoragePath = args::get(storageF); - if (storageEngineF) StorageEngine = args::get(storageEngineF); - if (startWithErrorsF) StartWithErrors = args::get(startWithErrorsF); - if (autorepairF) Autorepair = args::get(autorepairF); - if (disableNamespaceLeakF) AllowNamespaceLeak = !args::get(disableNamespaceLeakF); - if (logLevelF) LogLevel = args::get(logLevelF); - if (httpAddrF) HTTPAddr = args::get(httpAddrF); - if (rpcAddrF) RPCAddr = args::get(rpcAddrF); + if (storageF) { + StoragePath = args::get(storageF); + } + if (storageEngineF) { + StorageEngine = args::get(storageEngineF); + } + if (startWithErrorsF) { + StartWithErrors = args::get(startWithErrorsF); + } + if (autorepairF) { + Autorepair = args::get(autorepairF); + } + if (disableNamespaceLeakF) { + AllowNamespaceLeak = !args::get(disableNamespaceLeakF); + } + if (logLevelF) { + LogLevel = args::get(logLevelF); + } + if (httpAddrF) { + HTTPAddr = args::get(httpAddrF); + } + if (rpcAddrF) { + RPCAddr = args::get(rpcAddrF); + } - if (rpcThreadingModeF) RPCThreadingMode = args::get(rpcThreadingModeF); - if (httpThreadingModeF) HttpThreadingMode = args::get(httpThreadingModeF); - if (webRootF) WebRoot = args::get(webRootF); - if (MaxHttpReqSizeF) MaxHttpReqSize = args::get(MaxHttpReqSizeF); + if (rpcThreadingModeF) { + RPCThreadingMode = args::get(rpcThreadingModeF); + } + if (httpThreadingModeF) { + HttpThreadingMode = args::get(httpThreadingModeF); + } + if (webRootF) { + WebRoot = args::get(webRootF); + } + if (MaxHttpReqSizeF) { + MaxHttpReqSize = args::get(MaxHttpReqSizeF); + } #ifndef _WIN32 - if (rpcUnixAddrF) RPCUnixAddr = args::get(rpcUnixAddrF); - if (rpcUnixThreadingModeF) RPCUnixThreadingMode = args::get(rpcUnixThreadingModeF); - if (userF) UserName = args::get(userF); - if (daemonizeF) Daemonize = args::get(daemonizeF); - if (daemonPidFileF) DaemonPidFile = args::get(daemonPidFileF); + if (rpcUnixAddrF) { + RPCUnixAddr = args::get(rpcUnixAddrF); + } + if (rpcUnixThreadingModeF) { + RPCUnixThreadingMode = args::get(rpcUnixThreadingModeF); + } + if (userF) { + UserName = args::get(userF); + } + if (daemonizeF) { + Daemonize = args::get(daemonizeF); + } + if (daemonPidFileF) { + DaemonPidFile = args::get(daemonPidFileF); + } #else - if (installF) InstallSvc = args::get(installF); - if (removeF) RemoveSvc = args::get(removeF); - if (serviceF) SvcMode = args::get(serviceF); + if (installF) { + InstallSvc = args::get(installF); + } + if (removeF) { + RemoveSvc = args::get(removeF); + } + if (serviceF) { + SvcMode = args::get(serviceF); + } #endif #if REINDEX_WITH_GPERFTOOLS - if (allocatorCacheLimit) AllocatorCacheLimit = args::get(allocatorCacheLimit); - if (allocatorCachePart) AllocatorCachePart = args::get(allocatorCachePart); + if (allocatorCacheLimit) { + AllocatorCacheLimit = args::get(allocatorCacheLimit); + } + if (allocatorCachePart) { + AllocatorCachePart = args::get(allocatorCachePart); + } #endif - if (securityF) EnableSecurity = args::get(securityF); + if (securityF) { + EnableSecurity = args::get(securityF); + } #if defined(WITH_GRPC) - if (grpcF) EnableGRPC = args::get(grpcF); - if (grpcAddrF) GRPCAddr = args::get(grpcAddrF); + if (grpcF) { + EnableGRPC = args::get(grpcF); + } + if (grpcAddrF) { + GRPCAddr = args::get(grpcAddrF); + } #endif - if (serverLogF) ServerLog = args::get(serverLogF); - if (coreLogF) CoreLog = args::get(coreLogF); - if (httpLogF) HttpLog = args::get(httpLogF); - if (rpcLogF) RpcLog = args::get(rpcLogF); - if (pprofF) DebugPprof = args::get(pprofF); - if (prometheusF) EnablePrometheus = args::get(prometheusF); - if (prometheusPeriodF) PrometheusCollectPeriod = std::chrono::milliseconds(args::get(prometheusPeriodF)); - if (clientsConnectionsStatF) EnableConnectionsStats = args::get(clientsConnectionsStatF); - if (httpReadTimeoutF) HttpReadTimeout = std::chrono::seconds(args::get(httpReadTimeoutF)); - if (httpWriteTimeoutF) HttpWriteTimeout = std::chrono::seconds(args::get(httpWriteTimeoutF)); - if (logAllocsF) DebugAllocs = args::get(logAllocsF); - if (txIdleTimeoutF) TxIdleTimeout = std::chrono::seconds(args::get(txIdleTimeoutF)); - if (rpcQrIdleTimeoutF) RPCQrIdleTimeout = std::chrono::seconds(args::get(rpcQrIdleTimeoutF)); - if (maxUpdatesSizeF) MaxUpdatesSize = args::get(maxUpdatesSizeF); + if (serverLogF) { + ServerLog = args::get(serverLogF); + } + if (coreLogF) { + CoreLog = args::get(coreLogF); + } + if (httpLogF) { + HttpLog = args::get(httpLogF); + } + if (rpcLogF) { + RpcLog = args::get(rpcLogF); + } + if (pprofF) { + DebugPprof = args::get(pprofF); + } + if (prometheusF) { + EnablePrometheus = args::get(prometheusF); + } + if (prometheusPeriodF) { + PrometheusCollectPeriod = std::chrono::milliseconds(args::get(prometheusPeriodF)); + } + if (clientsConnectionsStatF) { + EnableConnectionsStats = args::get(clientsConnectionsStatF); + } + if (httpReadTimeoutF) { + HttpReadTimeout = std::chrono::seconds(args::get(httpReadTimeoutF)); + } + if (httpWriteTimeoutF) { + HttpWriteTimeout = std::chrono::seconds(args::get(httpWriteTimeoutF)); + } + if (logAllocsF) { + DebugAllocs = args::get(logAllocsF); + } + if (txIdleTimeoutF) { + TxIdleTimeout = std::chrono::seconds(args::get(txIdleTimeoutF)); + } + if (rpcQrIdleTimeoutF) { + RPCQrIdleTimeout = std::chrono::seconds(args::get(rpcQrIdleTimeoutF)); + } + if (maxUpdatesSizeF) { + MaxUpdatesSize = args::get(maxUpdatesSizeF); + } return {}; } -reindexer::Error ServerConfig::fromYaml(YAML::Node &root) { +reindexer::Error ServerConfig::fromYaml(YAML::Node& root) { try { AllowNamespaceLeak = root["db"]["ns_leak"].as(AllowNamespaceLeak); StoragePath = root["storage"]["path"].as(StoragePath); @@ -298,7 +378,7 @@ reindexer::Error ServerConfig::fromYaml(YAML::Node &root) { DebugAllocs = root["debug"]["allocs"].as(DebugAllocs); DebugPprof = root["debug"]["pprof"].as(DebugPprof); - } catch (const YAML::Exception &ex) { + } catch (const YAML::Exception& ex) { return Error(errParams, "Unable to parse YML server config: %s", ex.what()); } return {}; diff --git a/cpp_src/server/dbmanager.cc b/cpp_src/server/dbmanager.cc index 8ec1e6cae..1c10d3b23 100644 --- a/cpp_src/server/dbmanager.cc +++ b/cpp_src/server/dbmanager.cc @@ -18,10 +18,10 @@ using namespace std::string_view_literals; const std::string kUsersYAMLFilename = "users.yml"; const std::string kUsersJSONFilename = "users.json"; -DBManager::DBManager(const std::string &dbpath, bool noSecurity, IClientsStats *clientsStats) +DBManager::DBManager(const std::string& dbpath, bool noSecurity, IClientsStats* clientsStats) : dbpath_(dbpath), noSecurity_(noSecurity), storageType_(datastorage::StorageType::LevelDB), clientsStats_(clientsStats) {} -Error DBManager::Init(const std::string &storageEngine, bool allowDBErrors, bool withAutorepair) { +Error DBManager::Init(const std::string& storageEngine, bool allowDBErrors, bool withAutorepair) { if (!noSecurity_) { auto status = readUsers(); if (!status.ok()) { @@ -36,11 +36,11 @@ Error DBManager::Init(const std::string &storageEngine, bool allowDBErrors, bool try { storageType_ = datastorage::StorageTypeFromString(storageEngine); - } catch (const Error &err) { + } catch (const Error& err) { return err; } - for (auto &de : foundDb) { + for (auto& de : foundDb) { if (de.isDir && validateObjectName(de.name, false)) { auto status = loadOrCreateDatabase(de.name, allowDBErrors, withAutorepair); if (!status.ok()) { @@ -56,13 +56,13 @@ Error DBManager::Init(const std::string &storageEngine, bool allowDBErrors, bool return {}; } -Error DBManager::OpenDatabase(const std::string &dbName, AuthContext &auth, bool canCreate) { +Error DBManager::OpenDatabase(const std::string& dbName, AuthContext& auth, bool canCreate) { RdxContext dummyCtx; auto status = Login(dbName, auth); if (!status.ok()) { return status; } - auto dbConnect = [&auth](Reindexer *db) { + auto dbConnect = [&auth](Reindexer* db) { if (auth.checkClusterID_) { return db->Connect(std::string(), ConnectOpts().WithExpectedClusterID(auth.expectedClusterID_)); } @@ -73,7 +73,9 @@ Error DBManager::OpenDatabase(const std::string &dbName, AuthContext &auth, bool auto it = dbs_.find(dbName); if (it != dbs_.end()) { status = dbConnect(it->second.get()); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } auth.db_ = it->second.get(); return errOK; } @@ -93,7 +95,9 @@ Error DBManager::OpenDatabase(const std::string &dbName, AuthContext &auth, bool it = dbs_.find(dbName); if (it != dbs_.end()) { status = dbConnect(it->second.get()); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } auth.db_ = it->second.get(); return errOK; } @@ -109,7 +113,7 @@ Error DBManager::OpenDatabase(const std::string &dbName, AuthContext &auth, bool return errOK; } -Error DBManager::loadOrCreateDatabase(const std::string &dbName, bool allowDBErrors, bool withAutorepair, const AuthContext &auth) { +Error DBManager::loadOrCreateDatabase(const std::string& dbName, bool allowDBErrors, bool withAutorepair, const AuthContext& auth) { std::string storagePath = !dbpath_.empty() ? fs::JoinPath(dbpath_, dbName) : ""; logPrintf(LogInfo, "Loading database %s", dbName); @@ -135,15 +139,15 @@ Error DBManager::loadOrCreateDatabase(const std::string &dbName, bool allowDBErr return status; } -Error DBManager::DropDatabase(AuthContext &auth) { +Error DBManager::DropDatabase(AuthContext& auth) { { - Reindexer *db = nullptr; + Reindexer* db = nullptr; auto status = auth.GetDB(kRoleOwner, &db); if (!status.ok()) { return status; } } - const std::string &dbName = auth.dbName_; + const std::string& dbName = auth.dbName_; std::unique_lock lck(mtx_); auto it = dbs_.find(dbName); @@ -162,11 +166,13 @@ std::vector DBManager::EnumDatabases() { shared_lock lck(mtx_); dbs.reserve(dbs_.size()); - for (const auto &it : dbs_) dbs.emplace_back(it.first); + for (const auto& it : dbs_) { + dbs.emplace_back(it.first); + } return dbs; } -Error DBManager::Login(const std::string &dbName, AuthContext &auth) { +Error DBManager::Login(const std::string& dbName, AuthContext& auth) { if (kRoleSystem == auth.role_) { auth.dbName_ = dbName; return {}; @@ -198,7 +204,7 @@ Error DBManager::Login(const std::string &dbName, AuthContext &auth) { auth.role_ = kRoleNone; if (!dbName.empty()) { - const UserRecord &urec = it->second; + const UserRecord& urec = it->second; auto dbIt = urec.roles.find("*"); if (dbIt != urec.roles.end()) { @@ -211,7 +217,6 @@ Error DBManager::Login(const std::string &dbName, AuthContext &auth) { } } auth.dbName_ = dbName; - // logPrintf(LogInfo, "Authorized user '%s', to db '%s', role=%s", auth.login_, dbName, UserRoleName(auth.role_)); return {}; } @@ -232,12 +237,14 @@ Error DBManager::readUsers() noexcept { Error DBManager::readUsersYAML() noexcept { std::string content; int res = fs::ReadFile(fs::JoinPath(dbpath_, kUsersYAMLFilename), content); - if (res < 0) return Error(errNotFound, "Can't read '%s' file", kUsersYAMLFilename); + if (res < 0) { + return Error(errNotFound, "Can't read '%s' file", kUsersYAMLFilename); + } try { YAML::ScannerOpts opts; opts.disableAnchors = true; YAML::Node root = YAML::Load(content, opts); - for (const auto &user : root) { + for (const auto& user : root) { UserRecord urec; urec.login = user.first.as(); auto userNode = user.second; @@ -248,11 +255,11 @@ Error DBManager::readUsersYAML() noexcept { } auto userRoles = userNode["roles"]; if (userRoles.IsMap()) { - for (const auto &role : userRoles) { + for (const auto& role : userRoles) { std::string db(role.first.as()); try { urec.roles.emplace(db, userRoleFromString(role.second.as())); - } catch (const Error &err) { + } catch (const Error& err) { logPrintf(LogWarning, "Skipping user '%s' for db '%s': ", urec.login, db, err.what()); } } @@ -265,7 +272,7 @@ Error DBManager::readUsersYAML() noexcept { logPrintf(LogWarning, "Skipping user '%s': no 'roles' node found", urec.login); } } - } catch (const YAML::Exception &ex) { + } catch (const YAML::Exception& ex) { return Error(errParseJson, "Users: %s", ex.what()); } return errOK; @@ -274,12 +281,14 @@ Error DBManager::readUsersYAML() noexcept { Error DBManager::readUsersJSON() noexcept { std::string content; int res = fs::ReadFile(fs::JoinPath(dbpath_, kUsersJSONFilename), content); - if (res < 0) return Error(errNotFound, "Can't read '%s' file", kUsersJSONFilename); + if (res < 0) { + return Error(errNotFound, "Can't read '%s' file", kUsersJSONFilename); + } try { gason::JsonParser parser; auto root = parser.Parse(giftStr(content)); - for (auto &userNode : root) { + for (auto& userNode : root) { UserRecord urec; urec.login = std::string(userNode.key); auto err = ParseMd5CryptString(userNode["hash"].As(), urec.hash, urec.salt); @@ -287,12 +296,12 @@ Error DBManager::readUsersJSON() noexcept { logPrintf(LogWarning, "Hash parsing error for user '%s': %s", urec.login, err.what()); continue; } - for (auto &roleNode : userNode["roles"]) { + for (auto& roleNode : userNode["roles"]) { std::string db(roleNode.key); try { UserRole role = userRoleFromString(roleNode.As()); urec.roles.emplace(db, role); - } catch (const Error &err) { + } catch (const Error& err) { logPrintf(LogWarning, "Skipping user '%s' for db '%s': ", urec.login, db, err.what()); } } @@ -302,7 +311,7 @@ Error DBManager::readUsersJSON() noexcept { users_.emplace(urec.login, urec); } } - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return Error(errParseJson, "Users: %s", ex.what()); } return errOK; diff --git a/cpp_src/server/dbmanager.h b/cpp_src/server/dbmanager.h index 8054f5214..1fc13b528 100644 --- a/cpp_src/server/dbmanager.h +++ b/cpp_src/server/dbmanager.h @@ -56,7 +56,7 @@ class AuthContext { /// Construct context with user credentials /// @param login - User's login /// @param password - User's password - AuthContext(const std::string &login, const std::string &password) : login_(login), password_(password) {} + AuthContext(const std::string& login, const std::string& password) : login_(login), password_(password) {} /// Set expected master's replication clusted ID /// @param clusterID - Expected cluster ID value void SetExpectedClusterID(int clusterID) noexcept { @@ -67,10 +67,11 @@ class AuthContext { /// @param role - Requested role one of UserRole enum /// @param ret - Pointer to returned database pointer /// @return Error - error object - Error GetDB(UserRole role, Reindexer **ret) noexcept { - if (role > role_) + Error GetDB(UserRole role, Reindexer** ret) noexcept { + if (role > role_) { return Error(errForbidden, "Forbidden: need role %s of db '%s' user '%s' have role=%s", UserRoleName(role), dbName_, login_, UserRoleName(role_)); + } *ret = db_; return errOK; } @@ -84,10 +85,10 @@ class AuthContext { bool HaveDB() const noexcept { return db_ != nullptr; } /// Get user login /// @return user login - const std::string &Login() const noexcept { return login_; } + const std::string& Login() const noexcept { return login_; } /// Get database name /// @return db name - const std::string &DBName() const noexcept { return dbName_; } + const std::string& DBName() const noexcept { return dbName_; } /// Get user rights /// @return user rights UserRole UserRights() const noexcept { return role_; } @@ -101,7 +102,7 @@ class AuthContext { std::string dbName_; int expectedClusterID_ = -1; bool checkClusterID_ = false; - Reindexer *db_ = nullptr; + Reindexer* db_ = nullptr; }; static inline AuthContext MakeSystemAuthContext() { return AuthContext(kRoleSystem); } @@ -113,7 +114,7 @@ class DBManager { /// @param dbpath - path to database on file system /// @param noSecurity - if true, then disable all security validations and users authentication /// @param clientsStats - object for receiving clients statistics - DBManager(const std::string &dbpath, bool noSecurity, IClientsStats *clientsStats = nullptr); + DBManager(const std::string& dbpath, bool noSecurity, IClientsStats* clientsStats = nullptr); /// Initialize database: /// Read all found databases to RAM /// Read user's database @@ -121,22 +122,22 @@ class DBManager { /// @param allowDBErrors - true: Ignore errors during existing DBs load; false: Return error if error occures during DBs load /// @param withAutorepair - true: Enable storage autorepair feature for this DB; false: Disable storage autorepair feature for this DB /// @return Error - error object - Error Init(const std::string &storageEngine, bool allowDBErrors, bool withAutorepair); + Error Init(const std::string& storageEngine, bool allowDBErrors, bool withAutorepair); /// Authenticate user, and grant roles to database with specified dbName /// @param dbName - database name. Can be empty. /// @param auth - AuthContext with user credentials /// @return Error - error object - Error Login(const std::string &dbName, AuthContext &auth); + Error Login(const std::string& dbName, AuthContext& auth); /// Open database and authentificate user /// @param dbName - database name, Can't be empty /// @param auth - AuthContext filled with user credentials or already authorized AuthContext /// @param canCreate - true: Create database, if not exists; false: return error, if database not exists /// @return Error - error object - Error OpenDatabase(const std::string &dbName, AuthContext &auth, bool canCreate); + Error OpenDatabase(const std::string& dbName, AuthContext& auth, bool canCreate); /// Drop database from disk storage and memory. Reindexer DB object will be destroyed /// @param auth - Authorized AuthContext, with valid Reindexer DB object and reasonale role /// @return Error - error object - Error DropDatabase(AuthContext &auth); + Error DropDatabase(AuthContext& auth); /// Check if security disabled /// @return bool - true: security checks are disabled; false: security checks are enabled bool IsNoSecurity() { return noSecurity_; } @@ -151,7 +152,7 @@ class DBManager { Error readUsersJSON() noexcept; Error createDefaultUsersYAML() noexcept; static UserRole userRoleFromString(std::string_view strRole); - Error loadOrCreateDatabase(const std::string &name, bool allowDBErrors, bool withAutorepair, const AuthContext &auth = AuthContext()); + Error loadOrCreateDatabase(const std::string& name, bool allowDBErrors, bool withAutorepair, const AuthContext& auth = AuthContext()); std::unordered_map, nocase_hash_str, nocase_equal_str> dbs_; std::unordered_map users_; @@ -160,7 +161,7 @@ class DBManager { bool noSecurity_; datastorage::StorageType storageType_; - IClientsStats *clientsStats_ = nullptr; + IClientsStats* clientsStats_ = nullptr; }; } // namespace reindexer_server diff --git a/cpp_src/server/grpc/reindexerservice.cc b/cpp_src/server/grpc/reindexerservice.cc index 3347373b8..adae54294 100644 --- a/cpp_src/server/grpc/reindexerservice.cc +++ b/cpp_src/server/grpc/reindexerservice.cc @@ -474,32 +474,44 @@ Error ReindexerService::buildItems(WrSerializer& wrser, const reindexer::QueryRe for (auto& item : qr) { array.Raw(nullptr, ""); status = item.GetJSON(wrser, false); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } } if (qr.GetAggregationResults().size() > 0) { status = buildAggregation(builder, wrser, qr, opts); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } break; } case EncodingType::MSGPACK: { int fields = 0; bool withItems = (qr.Count() > 0); - if (withItems) ++fields; + if (withItems) { + ++fields; + } bool withAggregation = (qr.GetAggregationResults().size() > 0); - if (withAggregation) ++fields; + if (withAggregation) { + ++fields; + } MsgPackBuilder builder(wrser, ObjType::TypeObject, fields); if (withItems) { MsgPackBuilder array = builder.Array("items", qr.Count()); for (auto& item : qr) { status = item.GetMsgPack(wrser, false); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } } if (withAggregation) { status = buildAggregation(builder, wrser, qr, opts); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } break; } @@ -508,7 +520,9 @@ Error ReindexerService::buildItems(WrSerializer& wrser, const reindexer::QueryRe ProtobufBuilder array = builder.Array("items"); for (auto& it : qr) { status = it.GetProtobuf(wrser, false); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } break; } @@ -518,12 +532,16 @@ Error ReindexerService::buildItems(WrSerializer& wrser, const reindexer::QueryRe } for (auto& item : qr) { status = packCJSONItem(wrser, item, opts); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } auto jIt = item.GetJoined(); if (opts.withjoineditems() && jIt.getJoinedItemsCount() > 0) { wrser.PutVarUint(jIt.getJoinedItemsCount() > 0 ? jIt.getJoinedFieldsCount() : 0); - if (jIt.getJoinedItemsCount() == 0) continue; + if (jIt.getJoinedItemsCount() == 0) { + continue; + } size_t joinedField = item.qr_->joined_.size(); for (size_t ns = 0; ns < item.GetItemRef().Nsid(); ++ns) { @@ -531,13 +549,17 @@ Error ReindexerService::buildItems(WrSerializer& wrser, const reindexer::QueryRe } for (auto it = jIt.begin(); it != jIt.end(); ++it, ++joinedField) { wrser.PutVarUint(it.ItemsCount()); - if (it.ItemsCount() == 0) continue; + if (it.ItemsCount() == 0) { + continue; + } QueryResults jqr = it.ToQueryResults(); jqr.addNSContext(qr.getPayloadType(joinedField), qr.getTagsMatcher(joinedField), qr.getFieldsFilter(joinedField), qr.getSchema(joinedField)); for (size_t i = 0; i < jqr.Count(); i++) { status = packCJSONItem(wrser, jqr.begin() + i, opts); - if (!status.ok()) return status; + if (!status.ok()) { + return status; + } } } } @@ -979,7 +1001,7 @@ Error ReindexerService::execSqlQueryByType(QueryResults& res, const SelectSqlReq break; } default: - return Error(errParams, "unknown query type %d", q.Type()); + return Error(errParams, "unknown query type %d", int(q.Type())); } reindexer::Reindexer* rx = nullptr; auto err = getDB(request.dbname(), requiredRole, &rx); @@ -1001,7 +1023,7 @@ Error ReindexerService::execSqlQueryByType(QueryResults& res, const SelectSqlReq return rx->TruncateNamespace(q.NsName()); } default: - return Error(errParams, "unknown query type %d", q.Type()); + return Error(errParams, "unknown query type %d", int(q.Type())); } } catch (Error& e) { return e; diff --git a/cpp_src/server/httpserver.cc b/cpp_src/server/httpserver.cc index 458a396d8..bd59f8a18 100644 --- a/cpp_src/server/httpserver.cc +++ b/cpp_src/server/httpserver.cc @@ -40,8 +40,8 @@ namespace reindexer_server { constexpr size_t kTxIdLen = 20; constexpr auto kTxDeadlineCheckPeriod = std::chrono::seconds(1); -HTTPServer::HTTPServer(DBManager &dbMgr, LoggerWrapper &logger, const ServerConfig &serverConfig, Prometheus *prometheus, - IStatsWatcher *statsWatcher) +HTTPServer::HTTPServer(DBManager& dbMgr, LoggerWrapper& logger, const ServerConfig& serverConfig, Prometheus* prometheus, + IStatsWatcher* statsWatcher) : dbMgr_(dbMgr), serverConfig_(serverConfig), prometheus_(prometheus), @@ -50,7 +50,7 @@ HTTPServer::HTTPServer(DBManager &dbMgr, LoggerWrapper &logger, const ServerConf logger_(logger), startTs_(system_clock_w::now()) {} -Error HTTPServer::execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults &res, http::Context &ctx) { +Error HTTPServer::execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults& res, http::Context& ctx) { const auto q = reindexer::Query::FromSQL(sqlQuery); switch (q.Type()) { case QuerySelect: @@ -65,7 +65,7 @@ Error HTTPServer::execSqlQueryByType(std::string_view sqlQuery, reindexer::Query throw Error(errParams, "unknown query type %d", q.Type()); } -int HTTPServer::GetSQLQuery(http::Context &ctx) { +int HTTPServer::GetSQLQuery(http::Context& ctx) { std::string sqlQuery = urldecode2(ctx.request->params.Get("q")); std::string_view limitParam = ctx.request->params.Get("limit"); @@ -88,7 +88,7 @@ int HTTPServer::GetSQLQuery(http::Context &ctx) { return queryResults(ctx, res, true, limit, offset); } -int HTTPServer::GetSQLSuggest(http::Context &ctx) { +int HTTPServer::GetSQLSuggest(http::Context& ctx) { std::string sqlQuery = urldecode2(ctx.request->params.Get("q")); if (sqlQuery.empty()) { return jsonStatus(ctx, http::HttpStatus(http::StatusBadRequest, "Missing `q` parameter")); @@ -128,14 +128,16 @@ int HTTPServer::GetSQLSuggest(http::Context &ctx) { WrSerializer ser(ctx.writer->GetChunk()); reindexer::JsonBuilder builder(ser); auto node = builder.Array("suggests"); - for (auto &suggest : suggestions) node.Put(nullptr, suggest); + for (auto& suggest : suggestions) { + node.Put(nullptr, suggest); + } node.End(); builder.End(); return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::PostSQLQuery(http::Context &ctx) { +int HTTPServer::PostSQLQuery(http::Context& ctx) { reindexer::QueryResults res; std::string sqlQuery = ctx.body->Read(); if (!sqlQuery.length()) { @@ -149,7 +151,7 @@ int HTTPServer::PostSQLQuery(http::Context &ctx) { return queryResults(ctx, res, true); } -int HTTPServer::PostQuery(http::Context &ctx) { +int HTTPServer::PostQuery(http::Context& ctx) { auto db = getDB(ctx); reindexer::QueryResults res; std::string dsl = ctx.body->Read(); @@ -168,7 +170,7 @@ int HTTPServer::PostQuery(http::Context &ctx) { return queryResults(ctx, res, true); } -int HTTPServer::DeleteQuery(http::Context &ctx) { +int HTTPServer::DeleteQuery(http::Context& ctx) { auto db = getDB(ctx); std::string dsl = ctx.body->Read(); @@ -192,7 +194,7 @@ int HTTPServer::DeleteQuery(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::UpdateQuery(http::Context &ctx) { +int HTTPServer::UpdateQuery(http::Context& ctx) { auto db = getDB(ctx); std::string dsl = ctx.body->Read(); @@ -216,7 +218,7 @@ int HTTPServer::UpdateQuery(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::GetDatabases(http::Context &ctx) { +int HTTPServer::GetDatabases(http::Context& ctx) { std::string_view sortOrder = ctx.request->params.Get("sort_order"); auto dbs = dbMgr_.EnumDatabases(); @@ -231,7 +233,7 @@ int HTTPServer::GetDatabases(http::Context &ctx) { } if (sortDirection) { - boost::sort::pdqsort(dbs.begin(), dbs.end(), [sortDirection](const std::string &lhs, const std::string &rhs) { + boost::sort::pdqsort(dbs.begin(), dbs.end(), [sortDirection](const std::string& lhs, const std::string& rhs) { return (sortDirection > 0) ? (collateCompare(lhs, rhs, SortingPrioritiesTable()) == ComparationResult::Lt) : (collateCompare(lhs, rhs, SortingPrioritiesTable()) == ComparationResult::Gt); }); @@ -242,26 +244,28 @@ int HTTPServer::GetDatabases(http::Context &ctx) { JsonBuilder builder(ser); builder.Put("total_items", dbs.size()); auto arrNode = builder.Array("items"); - for (auto &db : dbs) arrNode.Put(nullptr, db); + for (auto& db : dbs) { + arrNode.Put(nullptr, db); + } } return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::PostDatabase(http::Context &ctx) { +int HTTPServer::PostDatabase(http::Context& ctx) { std::string newDbName = getNameFromJson(ctx.body->Read()); auto dbs = dbMgr_.EnumDatabases(); - for (auto &db : dbs) { + for (auto& db : dbs) { if (db == newDbName) { return jsonStatus(ctx, http::HttpStatus(http::StatusBadRequest, "Database already exists")); } } AuthContext dummyCtx; - AuthContext *actx = &dummyCtx; + AuthContext* actx = &dummyCtx; if (!dbMgr_.IsNoSecurity()) { - auto clientData = dynamic_cast(ctx.clientData.get()); + auto clientData = dynamic_cast(ctx.clientData.get()); assertrx(clientData); actx = &clientData->auth; // -V522 } @@ -274,13 +278,13 @@ int HTTPServer::PostDatabase(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::DeleteDatabase(http::Context &ctx) { +int HTTPServer::DeleteDatabase(http::Context& ctx) { std::string dbName(urldecode2(ctx.request->urlParams[0])); AuthContext dummyCtx; - AuthContext *actx = &dummyCtx; + AuthContext* actx = &dummyCtx; if (!dbMgr_.IsNoSecurity()) { - auto clientData = dynamic_cast(ctx.clientData.get()); + auto clientData = dynamic_cast(ctx.clientData.get()); assertrx(clientData); actx = &clientData->auth; // -V522 } @@ -304,7 +308,7 @@ int HTTPServer::DeleteDatabase(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::GetNamespaces(http::Context &ctx) { +int HTTPServer::GetNamespaces(http::Context& ctx) { std::string_view sortOrder = ctx.request->params.Get("sort_order"); std::vector nsDefs; @@ -323,7 +327,7 @@ int HTTPServer::GetNamespaces(http::Context &ctx) { } if (sortDirection) { - boost::sort::pdqsort(nsDefs.begin(), nsDefs.end(), [sortDirection](const NamespaceDef &lhs, const NamespaceDef &rhs) { + boost::sort::pdqsort(nsDefs.begin(), nsDefs.end(), [sortDirection](const NamespaceDef& lhs, const NamespaceDef& rhs) { return (sortDirection > 0) ? (collateCompare(lhs.name, rhs.name, SortingPrioritiesTable()) == ComparationResult::Lt) : (collateCompare(lhs.name, rhs.name, SortingPrioritiesTable()) == ComparationResult::Gt); @@ -335,7 +339,7 @@ int HTTPServer::GetNamespaces(http::Context &ctx) { JsonBuilder builder(ser); builder.Put("total_items", nsDefs.size()); auto arrNode = builder.Array("items"); - for (auto &nsDef : nsDefs) { + for (auto& nsDef : nsDefs) { auto objNode = arrNode.Object(nullptr); objNode.Put("name", nsDef.name); } @@ -343,7 +347,7 @@ int HTTPServer::GetNamespaces(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::GetNamespace(http::Context &ctx) { +int HTTPServer::GetNamespace(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -367,7 +371,7 @@ int HTTPServer::GetNamespace(http::Context &ctx) { return ctx.JSON(http::StatusOK, wrSer.DetachChunk()); } -int HTTPServer::PostNamespace(http::Context &ctx) { +int HTTPServer::PostNamespace(http::Context& ctx) { auto db = getDB(ctx); reindexer::NamespaceDef nsdef(""); @@ -385,7 +389,7 @@ int HTTPServer::PostNamespace(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::DeleteNamespace(http::Context &ctx) { +int HTTPServer::DeleteNamespace(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -403,7 +407,7 @@ int HTTPServer::DeleteNamespace(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::TruncateNamespace(http::Context &ctx) { +int HTTPServer::TruncateNamespace(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -421,7 +425,7 @@ int HTTPServer::TruncateNamespace(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::RenameNamespace(http::Context &ctx) { +int HTTPServer::RenameNamespace(http::Context& ctx) { auto db = getDB(ctx); std::string srcNsName = urldecode2(ctx.request->urlParams[1]); std::string dstNsName = urldecode2(ctx.request->urlParams[2]); @@ -444,7 +448,7 @@ int HTTPServer::RenameNamespace(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::GetItems(http::Context &ctx) { +int HTTPServer::GetItems(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -499,13 +503,13 @@ int HTTPServer::GetItems(http::Context &ctx) { return queryResults(ctx, res); } -int HTTPServer::DeleteItems(http::Context &ctx) { return modifyItems(ctx, ModeDelete); } +int HTTPServer::DeleteItems(http::Context& ctx) { return modifyItems(ctx, ModeDelete); } -int HTTPServer::PutItems(http::Context &ctx) { return modifyItems(ctx, ModeUpdate); } -int HTTPServer::PostItems(http::Context &ctx) { return modifyItems(ctx, ModeInsert); } -int HTTPServer::PatchItems(http::Context &ctx) { return modifyItems(ctx, ModeUpsert); } +int HTTPServer::PutItems(http::Context& ctx) { return modifyItems(ctx, ModeUpdate); } +int HTTPServer::PostItems(http::Context& ctx) { return modifyItems(ctx, ModeInsert); } +int HTTPServer::PatchItems(http::Context& ctx) { return modifyItems(ctx, ModeUpsert); } -int HTTPServer::GetMetaList(http::Context &ctx) { +int HTTPServer::GetMetaList(http::Context& ctx) { auto db = getDB(ctx); const std::string nsName = urldecode2(ctx.request->urlParams[1]); if (!nsName.length()) { @@ -569,7 +573,9 @@ int HTTPServer::GetMetaList(http::Context &ctx) { if (withValues) { std::string value; const Error err = db.GetMeta(nsName, *keysIt, value); - if (!err.ok()) return jsonStatus(ctx, http::HttpStatus(err)); + if (!err.ok()) { + return jsonStatus(ctx, http::HttpStatus(err)); + } objNode.Put("value", escapeString(value)); } objNode.End(); @@ -580,7 +586,7 @@ int HTTPServer::GetMetaList(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::GetMetaByKey(http::Context &ctx) { +int HTTPServer::GetMetaByKey(http::Context& ctx) { auto db = getDB(ctx); const std::string nsName = urldecode2(ctx.request->urlParams[1]); const std::string key = urldecode2(ctx.request->urlParams[2]); @@ -600,7 +606,7 @@ int HTTPServer::GetMetaByKey(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::PutMetaByKey(http::Context &ctx) { +int HTTPServer::PutMetaByKey(http::Context& ctx) { auto db = getDB(ctx); const std::string nsName = urldecode2(ctx.request->urlParams[1]); if (!nsName.length()) { @@ -616,13 +622,13 @@ int HTTPServer::PutMetaByKey(http::Context &ctx) { if (!err.ok()) { return jsonStatus(ctx, http::HttpStatus(err)); } - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { return jsonStatus(ctx, http::HttpStatus(Error(errParseJson, "Meta: %s", ex.what()))); } return jsonStatus(ctx); } -int HTTPServer::DeleteMetaByKey(http::Context &ctx) { +int HTTPServer::DeleteMetaByKey(http::Context& ctx) { auto db = getDB(ctx); const std::string nsName = urldecode2(ctx.request->urlParams[1]); const std::string keyName = urldecode2(ctx.request->urlParams[2]); @@ -637,7 +643,7 @@ int HTTPServer::DeleteMetaByKey(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::GetIndexes(http::Context &ctx) { +int HTTPServer::GetIndexes(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -660,7 +666,7 @@ int HTTPServer::GetIndexes(http::Context &ctx) { JsonBuilder builder(ser); builder.Put("total_items", nsDefs[0].indexes.size()); auto arrNode = builder.Array("items"); - for (auto &idxDef : nsDefs[0].indexes) { + for (auto& idxDef : nsDefs[0].indexes) { arrNode.Raw(nullptr, ""); idxDef.GetJSON(ser); } @@ -668,7 +674,7 @@ int HTTPServer::GetIndexes(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::PostIndex(http::Context &ctx) { +int HTTPServer::PostIndex(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -692,9 +698,9 @@ int HTTPServer::PostIndex(http::Context &ctx) { } if (!nsDefs.empty()) { - auto &indexes = nsDefs[0].indexes; + auto& indexes = nsDefs[0].indexes; auto foundIndexIt = - std::find_if(indexes.begin(), indexes.end(), [&newIdxName](const IndexDef &idx) { return idx.name_ == newIdxName; }); + std::find_if(indexes.begin(), indexes.end(), [&newIdxName](const IndexDef& idx) { return idx.name_ == newIdxName; }); if (foundIndexIt != indexes.end()) { return jsonStatus(ctx, http::HttpStatus(http::StatusBadRequest, "Index already exists")); } @@ -708,7 +714,7 @@ int HTTPServer::PostIndex(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::PutIndex(http::Context &ctx) { +int HTTPServer::PutIndex(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -729,7 +735,7 @@ int HTTPServer::PutIndex(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::PutSchema(http::Context &ctx) { +int HTTPServer::PutSchema(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -745,7 +751,7 @@ int HTTPServer::PutSchema(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::GetSchema(http::Context &ctx) { +int HTTPServer::GetSchema(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -762,11 +768,11 @@ int HTTPServer::GetSchema(http::Context &ctx) { return ctx.JSON(http::StatusOK, schema.length() ? schema : "{}"sv); } -int HTTPServer::GetProtobufSchema(http::Context &ctx) { +int HTTPServer::GetProtobufSchema(http::Context& ctx) { Reindexer db = getDB(ctx); std::vector nses; - for (auto &p : ctx.request->params) { + for (auto& p : ctx.request->params) { if (p.name == "ns"sv || p.name == "ns[]"sv) { nses.emplace_back(urldecode2(p.val)); } @@ -774,12 +780,14 @@ int HTTPServer::GetProtobufSchema(http::Context &ctx) { WrSerializer ser; Error err = db.GetProtobufSchema(ser, nses); - if (!err.ok()) return jsonStatus(ctx, http::HttpStatus(err)); + if (!err.ok()) { + return jsonStatus(ctx, http::HttpStatus(err)); + } return ctx.String(http::StatusOK, ser.Slice()); } -int HTTPServer::DeleteIndex(http::Context &ctx) { +int HTTPServer::DeleteIndex(http::Context& ctx) { auto db = getDB(ctx); std::string nsName = urldecode2(ctx.request->urlParams[1]); @@ -801,7 +809,7 @@ int HTTPServer::DeleteIndex(http::Context &ctx) { return jsonStatus(ctx); } -int HTTPServer::Check(http::Context &ctx) { +int HTTPServer::Check(http::Context& ctx) { WrSerializer ser(ctx.writer->GetChunk()); { JsonBuilder builder(ser); @@ -879,7 +887,7 @@ int HTTPServer::Check(http::Context &ctx) { return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::DocHandler(http::Context &ctx) { +int HTTPServer::DocHandler(http::Context& ctx) { std::string path(ctx.request->path.substr(1)); bool endsWithSlash = (path.length() > 0 && path.back() == '/'); @@ -911,7 +919,9 @@ int HTTPServer::DocHandler(http::Context &ctx) { } auto pos = path.find_last_of('/'); - if (pos == std::string::npos) break; + if (pos == std::string::npos) { + break; + } path = path.erase(pos); } @@ -919,13 +929,13 @@ int HTTPServer::DocHandler(http::Context &ctx) { return NotFoundHandler(ctx); } -int HTTPServer::NotFoundHandler(http::Context &ctx) { +int HTTPServer::NotFoundHandler(http::Context& ctx) { http::HttpStatus httpStatus(http::StatusNotFound, "Not found"); return jsonStatus(ctx, httpStatus); } -bool HTTPServer::Start(const std::string &addr, ev::dynamic_loop &loop) { +bool HTTPServer::Start(const std::string& addr, ev::dynamic_loop& loop) { router_.NotFound(this); router_.GET("/", this); @@ -1017,7 +1027,7 @@ bool HTTPServer::Start(const std::string &addr, ev::dynamic_loop &loop) { return listener_->Bind(addr, socket_domain::tcp); } -Error HTTPServer::modifyItem(Reindexer &db, std::string &nsName, Item &item, ItemModifyMode mode) { +Error HTTPServer::modifyItem(Reindexer& db, std::string& nsName, Item& item, ItemModifyMode mode) { Error status; switch (mode) { case ModeUpsert: @@ -1036,7 +1046,7 @@ Error HTTPServer::modifyItem(Reindexer &db, std::string &nsName, Item &item, Ite return status; } -Error HTTPServer::modifyItem(Reindexer &db, std::string &nsName, Item &item, QueryResults &qr, ItemModifyMode mode) { +Error HTTPServer::modifyItem(Reindexer& db, std::string& nsName, Item& item, QueryResults& qr, ItemModifyMode mode) { Error status; switch (mode) { case ModeUpsert: @@ -1055,21 +1065,21 @@ Error HTTPServer::modifyItem(Reindexer &db, std::string &nsName, Item &item, Que return status; } -int HTTPServer::modifyItemsJSON(http::Context &ctx, std::string &nsName, const std::vector &precepts, ItemModifyMode mode) { +int HTTPServer::modifyItemsJSON(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode) { auto db = getDB(ctx); std::string itemJson = ctx.body->Read(); int cnt = 0; std::vector updatedItems; if (itemJson.size()) { - char *jsonPtr = &itemJson[0]; + char* jsonPtr = &itemJson[0]; size_t jsonLeft = itemJson.size(); while (jsonPtr && *jsonPtr) { Item item = db.NewItem(nsName); if (!item.Status().ok()) { return jsonStatus(ctx, http::HttpStatus(item.Status())); } - char *prevPtr = jsonPtr; + char* prevPtr = jsonPtr; auto str = std::string_view(jsonPtr, jsonLeft); if (jsonPtr != &itemJson[0] && isBlank(str)) { break; @@ -1090,7 +1100,9 @@ int HTTPServer::modifyItemsJSON(http::Context &ctx, std::string &nsName, const s if (item.GetID() != -1) { ++cnt; - if (!precepts.empty()) updatedItems.emplace_back(item.GetJSON()); + if (!precepts.empty()) { + updatedItems.emplace_back(item.GetJSON()); + } } } } @@ -1101,7 +1113,9 @@ int HTTPServer::modifyItemsJSON(http::Context &ctx, std::string &nsName, const s builder.Put(kParamSuccess, true); if (!precepts.empty()) { auto itemsArray = builder.Array(kParamItems); - for (const std::string &item : updatedItems) itemsArray.Raw(nullptr, item); + for (const std::string& item : updatedItems) { + itemsArray.Raw(nullptr, item); + } itemsArray.End(); } builder.End(); @@ -1109,7 +1123,7 @@ int HTTPServer::modifyItemsJSON(http::Context &ctx, std::string &nsName, const s return ctx.JSON(http::StatusOK, ser.DetachChunk()); } -int HTTPServer::modifyItemsMsgPack(http::Context &ctx, std::string &nsName, const std::vector &precepts, ItemModifyMode mode) { +int HTTPServer::modifyItemsMsgPack(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode) { QueryResults qr; int totalItems = 0; @@ -1121,10 +1135,14 @@ int HTTPServer::modifyItemsMsgPack(http::Context &ctx, std::string &nsName, cons while (offset < length) { Item item = db.NewItem(nsName); - if (!item.Status().ok()) return msgpackStatus(ctx, http::HttpStatus(item.Status())); + if (!item.Status().ok()) { + return msgpackStatus(ctx, http::HttpStatus(item.Status())); + } Error status = item.FromMsgPack(std::string_view(sbuffer.data(), sbuffer.size()), offset); - if (!status.ok()) return msgpackStatus(ctx, http::HttpStatus(status)); + if (!status.ok()) { + return msgpackStatus(ctx, http::HttpStatus(status)); + } item.SetPrecepts(precepts); if (!precepts.empty()) { @@ -1132,7 +1150,9 @@ int HTTPServer::modifyItemsMsgPack(http::Context &ctx, std::string &nsName, cons } else { status = modifyItem(db, nsName, item, mode); } - if (!status.ok()) return msgpackStatus(ctx, http::HttpStatus(status)); + if (!status.ok()) { + return msgpackStatus(ctx, http::HttpStatus(status)); + } if (item.GetID() != -1) { ++totalItems; @@ -1145,7 +1165,7 @@ int HTTPServer::modifyItemsMsgPack(http::Context &ctx, std::string &nsName, cons msgpackBuilder.Put(kParamSuccess, true); if (!precepts.empty()) { auto itemsArray = msgpackBuilder.Array(kParamItems, qr.Count()); - for (auto &it : qr) { + for (auto& it : qr) { const auto err = it.GetMsgPack(wrSer, false); if (!err.ok()) { return msgpackStatus(ctx, http::HttpStatus(err)); @@ -1157,12 +1177,12 @@ int HTTPServer::modifyItemsMsgPack(http::Context &ctx, std::string &nsName, cons return ctx.MSGPACK(http::StatusOK, wrSer.DetachChunk()); } -int HTTPServer::modifyItemsProtobuf(http::Context &ctx, std::string &nsName, const std::vector &precepts, +int HTTPServer::modifyItemsProtobuf(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode) { WrSerializer wrSer(ctx.writer->GetChunk()); ProtobufBuilder builder(&wrSer); - auto sendResponse = [&](int items, const Error &err) { + auto sendResponse = [&](int items, const Error& err) { if (err.ok()) { builder.Put(kProtoModifyResultsFields.at(kParamUpdated), int(items)); builder.Put(kProtoModifyResultsFields.at(kParamSuccess), err.ok()); @@ -1175,15 +1195,21 @@ int HTTPServer::modifyItemsProtobuf(http::Context &ctx, std::string &nsName, con auto db = getDB(ctx); Item item = db.NewItem(nsName); - if (!item.Status().ok()) return sendResponse(0, item.Status()); + if (!item.Status().ok()) { + return sendResponse(0, item.Status()); + } std::string sbuffer = ctx.body->Read(); Error status = item.FromProtobuf(std::string_view(sbuffer.data(), sbuffer.size())); - if (!status.ok()) return sendResponse(0, status); + if (!status.ok()) { + return sendResponse(0, status); + } item.SetPrecepts(precepts); status = modifyItem(db, nsName, item, mode); - if (!status.ok()) return sendResponse(0, item.Status()); + if (!status.ok()) { + return sendResponse(0, item.Status()); + } int totalItems = 0; if (item.GetID() != -1) { @@ -1198,11 +1224,11 @@ int HTTPServer::modifyItemsProtobuf(http::Context &ctx, std::string &nsName, con return sendResponse(totalItems, item.Status()); } -int HTTPServer::modifyItemsTxJSON(http::Context &ctx, Transaction &tx, const std::vector &precepts, ItemModifyMode mode) { +int HTTPServer::modifyItemsTxJSON(http::Context& ctx, Transaction& tx, const std::vector& precepts, ItemModifyMode mode) { std::string itemJson = ctx.body->Read(); if (itemJson.size()) { - char *jsonPtr = &itemJson[0]; + char* jsonPtr = &itemJson[0]; size_t jsonLeft = itemJson.size(); while (jsonPtr && *jsonPtr) { Item item = tx.NewItem(); @@ -1210,7 +1236,7 @@ int HTTPServer::modifyItemsTxJSON(http::Context &ctx, Transaction &tx, const std http::HttpStatus httpStatus(item.Status()); return jsonStatus(ctx, httpStatus); } - char *prevPtr = jsonPtr; + char* prevPtr = jsonPtr; auto str = std::string_view(jsonPtr, jsonLeft); if (jsonPtr != &itemJson[0] && isBlank(str)) { break; @@ -1231,17 +1257,21 @@ int HTTPServer::modifyItemsTxJSON(http::Context &ctx, Transaction &tx, const std return jsonStatus(ctx); } -int HTTPServer::modifyItemsTxMsgPack(http::Context &ctx, Transaction &tx, const std::vector &precepts, ItemModifyMode mode) { +int HTTPServer::modifyItemsTxMsgPack(http::Context& ctx, Transaction& tx, const std::vector& precepts, ItemModifyMode mode) { std::string sbuffer = ctx.body->Read(); size_t length = sbuffer.size(); size_t offset = 0; while (offset < length) { Item item = tx.NewItem(); - if (!item.Status().ok()) return msgpackStatus(ctx, http::HttpStatus(item.Status())); + if (!item.Status().ok()) { + return msgpackStatus(ctx, http::HttpStatus(item.Status())); + } Error status = item.FromMsgPack(std::string_view(sbuffer.data(), sbuffer.size()), offset); - if (!status.ok()) return msgpackStatus(ctx, http::HttpStatus(status)); + if (!status.ok()) { + return msgpackStatus(ctx, http::HttpStatus(status)); + } item.SetPrecepts(precepts); tx.Modify(std::move(item), mode); @@ -1250,14 +1280,14 @@ int HTTPServer::modifyItemsTxMsgPack(http::Context &ctx, Transaction &tx, const return msgpackStatus(ctx); } -int HTTPServer::modifyItems(http::Context &ctx, ItemModifyMode mode) { +int HTTPServer::modifyItems(http::Context& ctx, ItemModifyMode mode) { std::string nsName = urldecode2(ctx.request->urlParams[1]); if (nsName.empty()) { return jsonStatus(ctx, http::HttpStatus(http::StatusBadRequest, "Namespace is not specified")); } std::vector precepts; - for (auto &p : ctx.request->params) { + for (auto& p : ctx.request->params) { if (p.name == "precepts"sv) { precepts.emplace_back(urldecode2(p.val)); } @@ -1273,7 +1303,7 @@ int HTTPServer::modifyItems(http::Context &ctx, ItemModifyMode mode) { } } -int HTTPServer::modifyItemsTx(http::Context &ctx, ItemModifyMode mode) { +int HTTPServer::modifyItemsTx(http::Context& ctx, ItemModifyMode mode) { std::string dbName; auto db = getDB(ctx, &dbName); std::string txId = urldecode2(ctx.request->urlParams[1]); @@ -1282,7 +1312,7 @@ int HTTPServer::modifyItemsTx(http::Context &ctx, ItemModifyMode mode) { } std::vector precepts; - for (auto &p : ctx.request->params) { + for (auto& p : ctx.request->params) { if (p.name == "precepts"sv) { precepts.emplace_back(urldecode2(p.val)); } @@ -1293,7 +1323,7 @@ int HTTPServer::modifyItemsTx(http::Context &ctx, ItemModifyMode mode) { return format == "msgpack"sv ? modifyItemsTxMsgPack(ctx, *tx, precepts, mode) : modifyItemsTxJSON(ctx, *tx, precepts, mode); } -int HTTPServer::queryResultsJSON(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, +int HTTPServer::queryResultsJSON(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width) { WrSerializer wrSer(ctx.writer->GetChunk()); JsonBuilder builder(wrSer); @@ -1337,7 +1367,9 @@ int HTTPServer::queryResultsJSON(http::Context &ctx, const reindexer::QueryResul } } - if (i == offset) wrSer.Reserve(wrSer.Len() * (std::min(limit, unsigned(res.Count() - offset)) + 1)); + if (i == offset) { + wrSer.Reserve(wrSer.Len() * (std::min(limit, unsigned(res.Count() - offset)) + 1)); + } } iarray.End(); @@ -1354,7 +1386,7 @@ int HTTPServer::queryResultsJSON(http::Context &ctx, const reindexer::QueryResul return ctx.JSON(http::StatusOK, wrSer.DetachChunk()); } -int HTTPServer::queryResultsCSV(http::Context &ctx, reindexer::QueryResults &res, unsigned limit, unsigned offset) { +int HTTPServer::queryResultsCSV(http::Context& ctx, reindexer::QueryResults& res, unsigned limit, unsigned offset) { if (res.GetAggregationResults().size()) { throw Error(errForbidden, "Aggregations are not supported in CSV"); } @@ -1363,7 +1395,7 @@ int HTTPServer::queryResultsCSV(http::Context &ctx, reindexer::QueryResults &res } const size_t kChunkMaxSize = 0x1000; - auto createChunk = [](const WrSerializer &from, WrSerializer &to) { + auto createChunk = [](const WrSerializer& from, WrSerializer& to) { char szBuf[64]; size_t l = u32toax(from.Len(), szBuf) - szBuf; to << std::string_view(szBuf, l); @@ -1372,8 +1404,8 @@ int HTTPServer::queryResultsCSV(http::Context &ctx, reindexer::QueryResults &res to << "\r\n"; }; - auto createCSVHeaders = [&res](WrSerializer &ser, const CsvOrdering &ordering) { - const auto &tm = res.getTagsMatcher(0); + auto createCSVHeaders = [&res](WrSerializer& ser, const CsvOrdering& ordering) { + const auto& tm = res.getTagsMatcher(0); for (auto it = ordering.begin(); it != ordering.end(); ++it) { if (it != ordering.begin()) { ser << ','; @@ -1416,16 +1448,26 @@ int HTTPServer::queryResultsCSV(http::Context &ctx, reindexer::QueryResults &res return ctx.CSV(http::StatusOK, wrSerRes.DetachChunk()); } -int HTTPServer::queryResultsMsgPack(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, +int HTTPServer::queryResultsMsgPack(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width) { int paramsToSend = 3; bool withTotalItems = (!isQueryResults || limit != kDefaultLimit); - if (!res.aggregationResults.empty()) ++paramsToSend; - if (!res.GetExplainResults().empty()) ++paramsToSend; - if (withTotalItems) ++paramsToSend; - if (withColumns) ++paramsToSend; + if (!res.aggregationResults.empty()) { + ++paramsToSend; + } + if (!res.GetExplainResults().empty()) { + ++paramsToSend; + } + if (withTotalItems) { + ++paramsToSend; + } + if (withColumns) { + ++paramsToSend; + } if (isQueryResults && res.totalCount) { - if (limit == kDefaultLimit) ++paramsToSend; + if (limit == kDefaultLimit) { + ++paramsToSend; + } ++paramsToSend; } @@ -1454,7 +1496,7 @@ int HTTPServer::queryResultsMsgPack(http::Context &ctx, const reindexer::QueryRe return ctx.MSGPACK(http::StatusOK, wrSer.DetachChunk()); } -int HTTPServer::queryResultsProtobuf(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, +int HTTPServer::queryResultsProtobuf(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width) { WrSerializer wrSer(ctx.writer->GetChunk()); ProtobufBuilder protobufBuilder(&wrSer); @@ -1505,10 +1547,10 @@ int HTTPServer::queryResultsProtobuf(http::Context &ctx, const reindexer::QueryR if (withColumns) { reindexer::TableCalculator tableCalculator(res, width, limit); - auto &header = tableCalculator.GetHeader(); - auto &columnsSettings = tableCalculator.GetColumnsSettings(); + auto& header = tableCalculator.GetHeader(); + auto& columnsSettings = tableCalculator.GetColumnsSettings(); for (auto it = header.begin(); it != header.end(); ++it) { - ColumnData &data = columnsSettings[*it]; + ColumnData& data = columnsSettings[*it]; auto parameteresObj = protobufBuilder.Object(kProtoQueryResultsFields.at(kParamColumns)); parameteresObj.Put(kProtoColumnsFields.at(kParamName), *it); parameteresObj.Put(kProtoColumnsFields.at(kParamWidthPercents), data.widthTerminalPercentage); @@ -1523,7 +1565,7 @@ int HTTPServer::queryResultsProtobuf(http::Context &ctx, const reindexer::QueryR } template -void HTTPServer::queryResultParams(Builder &builder, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, +void HTTPServer::queryResultParams(Builder& builder, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, bool withColumns, int width) { h_vector namespaces(res.GetNamespaces()); auto namespacesArray = builder.Array(kParamNamespaces, namespaces.size()); @@ -1551,11 +1593,11 @@ void HTTPServer::queryResultParams(Builder &builder, const reindexer::QueryResul if (withColumns) { reindexer::TableCalculator tableCalculator(res, width, limit); - auto &header = tableCalculator.GetHeader(); - auto &columnsSettings = tableCalculator.GetColumnsSettings(); + auto& header = tableCalculator.GetHeader(); + auto& columnsSettings = tableCalculator.GetColumnsSettings(); auto headerArray = builder.Array(kParamColumns, header.size()); for (auto it = header.begin(); it != header.end(); ++it) { - ColumnData &data = columnsSettings[*it]; + ColumnData& data = columnsSettings[*it]; auto parameteresObj = headerArray.Object(nullptr, 4); parameteresObj.Put(kParamName, *it); parameteresObj.Put(kParamWidthPercents, data.widthTerminalPercentage); @@ -1565,7 +1607,7 @@ void HTTPServer::queryResultParams(Builder &builder, const reindexer::QueryResul } } -int HTTPServer::queryResults(http::Context &ctx, reindexer::QueryResults &res, bool isQueryResults, unsigned limit, unsigned offset) { +int HTTPServer::queryResults(http::Context& ctx, reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset) { std::string_view widthParam = ctx.request->params.Get("width"sv); int width = widthParam.empty() ? 0 : stoi(widthParam); @@ -1588,7 +1630,7 @@ int HTTPServer::queryResults(http::Context &ctx, reindexer::QueryResults &res, b } } -int HTTPServer::status(http::Context &ctx, const http::HttpStatus &status) { +int HTTPServer::status(http::Context& ctx, const http::HttpStatus& status) { std::string_view format = ctx.request->params.Get("format"sv); if (format == "msgpack"sv) { return msgpackStatus(ctx, status); @@ -1599,7 +1641,7 @@ int HTTPServer::status(http::Context &ctx, const http::HttpStatus &status) { } } -int HTTPServer::msgpackStatus(http::Context &ctx, const http::HttpStatus &status) { +int HTTPServer::msgpackStatus(http::Context& ctx, const http::HttpStatus& status) { WrSerializer wrSer(ctx.writer->GetChunk()); MsgPackBuilder msgpackBuilder(wrSer, ObjType::TypeObject, 3); msgpackBuilder.Put(kParamSuccess, status.code == http::StatusOK); @@ -1609,7 +1651,7 @@ int HTTPServer::msgpackStatus(http::Context &ctx, const http::HttpStatus &status return ctx.MSGPACK(status.code, wrSer.DetachChunk()); } -int HTTPServer::jsonStatus(http::Context &ctx, const http::HttpStatus &status) { +int HTTPServer::jsonStatus(http::Context& ctx, const http::HttpStatus& status) { WrSerializer ser(ctx.writer->GetChunk()); JsonBuilder builder(ser); builder.Put(kParamSuccess, status.code == http::StatusOK); @@ -1619,7 +1661,7 @@ int HTTPServer::jsonStatus(http::Context &ctx, const http::HttpStatus &status) { return ctx.JSON(status.code, ser.DetachChunk()); } -int HTTPServer::protobufStatus(http::Context &ctx, const http::HttpStatus &status) { +int HTTPServer::protobufStatus(http::Context& ctx, const http::HttpStatus& status) { WrSerializer ser(ctx.writer->GetChunk()); ProtobufBuilder builder(&ser); builder.Put(kProtoErrorResultsFields.at(kParamSuccess), status.code == http::StatusOK); @@ -1634,7 +1676,9 @@ unsigned HTTPServer::prepareLimit(std::string_view limitParam, int limitDefault) if (limitParam.length()) { limit = stoi(limitParam); - if (limit < 0) limit = 0; + if (limit < 0) { + limit = 0; + } } return static_cast(limit); @@ -1645,13 +1689,15 @@ unsigned HTTPServer::prepareOffset(std::string_view offsetParam, int offsetDefau if (offsetParam.length()) { offset = stoi(offsetParam); - if (offset < 0) offset = 0; + if (offset < 0) { + offset = 0; + } } return static_cast(offset); } -int HTTPServer::modifyQueryTxImpl(http::Context &ctx, const std::string &dbName, std::string_view txId, Query &q) { +int HTTPServer::modifyQueryTxImpl(http::Context& ctx, const std::string& dbName, std::string_view txId, Query& q) { reindexer::QueryResults res; auto tx = getTx(dbName, txId); if (!q.GetMergeQueries().empty()) { @@ -1665,17 +1711,17 @@ int HTTPServer::modifyQueryTxImpl(http::Context &ctx, const std::string &dbName, } template -Reindexer HTTPServer::getDB(http::Context &ctx, std::string *dbNameOut) { +Reindexer HTTPServer::getDB(http::Context& ctx, std::string* dbNameOut) { (void)ctx; - Reindexer *db = nullptr; + Reindexer* db = nullptr; std::string dbName(urldecode2(ctx.request->urlParams[0])); AuthContext dummyCtx; - AuthContext *actx = &dummyCtx; + AuthContext* actx = &dummyCtx; if (!dbMgr_.IsNoSecurity()) { - auto clientData = dynamic_cast(ctx.clientData.get()); + auto clientData = dynamic_cast(ctx.clientData.get()); assertrx(clientData); actx = &clientData->auth; // -V522 } @@ -1721,12 +1767,12 @@ std::string HTTPServer::getNameFromJson(std::string_view json) { gason::JsonParser parser; auto root = parser.Parse(json); return root["name"].As(); - } catch (const gason::Exception &ex) { + } catch (const gason::Exception& ex) { throw Error(errParseJson, "getNameFromJson: %s", ex.what()); } } -std::shared_ptr HTTPServer::getTx(const std::string &dbName, std::string_view txId) { +std::shared_ptr HTTPServer::getTx(const std::string& dbName, std::string_view txId) { std::lock_guard lck(txMtx_); auto found = txMap_.find(txId); if (found == txMap_.end()) { @@ -1739,7 +1785,7 @@ std::shared_ptr HTTPServer::getTx(const std::string &dbName, std::s return found.value().tx; } -std::string HTTPServer::addTx(std::string dbName, Transaction &&tx) { +std::string HTTPServer::addTx(std::string dbName, Transaction&& tx) { const auto now = TxDeadlineClock::now_coarse(); auto ts = std::chrono::duration_cast(now.time_since_epoch()); std::string txId = randStringAlph(kTxIdLen) + "_" + std::to_string(ts.count()); @@ -1756,7 +1802,7 @@ std::string HTTPServer::addTx(std::string dbName, Transaction &&tx) { return txId; } -void HTTPServer::removeTx(const std::string &dbName, std::string_view txId) { +void HTTPServer::removeTx(const std::string& dbName, std::string_view txId) { std::lock_guard lck(txMtx_); auto found = txMap_.find(txId); if (found == txMap_.end() || !iequals(found.value().dbName, dbName)) { @@ -1774,7 +1820,7 @@ void HTTPServer::removeExpiredTx() { auto ctx = MakeSystemAuthContext(); auto status = dbMgr_.OpenDatabase(it->second.dbName, ctx, false); if (status.ok()) { - reindexer::Reindexer *db = nullptr; + reindexer::Reindexer* db = nullptr; status = ctx.GetDB(kRoleSystem, &db); if (db && status.ok()) { logger_.info("Rollback tx {} on idle deadline", it->first); @@ -1788,7 +1834,7 @@ void HTTPServer::removeExpiredTx() { } } -int HTTPServer::CheckAuth(http::Context &ctx) { +int HTTPServer::CheckAuth(http::Context& ctx) { (void)ctx; if (dbMgr_.IsNoSecurity()) { return 0; @@ -1803,10 +1849,12 @@ int HTTPServer::CheckAuth(http::Context &ctx) { } h_vector credVec(authHeader.length()); - char *credBuf = &credVec.front(); + char* credBuf = &credVec.front(); Base64decode(credBuf, authHeader.data() + 6); - char *password = strchr(credBuf, ':'); - if (password != nullptr) *password++ = 0; + char* password = strchr(credBuf, ':'); + if (password != nullptr) { + *password++ = 0; + } AuthContext auth(credBuf, password ? password : ""); auto status = dbMgr_.Login("", auth); @@ -1822,7 +1870,7 @@ int HTTPServer::CheckAuth(http::Context &ctx) { return 0; } -int HTTPServer::BeginTx(http::Context &ctx) { +int HTTPServer::BeginTx(http::Context& ctx) { std::string nsName = urldecode2(ctx.request->urlParams[1]); if (nsName.empty()) { return jsonStatus(ctx, http::HttpStatus(http::StatusBadRequest, "Namespace is not specified")); @@ -1849,7 +1897,7 @@ int HTTPServer::BeginTx(http::Context &ctx) { } } -int HTTPServer::CommitTx(http::Context &ctx) { +int HTTPServer::CommitTx(http::Context& ctx) { std::string txId = urldecode2(ctx.request->urlParams[1]); if (txId.empty()) { return status(ctx, http::HttpStatus(http::StatusBadRequest, "Tx ID is not specified")); @@ -1867,7 +1915,7 @@ int HTTPServer::CommitTx(http::Context &ctx) { return queryResults(ctx, qr); } -int HTTPServer::RollbackTx(http::Context &ctx) { +int HTTPServer::RollbackTx(http::Context& ctx) { std::string txId = urldecode2(ctx.request->urlParams[1]); if (txId.empty()) { return status(ctx, http::HttpStatus(http::StatusBadRequest, "Tx ID is not specified")); @@ -1885,15 +1933,15 @@ int HTTPServer::RollbackTx(http::Context &ctx) { return status(ctx); } -int HTTPServer::PostItemsTx(http::Context &ctx) { return modifyItemsTx(ctx, ModeInsert); } +int HTTPServer::PostItemsTx(http::Context& ctx) { return modifyItemsTx(ctx, ModeInsert); } -int HTTPServer::PutItemsTx(http::Context &ctx) { return modifyItemsTx(ctx, ModeUpdate); } +int HTTPServer::PutItemsTx(http::Context& ctx) { return modifyItemsTx(ctx, ModeUpdate); } -int HTTPServer::PatchItemsTx(http::Context &ctx) { return modifyItemsTx(ctx, ModeUpsert); } +int HTTPServer::PatchItemsTx(http::Context& ctx) { return modifyItemsTx(ctx, ModeUpsert); } -int HTTPServer::DeleteItemsTx(http::Context &ctx) { return modifyItemsTx(ctx, ModeDelete); } +int HTTPServer::DeleteItemsTx(http::Context& ctx) { return modifyItemsTx(ctx, ModeDelete); } -int HTTPServer::GetSQLQueryTx(http::Context &ctx) { +int HTTPServer::GetSQLQueryTx(http::Context& ctx) { std::string dbName; auto db = getDB(ctx, &dbName); std::string txId = urldecode2(ctx.request->urlParams[1]); @@ -1917,12 +1965,12 @@ int HTTPServer::GetSQLQueryTx(http::Context &ctx) { return status(ctx, http::HttpStatus(http::StatusInternalServerError, "Transactions support update/delete queries only")); } return status(ctx, http::HttpStatus(Error(errLogic, "Unexpected query type: %d", q.type_))); - } catch (const Error &e) { + } catch (const Error& e) { return status(ctx, http::HttpStatus(e)); } } -int HTTPServer::DeleteQueryTx(http::Context &ctx) { +int HTTPServer::DeleteQueryTx(http::Context& ctx) { std::string dbName; auto db = getDB(ctx, &dbName); std::string dsl = ctx.body->Read(); @@ -1942,7 +1990,7 @@ int HTTPServer::DeleteQueryTx(http::Context &ctx) { return modifyQueryTxImpl(ctx, dbName, txId, q); } -int HTTPServer::PostMemReset(http::Context &ctx) { +int HTTPServer::PostMemReset(http::Context& ctx) { #if REINDEX_WITH_GPERFTOOLS if (alloc_ext::TCMallocIsAvailable()) { alloc_ext::instance()->ReleaseFreeMemory(); @@ -1955,7 +2003,7 @@ int HTTPServer::PostMemReset(http::Context &ctx) { #endif } -int HTTPServer::GetMemInfo(http::Context &ctx) { +int HTTPServer::GetMemInfo(http::Context& ctx) { #if REINDEX_WITH_GPERFTOOLS if (alloc_ext::TCMallocIsAvailable()) { const int bufSize = 32000; @@ -1970,9 +2018,9 @@ int HTTPServer::GetMemInfo(http::Context &ctx) { #endif } -void HTTPServer::Logger(http::Context &ctx) { +void HTTPServer::Logger(http::Context& ctx) { HandlerStat statDiff = HandlerStat() - ctx.stat.allocStat; - auto clientData = reinterpret_cast(ctx.clientData.get()); + auto clientData = reinterpret_cast(ctx.clientData.get()); if (serverConfig_.DebugAllocs) { logger_.info("{} - {} {} {} {} {} {}us | allocs: {}, allocated: {} byte(s)", ctx.request->clientAddr, clientData ? clientData->auth.Login() : "", ctx.request->method, ctx.request->uri, ctx.writer->RespCode(), @@ -1983,11 +2031,11 @@ void HTTPServer::Logger(http::Context &ctx) { } } -void HTTPServer::OnResponse(http::Context &ctx) { +void HTTPServer::OnResponse(http::Context& ctx) { if (statsWatcher_) { static const std::string kUnknownDBName = ""; std::string dbName; - const std::string *dbNamePtr = &kUnknownDBName; + const std::string* dbNamePtr = &kUnknownDBName; if (nullptr != ctx.request && !ctx.request->urlParams.empty() && 0 == ctx.request->path.find("/api/v1/db/"sv)) { dbName = urldecode2(ctx.request->urlParams[0]); dbNamePtr = &dbName; diff --git a/cpp_src/server/httpserver.h b/cpp_src/server/httpserver.h index be5a140c3..234e0495d 100644 --- a/cpp_src/server/httpserver.h +++ b/cpp_src/server/httpserver.h @@ -23,107 +23,107 @@ struct HTTPClientData final : public http::ClientData { class HTTPServer { public: - HTTPServer(DBManager &dbMgr, LoggerWrapper &logger, const ServerConfig &serverConfig, Prometheus *prometheusI = nullptr, - IStatsWatcher *statsWatcherI = nullptr); + HTTPServer(DBManager& dbMgr, LoggerWrapper& logger, const ServerConfig& serverConfig, Prometheus* prometheusI = nullptr, + IStatsWatcher* statsWatcherI = nullptr); - bool Start(const std::string &addr, ev::dynamic_loop &loop); + bool Start(const std::string& addr, ev::dynamic_loop& loop); void Stop() { listener_->Stop(); } - int NotFoundHandler(http::Context &ctx); - int DocHandler(http::Context &ctx); - int Check(http::Context &ctx); - int PostQuery(http::Context &ctx); - int DeleteQuery(http::Context &ctx); - int UpdateQuery(http::Context &ctx); - int GetSQLQuery(http::Context &ctx); - int PostSQLQuery(http::Context &ctx); - int GetSQLSuggest(http::Context &ctx); - int GetDatabases(http::Context &ctx); - int PostDatabase(http::Context &ctx); - int DeleteDatabase(http::Context &ctx); - int GetNamespaces(http::Context &ctx); - int GetNamespace(http::Context &ctx); - int PostNamespace(http::Context &ctx); - int DeleteNamespace(http::Context &ctx); - int TruncateNamespace(http::Context &ctx); - int RenameNamespace(http::Context &ctx); - int GetItems(http::Context &ctx); - int PostItems(http::Context &ctx); - int PatchItems(http::Context &ctx); - int PutItems(http::Context &ctx); - int DeleteItems(http::Context &ctx); - int GetIndexes(http::Context &ctx); - int PostIndex(http::Context &ctx); - int PutIndex(http::Context &ctx); - int PutSchema(http::Context &ctx); - int GetSchema(http::Context &ctx); - int GetProtobufSchema(http::Context &ctx); - int GetMetaList(http::Context &ctx); - int GetMetaByKey(http::Context &ctx); - int PutMetaByKey(http::Context &ctx); - int DeleteMetaByKey(http::Context &ctx); - int DeleteIndex(http::Context &ctx); - int CheckAuth(http::Context &ctx); - int BeginTx(http::Context &ctx); - int CommitTx(http::Context &ctx); - int RollbackTx(http::Context &ctx); - int PostItemsTx(http::Context &ctx); - int PutItemsTx(http::Context &ctx); - int PatchItemsTx(http::Context &ctx); - int DeleteItemsTx(http::Context &ctx); - int GetSQLQueryTx(http::Context &ctx); - int DeleteQueryTx(http::Context &ctx); - int PostMemReset(http::Context &ctx); - int GetMemInfo(http::Context &ctx); - void Logger(http::Context &ctx); - void OnResponse(http::Context &ctx); + int NotFoundHandler(http::Context& ctx); + int DocHandler(http::Context& ctx); + int Check(http::Context& ctx); + int PostQuery(http::Context& ctx); + int DeleteQuery(http::Context& ctx); + int UpdateQuery(http::Context& ctx); + int GetSQLQuery(http::Context& ctx); + int PostSQLQuery(http::Context& ctx); + int GetSQLSuggest(http::Context& ctx); + int GetDatabases(http::Context& ctx); + int PostDatabase(http::Context& ctx); + int DeleteDatabase(http::Context& ctx); + int GetNamespaces(http::Context& ctx); + int GetNamespace(http::Context& ctx); + int PostNamespace(http::Context& ctx); + int DeleteNamespace(http::Context& ctx); + int TruncateNamespace(http::Context& ctx); + int RenameNamespace(http::Context& ctx); + int GetItems(http::Context& ctx); + int PostItems(http::Context& ctx); + int PatchItems(http::Context& ctx); + int PutItems(http::Context& ctx); + int DeleteItems(http::Context& ctx); + int GetIndexes(http::Context& ctx); + int PostIndex(http::Context& ctx); + int PutIndex(http::Context& ctx); + int PutSchema(http::Context& ctx); + int GetSchema(http::Context& ctx); + int GetProtobufSchema(http::Context& ctx); + int GetMetaList(http::Context& ctx); + int GetMetaByKey(http::Context& ctx); + int PutMetaByKey(http::Context& ctx); + int DeleteMetaByKey(http::Context& ctx); + int DeleteIndex(http::Context& ctx); + int CheckAuth(http::Context& ctx); + int BeginTx(http::Context& ctx); + int CommitTx(http::Context& ctx); + int RollbackTx(http::Context& ctx); + int PostItemsTx(http::Context& ctx); + int PutItemsTx(http::Context& ctx); + int PatchItemsTx(http::Context& ctx); + int DeleteItemsTx(http::Context& ctx); + int GetSQLQueryTx(http::Context& ctx); + int DeleteQueryTx(http::Context& ctx); + int PostMemReset(http::Context& ctx); + int GetMemInfo(http::Context& ctx); + void Logger(http::Context& ctx); + void OnResponse(http::Context& ctx); protected: - Error modifyItem(Reindexer &db, std::string &nsName, Item &item, ItemModifyMode mode); - Error modifyItem(Reindexer &db, std::string &nsName, Item &item, QueryResults &, ItemModifyMode mode); - int modifyItems(http::Context &ctx, ItemModifyMode mode); - int modifyItemsTx(http::Context &ctx, ItemModifyMode mode); - int modifyItemsProtobuf(http::Context &ctx, std::string &nsName, const std::vector &precepts, ItemModifyMode mode); - int modifyItemsMsgPack(http::Context &ctx, std::string &nsName, const std::vector &precepts, ItemModifyMode mode); - int modifyItemsJSON(http::Context &ctx, std::string &nsName, const std::vector &precepts, ItemModifyMode mode); - int modifyItemsTxMsgPack(http::Context &ctx, Transaction &tx, const std::vector &precepts, ItemModifyMode mode); - int modifyItemsTxJSON(http::Context &ctx, Transaction &tx, const std::vector &precepts, ItemModifyMode mode); - int queryResults(http::Context &ctx, reindexer::QueryResults &res, bool isQueryResults = false, unsigned limit = kDefaultLimit, + Error modifyItem(Reindexer& db, std::string& nsName, Item& item, ItemModifyMode mode); + Error modifyItem(Reindexer& db, std::string& nsName, Item& item, QueryResults&, ItemModifyMode mode); + int modifyItems(http::Context& ctx, ItemModifyMode mode); + int modifyItemsTx(http::Context& ctx, ItemModifyMode mode); + int modifyItemsProtobuf(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode); + int modifyItemsMsgPack(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode); + int modifyItemsJSON(http::Context& ctx, std::string& nsName, const std::vector& precepts, ItemModifyMode mode); + int modifyItemsTxMsgPack(http::Context& ctx, Transaction& tx, const std::vector& precepts, ItemModifyMode mode); + int modifyItemsTxJSON(http::Context& ctx, Transaction& tx, const std::vector& precepts, ItemModifyMode mode); + int queryResults(http::Context& ctx, reindexer::QueryResults& res, bool isQueryResults = false, unsigned limit = kDefaultLimit, unsigned offset = kDefaultOffset); - int queryResultsMsgPack(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, unsigned offset, + int queryResultsMsgPack(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width = 0); - int queryResultsProtobuf(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, unsigned offset, + int queryResultsProtobuf(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width = 0); - int queryResultsJSON(http::Context &ctx, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, unsigned offset, + int queryResultsJSON(http::Context& ctx, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, unsigned offset, bool withColumns, int width = 0); - int queryResultsCSV(http::Context &ctx, reindexer::QueryResults &res, unsigned limit, unsigned offset); + int queryResultsCSV(http::Context& ctx, reindexer::QueryResults& res, unsigned limit, unsigned offset); template - void queryResultParams(Builder &builder, const reindexer::QueryResults &res, bool isQueryResults, unsigned limit, bool withColumns, + void queryResultParams(Builder& builder, const reindexer::QueryResults& res, bool isQueryResults, unsigned limit, bool withColumns, int width); - int status(http::Context &ctx, const http::HttpStatus &status = http::HttpStatus()); - int jsonStatus(http::Context &ctx, const http::HttpStatus &status = http::HttpStatus()); - int msgpackStatus(http::Context &ctx, const http::HttpStatus &status = http::HttpStatus()); - int protobufStatus(http::Context &ctx, const http::HttpStatus &status = http::HttpStatus()); + int status(http::Context& ctx, const http::HttpStatus& status = http::HttpStatus()); + int jsonStatus(http::Context& ctx, const http::HttpStatus& status = http::HttpStatus()); + int msgpackStatus(http::Context& ctx, const http::HttpStatus& status = http::HttpStatus()); + int protobufStatus(http::Context& ctx, const http::HttpStatus& status = http::HttpStatus()); unsigned prepareLimit(std::string_view limitParam, int limitDefault = kDefaultLimit); unsigned prepareOffset(std::string_view offsetParam, int offsetDefault = kDefaultOffset); - int modifyQueryTxImpl(http::Context &ctx, const std::string &dbName, std::string_view txId, Query &q); + int modifyQueryTxImpl(http::Context& ctx, const std::string& dbName, std::string_view txId, Query& q); template - Reindexer getDB(http::Context &ctx, std::string *dbNameOut = nullptr); + Reindexer getDB(http::Context& ctx, std::string* dbNameOut = nullptr); std::string getNameFromJson(std::string_view json); constexpr static std::string_view statsSourceName() { return std::string_view{"http"}; } - std::shared_ptr getTx(const std::string &dbName, std::string_view txId); - std::string addTx(std::string dbName, Transaction &&tx); - void removeTx(const std::string &dbName, std::string_view txId); + std::shared_ptr getTx(const std::string& dbName, std::string_view txId); + std::string addTx(std::string dbName, Transaction&& tx); + void removeTx(const std::string& dbName, std::string_view txId); void removeExpiredTx(); - void deadlineTimerCb(ev::periodic &, int) { removeExpiredTx(); } + void deadlineTimerCb(ev::periodic&, int) { removeExpiredTx(); } - DBManager &dbMgr_; + DBManager& dbMgr_; Pprof pprof_; - const ServerConfig &serverConfig_; - Prometheus *prometheus_; - IStatsWatcher *statsWatcher_; + const ServerConfig& serverConfig_; + Prometheus* prometheus_; + IStatsWatcher* statsWatcher_; const std::string webRoot_; http::Router router_; @@ -150,7 +150,7 @@ class HTTPServer { std::atomic currentCsvDownloads_ = {0}; private: - Error execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults &res, http::Context &ctx); + Error execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults& res, http::Context& ctx); }; } // namespace reindexer_server diff --git a/cpp_src/server/loggerwrapper.h b/cpp_src/server/loggerwrapper.h index 08737a9d8..0636f002f 100644 --- a/cpp_src/server/loggerwrapper.h +++ b/cpp_src/server/loggerwrapper.h @@ -8,49 +8,85 @@ namespace reindexer_server { class LoggerWrapper { public: LoggerWrapper() = default; - LoggerWrapper(const char *name) : logger_(spdlog::get(name)) {} + LoggerWrapper(const char* name) : logger_(spdlog::get(name)) {} operator bool() const noexcept { return logger_ != nullptr; } template - void error(Args &&...args) const { + void error(spdlog::format_string_t fmt, Args&&... args) const { if (logger_) { - logger_->error(std::forward(args)...); + logger_->error(fmt, std::forward(args)...); + } + } + template + void error(const T& msg) const { + if (logger_) { + logger_->error(msg); } } template - void warn(Args &&...args) const { + void warn(spdlog::format_string_t fmt, Args&&... args) const { + if (logger_) { + logger_->warn(fmt, std::forward(args)...); + } + } + template + void warn(const T& msg) const { if (logger_) { - logger_->warn(std::forward(args)...); + logger_->warn(msg); } } template - void info(Args &&...args) const { + void info(spdlog::format_string_t fmt, Args&&... args) const { if (logger_) { - logger_->info(std::forward(args)...); + logger_->info(fmt, std::forward(args)...); + } + } + template + void info(const T& msg) const { + if (logger_) { + logger_->info(msg); } } template - void trace(Args &&...args) const { + void trace(spdlog::format_string_t fmt, Args&&... args) const { if (logger_) { - logger_->trace(std::forward(args)...); + logger_->trace(fmt, std::forward(args)...); + } + } + template + void trace(const T& msg) const { + if (logger_) { + logger_->trace(msg); } } template - void critical(Args &&...args) const { + void critical(spdlog::format_string_t fmt, Args&&... args) const { + if (logger_) { + logger_->critical(fmt, std::forward(args)...); + } + } + template + void critical(const T& msg) const { if (logger_) { - logger_->critical(std::forward(args)...); + logger_->critical(msg); } } template - void debug(Args &&...args) const { + void debug(spdlog::format_string_t fmt, Args&&... args) const { if (logger_) { - logger_->debug(std::forward(args)...); + logger_->debug(fmt, std::forward(args)...); + } + } + template + void debug(const T& msg) const { + if (logger_) { + logger_->debug(msg); } } @@ -59,9 +95,3 @@ class LoggerWrapper { }; } // namespace reindexer_server - -namespace fmt { -static inline void format_arg(fmt::BasicFormatter &f, const char *&, std::string_view s) { - f.writer() << fmt::BasicStringRef(s.data(), s.length()); -} -} // namespace fmt diff --git a/cpp_src/server/pidfile.h b/cpp_src/server/pidfile.h index dc9c3acfd..99c9fd254 100644 --- a/cpp_src/server/pidfile.h +++ b/cpp_src/server/pidfile.h @@ -16,16 +16,22 @@ namespace reindexer_server { class PidFile { public: PidFile(const std::string& name = std::string(), pid_t pid = -1) : file_(-1) { - if (!name.empty()) Open(name, pid); + if (!name.empty()) { + Open(name, pid); + } } ~PidFile() { - if (IsOpen()) Close(); + if (IsOpen()) { + Close(); + } } bool IsOpen() const { return file_ != -1; } bool Open(const std::string& name, pid_t pid = -1) { - if (IsOpen() || name.empty()) return false; + if (IsOpen() || name.empty()) { + return false; + } // open file int fd = ::open(name.c_str(), O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd == -1) { @@ -38,7 +44,9 @@ class PidFile { return false; } // get PID value and convert it to string - if (pid == -1) pid = ::getpid(); + if (pid == -1) { + pid = ::getpid(); + } std::string buf = fmt::sprintf("%d\n", pid); // write PID to file size_t rc = static_cast(::write(fd, buf.c_str(), buf.size())); @@ -68,8 +76,8 @@ class PidFile { reindexer::Error Status() { return error_; } private: - PidFile(PidFile const&); - PidFile& operator=(PidFile const&); + PidFile(const PidFile&); + PidFile& operator=(const PidFile&); private: int file_; diff --git a/cpp_src/server/pprof/gperf_profiler.cc b/cpp_src/server/pprof/gperf_profiler.cc index 50dd72fa2..116920809 100644 --- a/cpp_src/server/pprof/gperf_profiler.cc +++ b/cpp_src/server/pprof/gperf_profiler.cc @@ -9,17 +9,17 @@ #include #include #include "tools/alloc_ext/tc_malloc_extension.h" -#endif // _WIN32 +#endif // _WIN32 #ifdef _WIN32 void ProfilerRegisterThread() { ::ProfilerRegisterThread(); } -int ProfilerStart(const char *fname) { return ::ProfilerStart(); } +int ProfilerStart(const char* fname) { return ::ProfilerStart(); } void ProfilerStop() { ::ProfilerStop(); } -char *GetHeapProfile() { return ::GetHeapProfile(); } +char* GetHeapProfile() { return ::GetHeapProfile(); } bool GperfProfilerIsAvailable() { return true; } @@ -29,9 +29,9 @@ namespace reindexer_server { namespace pprof { using ProfilerRegisterThreadFn = void (*)(); -using ProfilerStartFn = int (*)(const char *); +using ProfilerStartFn = int (*)(const char*); using ProfilerStopFn = void (*)(); -using GetHeapProfileFn = char *(*)(); +using GetHeapProfileFn = char* (*)(); static ProfilerRegisterThreadFn getProfilerRegisterThreadFn() { static auto profiler_register_thread_fn = reinterpret_cast(dlsym(RTLD_DEFAULT, "ProfilerRegisterThread")); @@ -61,7 +61,7 @@ void ProfilerRegisterThread() { return; } -int ProfilerStart(const char *fname) { +int ProfilerStart(const char* fname) { auto profiler_start_fn = getProfilerStartFn(); if (profiler_start_fn) { return profiler_start_fn(fname); @@ -77,7 +77,7 @@ void ProfilerStop() { return; } -char *GetHeapProfile() { +char* GetHeapProfile() { auto get_heap_profile_fn = getGetHeapProfileFn(); if (get_heap_profile_fn) { return get_heap_profile_fn(); @@ -90,9 +90,9 @@ bool GperfProfilerIsAvailable() { (getProfilerStopFn() != nullptr) && (getGetHeapProfileFn() != nullptr); } -#endif //_WIN32 +#endif //_WIN32 } // namespace pprof } // namespace reindexer_server -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS diff --git a/cpp_src/server/pprof/gperf_profiler.h b/cpp_src/server/pprof/gperf_profiler.h index dc761e92f..5b2c02c71 100644 --- a/cpp_src/server/pprof/gperf_profiler.h +++ b/cpp_src/server/pprof/gperf_profiler.h @@ -6,12 +6,12 @@ namespace reindexer_server { namespace pprof { void ProfilerRegisterThread(); -int ProfilerStart(const char *fname); +int ProfilerStart(const char* fname); void ProfilerStop(); -char *GetHeapProfile(); +char* GetHeapProfile(); bool GperfProfilerIsAvailable(); } // namespace pprof } // namespace reindexer_server -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS diff --git a/cpp_src/server/pprof/pprof.cc b/cpp_src/server/pprof/pprof.cc index 489685d99..c85446aa2 100644 --- a/cpp_src/server/pprof/pprof.cc +++ b/cpp_src/server/pprof/pprof.cc @@ -16,7 +16,7 @@ static const std::string kProfileNamePrefix = "reindexer_server"; namespace reindexer_server { using namespace reindexer; -void Pprof::Attach(http::Router &router) { +void Pprof::Attach(http::Router& router) { router.GET("/debug/pprof/profile", this); router.GET("/pprof/profile", this); @@ -36,18 +36,24 @@ void Pprof::Attach(http::Router &router) { router.POST("/symbolz", this); } -int Pprof::Profile(http::Context &ctx) { +int Pprof::Profile(http::Context& ctx) { #if REINDEX_WITH_GPERFTOOLS long long seconds = 30; std::string_view secondsParam; std::string filePath = fs::JoinPath(fs::GetTempDir(), kProfileNamePrefix + ".profile"); for (auto p : ctx.request->params) { - if (p.name == "seconds") secondsParam = p.val; + if (p.name == "seconds") { + secondsParam = p.val; + } } - if (secondsParam.length()) seconds = stoi(secondsParam); - if (seconds < 1) seconds = 30; + if (secondsParam.length()) { + seconds = stoi(secondsParam); + } + if (seconds < 1) { + seconds = 30; + } if (alloc_ext::TCMallocIsAvailable()) { pprof::ProfilerStart(filePath.c_str()); @@ -66,11 +72,11 @@ int Pprof::Profile(http::Context &ctx) { #endif } -int Pprof::ProfileHeap(http::Context &ctx) { +int Pprof::ProfileHeap(http::Context& ctx) { #if REINDEX_WITH_GPERFTOOLS if (pprof::GperfProfilerIsAvailable()) { if (std::getenv("HEAPPROFILE")) { - char *profile = pprof::GetHeapProfile(); + char* profile = pprof::GetHeapProfile(); int res = ctx.String(http::StatusOK, profile); free(profile); return res; @@ -84,7 +90,7 @@ int Pprof::ProfileHeap(http::Context &ctx) { #elif REINDEX_WITH_JEMALLOC std::string content; std::string filePath = fs::JoinPath(fs::GetTempDir(), kProfileNamePrefix + ".heapprofile"); - const char *pfp = &filePath[0]; + const char* pfp = &filePath[0]; alloc_ext::mallctl("prof.dump", NULL, NULL, &pfp, sizeof(pfp)); if (fs::ReadFile(filePath, content) < 0) { @@ -97,7 +103,7 @@ int Pprof::ProfileHeap(http::Context &ctx) { #endif } -int Pprof::Growth(http::Context &ctx) { +int Pprof::Growth(http::Context& ctx) { #if REINDEX_WITH_GPERFTOOLS if (alloc_ext::TCMallocIsAvailable()) { std::string output; @@ -111,9 +117,9 @@ int Pprof::Growth(http::Context &ctx) { #endif } -int Pprof::CmdLine(http::Context &ctx) { return ctx.String(http::StatusOK, "reindexer_server"); } +int Pprof::CmdLine(http::Context& ctx) { return ctx.String(http::StatusOK, "reindexer_server"); } -int Pprof::Symbol(http::Context &ctx) { +int Pprof::Symbol(http::Context& ctx) { using namespace std::string_view_literals; WrSerializer ser; @@ -130,10 +136,12 @@ int Pprof::Symbol(http::Context &ctx) { return ctx.String(http::StatusOK, ser.DetachChunk()); } - char *endp; + char* endp; for (size_t pos = 0; pos != std::string::npos; pos = req.find_first_of(" +", pos)) { pos = req.find_first_not_of(" +", pos); - if (pos == std::string::npos) break; + if (pos == std::string::npos) { + break; + } uintptr_t addr = strtoull(&req[pos], &endp, 16); ser << std::string_view(&req[pos], endp - &req[pos]) << '\t'; resolveSymbol(addr, ser); @@ -143,7 +151,7 @@ int Pprof::Symbol(http::Context &ctx) { return ctx.String(http::StatusOK, ser.DetachChunk()); } -void Pprof::resolveSymbol(uintptr_t ptr, WrSerializer &out) { +void Pprof::resolveSymbol(uintptr_t ptr, WrSerializer& out) { auto te = debug::TraceEntry(ptr); std::string_view symbol = te.FuncName(); @@ -169,7 +177,9 @@ void Pprof::resolveSymbol(uintptr_t ptr, WrSerializer &out) { tmpl--; break; default: - if (tmpl == 0) out << symbol[p]; + if (tmpl == 0) { + out << symbol[p]; + } } p++; } diff --git a/cpp_src/server/pprof/pprof.h b/cpp_src/server/pprof/pprof.h index d1c1c6e13..f76cc15a8 100644 --- a/cpp_src/server/pprof/pprof.h +++ b/cpp_src/server/pprof/pprof.h @@ -12,16 +12,16 @@ using reindexer::WrSerializer; class Pprof { public: - void Attach(http::Router &router); + void Attach(http::Router& router); - int Profile(http::Context &ctx); - int ProfileHeap(http::Context &ctx); - int Growth(http::Context &ctx); - int CmdLine(http::Context &ctx); - int Symbol(http::Context &ctx); + int Profile(http::Context& ctx); + int ProfileHeap(http::Context& ctx); + int Growth(http::Context& ctx); + int CmdLine(http::Context& ctx); + int Symbol(http::Context& ctx); protected: - void resolveSymbol(uintptr_t ptr, WrSerializer &out); + void resolveSymbol(uintptr_t ptr, WrSerializer& out); }; } // namespace reindexer_server diff --git a/cpp_src/server/resources_wrapper.cc b/cpp_src/server/resources_wrapper.cc index 0e6e86442..108cb2ca1 100644 --- a/cpp_src/server/resources_wrapper.cc +++ b/cpp_src/server/resources_wrapper.cc @@ -7,7 +7,9 @@ namespace reindexer_server { DocumentStatus web::fsStatus(const std::string& target) { - if (webRoot_.empty()) return DocumentStatus{}; + if (webRoot_.empty()) { + return DocumentStatus{}; + } DocumentStatus status; status.fstatus = reindexer::fs::Stat(webRoot_ + target); if (status.fstatus == reindexer::fs::StatError) { diff --git a/cpp_src/server/rpcqrwatcher.h b/cpp_src/server/rpcqrwatcher.h index 82a1e3aca..54bab1eb9 100644 --- a/cpp_src/server/rpcqrwatcher.h +++ b/cpp_src/server/rpcqrwatcher.h @@ -48,7 +48,9 @@ class RPCQrWatcher { } } QueryResults& operator*() { - if (!d_.qr) throw Error(errLogic, "Query results' pointer is nullptr"); + if (!d_.qr) { + throw Error(errLogic, "Query results' pointer is nullptr"); + } return *d_.qr; } uint32_t ID() const noexcept { return d_.id; } @@ -149,8 +151,7 @@ class RPCQrWatcher { }; UID() noexcept : freed(0), state(Uninitialized), refs(0), val(0) {} - UID(int64_t uid, bool addRef) - noexcept + UID(int64_t uid, bool addRef) noexcept : freed(0), state(uid >= 0 ? InitializedUIDEnabled : InitializedUIDDisabled), refs(addRef ? 1 : 0), val(uid >= 0 ? uid : 0) { assertf(uid == kDisabled || val == (uid & kUIDValueBitmask), "UID: %d, val: %d", uid, val); } diff --git a/cpp_src/server/rpcserver.cc b/cpp_src/server/rpcserver.cc index 5e4133c7f..837a56423 100644 --- a/cpp_src/server/rpcserver.cc +++ b/cpp_src/server/rpcserver.cc @@ -16,8 +16,8 @@ using namespace std::string_view_literals; const reindexer::SemVersion kMinUnknownReplSupportRxVersion("2.6.0"); constexpr size_t kMaxTxCount = 1024; -RPCServer::RPCServer(DBManager &dbMgr, LoggerWrapper &logger, IClientsStats *clientsStats, const ServerConfig &scfg, - IStatsWatcher *statsCollector) +RPCServer::RPCServer(DBManager& dbMgr, LoggerWrapper& logger, IClientsStats* clientsStats, const ServerConfig& scfg, + IStatsWatcher* statsCollector) : dbMgr_(dbMgr), serverConfig_(scfg), logger_(logger), @@ -33,14 +33,14 @@ RPCServer::~RPCServer() { listener_.reset(); } -Error RPCServer::Ping(cproto::Context &) { +Error RPCServer::Ping(cproto::Context&) { // return {}; } static std::atomic connCounter; -Error RPCServer::Login(cproto::Context &ctx, p_string login, p_string password, p_string db, std::optional createDBIfMissing, +Error RPCServer::Login(cproto::Context& ctx, p_string login, p_string password, p_string db, std::optional createDBIfMissing, std::optional checkClusterID, std::optional expectedClusterID, std::optional clientRxVersion, std::optional appName) { if (ctx.GetClientData()) { @@ -48,7 +48,7 @@ Error RPCServer::Login(cproto::Context &ctx, p_string login, p_string password, } auto clientData = std::make_unique(); - auto &clientDataRef = *clientData; + auto& clientDataRef = *clientData; clientData->connID = connCounter.fetch_add(1, std::memory_order_relaxed); clientData->pusher.SetWriter(ctx.writer); @@ -72,7 +72,7 @@ Error RPCServer::Login(cproto::Context &ctx, p_string login, p_string password, clientData->rxVersion = SemVersion(); } if (clientData->rxVersion < kMinUnknownReplSupportRxVersion) { - clientData->pusher.SetFilter([](WALRecord &rec) { + clientData->pusher.SetFilter([](WALRecord& rec) { if (rec.type == WalCommitTransaction || rec.type == WalInitTransaction || rec.type == WalSetSchema) { return true; } @@ -111,16 +111,18 @@ Error RPCServer::Login(cproto::Context &ctx, p_string login, p_string password, return status; } -static RPCClientData *getClientDataUnsafe(cproto::Context &ctx) noexcept { return dynamic_cast(ctx.GetClientData()); } +static RPCClientData* getClientDataUnsafe(cproto::Context& ctx) noexcept { return dynamic_cast(ctx.GetClientData()); } -static RPCClientData *getClientDataSafe(cproto::Context &ctx) noexcept { - auto ret = dynamic_cast(ctx.GetClientData()); - if rx_unlikely (!ret) std::abort(); // It has to be set by the middleware +static RPCClientData* getClientDataSafe(cproto::Context& ctx) noexcept { + auto ret = dynamic_cast(ctx.GetClientData()); + if rx_unlikely (!ret) { + std::abort(); // It has to be set by the middleware + } return ret; } -Error RPCServer::OpenDatabase(cproto::Context &ctx, p_string db, std::optional createDBIfMissing) { - auto *clientData = getClientDataSafe(ctx); +Error RPCServer::OpenDatabase(cproto::Context& ctx, p_string db, std::optional createDBIfMissing) { + auto* clientData = getClientDataSafe(ctx); if (clientData->auth.HaveDB()) { return Error(errParams, "Database already opened"); } @@ -131,11 +133,11 @@ Error RPCServer::OpenDatabase(cproto::Context &ctx, p_string db, std::optionalauth.ResetDB(); return {}; } -Error RPCServer::DropDatabase(cproto::Context &ctx) { +Error RPCServer::DropDatabase(cproto::Context& ctx) { auto clientData = getClientDataSafe(ctx); if (statsWatcher_) { // Avoid database access from the stats collecting thread during database drop @@ -145,9 +147,9 @@ Error RPCServer::DropDatabase(cproto::Context &ctx) { return dbMgr_.DropDatabase(clientData->auth); } -Error RPCServer::CheckAuth(cproto::Context &ctx) { - cproto::ClientData *ptr = ctx.GetClientData(); - auto clientData = dynamic_cast(ptr); +Error RPCServer::CheckAuth(cproto::Context& ctx) { + cproto::ClientData* ptr = ctx.GetClientData(); + auto clientData = dynamic_cast(ptr); if (ctx.call->cmd == cproto::kCmdLogin || ctx.call->cmd == cproto::kCmdPing) { return {}; @@ -160,7 +162,7 @@ Error RPCServer::CheckAuth(cproto::Context &ctx) { return {}; } -void RPCServer::OnClose(cproto::Context &ctx, const Error &err) { +void RPCServer::OnClose(cproto::Context& ctx, const Error& err) { (void)ctx; (void)err; @@ -172,7 +174,7 @@ void RPCServer::OnClose(cproto::Context &ctx, const Error &err) { if (clientsStats_) { clientsStats_->DeleteConnection(clientData->connID); } - for (auto &qrId : clientData->results) { + for (auto& qrId : clientData->results) { if (qrId.main >= 0) { try { qrWatcher_.FreeQueryResults(qrId, false); @@ -186,11 +188,11 @@ void RPCServer::OnClose(cproto::Context &ctx, const Error &err) { logger_.info("RPC: Client disconnected"); } -void RPCServer::OnResponse(cproto::Context &ctx) { +void RPCServer::OnResponse(cproto::Context& ctx) { if (statsWatcher_) { auto clientData = getClientDataUnsafe(ctx); static const std::string kUnknownDbName(""); - const std::string &dbName = (clientData != nullptr) ? clientData->auth.DBName() : kUnknownDbName; + const std::string& dbName = (clientData != nullptr) ? clientData->auth.DBName() : kUnknownDbName; statsWatcher_->OnOutputTraffic(dbName, statsSourceName(), protocolName_, ctx.stat.sizeStat.respSizeBytes); if (ctx.stat.sizeStat.respSizeBytes) { // Don't update stats on responses like "updates push" @@ -199,7 +201,7 @@ void RPCServer::OnResponse(cproto::Context &ctx) { } } -Error RPCServer::execSqlQueryByType(std::string_view sqlQuery, QueryResults &res, cproto::Context &ctx) noexcept { +Error RPCServer::execSqlQueryByType(std::string_view sqlQuery, QueryResults& res, cproto::Context& ctx) noexcept { try { const auto q = Query::FromSQL(sqlQuery); switch (q.Type()) { @@ -217,7 +219,7 @@ Error RPCServer::execSqlQueryByType(std::string_view sqlQuery, QueryResults &res CATCH_AND_RETURN; } -void RPCServer::Logger(cproto::Context &ctx, const Error &err, const cproto::Args &ret) { +void RPCServer::Logger(cproto::Context& ctx, const Error& err, const cproto::Args& ret) { const auto clientData = getClientDataUnsafe(ctx); uint8_t buf[0x500]; WrSerializer ser(buf); @@ -251,7 +253,7 @@ void RPCServer::Logger(cproto::Context &ctx, const Error &err, const cproto::Arg logger_.info("{}", ser.Slice()); } -Error RPCServer::OpenNamespace(cproto::Context &ctx, p_string nsDefJson) { +Error RPCServer::OpenNamespace(cproto::Context& ctx, p_string nsDefJson) { NamespaceDef nsDef; if (auto err = nsDef.FromJSON(giftStr(nsDefJson)); !err.ok()) { @@ -263,29 +265,33 @@ Error RPCServer::OpenNamespace(cproto::Context &ctx, p_string nsDefJson) { return getDB(ctx, kRoleDataRead).OpenNamespace(nsDef.name, nsDef.storage); } -Error RPCServer::DropNamespace(cproto::Context &ctx, p_string ns) { +Error RPCServer::DropNamespace(cproto::Context& ctx, p_string ns) { // return getDB(ctx, kRoleDBAdmin).DropNamespace(ns); } -Error RPCServer::TruncateNamespace(cproto::Context &ctx, p_string ns) { return getDB(ctx, kRoleDBAdmin).TruncateNamespace(ns); } +Error RPCServer::TruncateNamespace(cproto::Context& ctx, p_string ns) { return getDB(ctx, kRoleDBAdmin).TruncateNamespace(ns); } -Error RPCServer::RenameNamespace(cproto::Context &ctx, p_string srcNsName, p_string dstNsName) { +Error RPCServer::RenameNamespace(cproto::Context& ctx, p_string srcNsName, p_string dstNsName) { return getDB(ctx, kRoleDBAdmin).RenameNamespace(srcNsName, dstNsName.toString()); } -Error RPCServer::CloseNamespace(cproto::Context &ctx, p_string ns) { +Error RPCServer::CloseNamespace(cproto::Context& ctx, p_string ns) { // Do not close. // TODO: add reference counters // return getDB(ctx, kRoleDataRead)->CloseNamespace(ns); return getDB(ctx, kRoleDataRead).Commit(ns); } -Error RPCServer::EnumNamespaces(cproto::Context &ctx, std::optional opts, std::optional filter) { +Error RPCServer::EnumNamespaces(cproto::Context& ctx, std::optional opts, std::optional filter) { std::vector nsDefs; EnumNamespacesOpts eopts; - if (opts) eopts.options_ = *opts; - if (filter) eopts.filter_ = *filter; + if (opts) { + eopts.options_ = *opts; + } + if (filter) { + eopts.filter_ = *filter; + } auto err = getDB(ctx, kRoleDataRead).EnumNamespaces(nsDefs, eopts); if (!err.ok()) { @@ -294,7 +300,9 @@ Error RPCServer::EnumNamespaces(cproto::Context &ctx, std::optional opts, s WrSerializer ser; ser << "{\"items\":["; for (unsigned i = 0; i < nsDefs.size(); i++) { - if (i != 0) ser << ','; + if (i != 0) { + ser << ','; + } nsDefs[i].GetJSON(ser); } ser << "]}"; @@ -304,7 +312,7 @@ Error RPCServer::EnumNamespaces(cproto::Context &ctx, std::optional opts, s return errOK; } -Error RPCServer::EnumDatabases(cproto::Context &ctx) { +Error RPCServer::EnumDatabases(cproto::Context& ctx) { auto dbList = dbMgr_.EnumDatabases(); WrSerializer ser; @@ -319,7 +327,7 @@ Error RPCServer::EnumDatabases(cproto::Context &ctx) { return errOK; } -Error RPCServer::AddIndex(cproto::Context &ctx, p_string ns, p_string indexDef) { +Error RPCServer::AddIndex(cproto::Context& ctx, p_string ns, p_string indexDef) { IndexDef iDef; auto err = iDef.FromJSON(giftStr(indexDef)); if (!err.ok()) { @@ -328,7 +336,7 @@ Error RPCServer::AddIndex(cproto::Context &ctx, p_string ns, p_string indexDef) return getDB(ctx, kRoleDBAdmin).AddIndex(ns, iDef); } -Error RPCServer::UpdateIndex(cproto::Context &ctx, p_string ns, p_string indexDef) { +Error RPCServer::UpdateIndex(cproto::Context& ctx, p_string ns, p_string indexDef) { IndexDef iDef; auto err = iDef.FromJSON(giftStr(indexDef)); if (!err.ok()) { @@ -337,29 +345,29 @@ Error RPCServer::UpdateIndex(cproto::Context &ctx, p_string ns, p_string indexDe return getDB(ctx, kRoleDBAdmin).UpdateIndex(ns, iDef); } -Error RPCServer::DropIndex(cproto::Context &ctx, p_string ns, p_string index) { +Error RPCServer::DropIndex(cproto::Context& ctx, p_string ns, p_string index) { IndexDef idef(index.toString()); return getDB(ctx, kRoleDBAdmin).DropIndex(ns, idef); } -Error RPCServer::SetSchema(cproto::Context &ctx, p_string ns, p_string schema) { +Error RPCServer::SetSchema(cproto::Context& ctx, p_string ns, p_string schema) { return getDB(ctx, kRoleDBAdmin).SetSchema(ns, std::string_view(schema)); } -Error RPCServer::StartTransaction(cproto::Context &ctx, p_string nsName) { +Error RPCServer::StartTransaction(cproto::Context& ctx, p_string nsName) { int64_t id = -1; try { id = addTx(ctx, nsName); - } catch (reindexer::Error &e) { + } catch (reindexer::Error& e) { return e; } ctx.Return({cproto::Arg(id)}); return errOK; } -Error RPCServer::AddTxItem(cproto::Context &ctx, int format, p_string itemData, int mode, p_string perceptsPack, int stateToken, +Error RPCServer::AddTxItem(cproto::Context& ctx, int format, p_string itemData, int mode, p_string perceptsPack, int stateToken, int64_t txID) { - Transaction &tr = getTx(ctx, txID); + Transaction& tr = getTx(ctx, txID); auto item = tr.NewItem(); Error err; @@ -395,11 +403,11 @@ Error RPCServer::AddTxItem(cproto::Context &ctx, int format, p_string itemData, return err; } -Error RPCServer::DeleteQueryTx(cproto::Context &ctx, p_string queryBin, int64_t txID) noexcept { +Error RPCServer::DeleteQueryTx(cproto::Context& ctx, p_string queryBin, int64_t txID) noexcept { try { auto db = getDB(ctx, kRoleDataWrite); - Transaction &tr = getTx(ctx, txID); + Transaction& tr = getTx(ctx, txID); Serializer ser(queryBin.data(), queryBin.size()); Query query = Query::Deserialize(ser); query.type_ = QueryDelete; @@ -409,11 +417,11 @@ Error RPCServer::DeleteQueryTx(cproto::Context &ctx, p_string queryBin, int64_t CATCH_AND_RETURN; } -Error RPCServer::UpdateQueryTx(cproto::Context &ctx, p_string queryBin, int64_t txID) noexcept { +Error RPCServer::UpdateQueryTx(cproto::Context& ctx, p_string queryBin, int64_t txID) noexcept { try { auto db = getDB(ctx, kRoleDataWrite); - Transaction &tr = getTx(ctx, txID); + Transaction& tr = getTx(ctx, txID); Serializer ser(queryBin.data(), queryBin.size()); Query query = Query::Deserialize(ser); query.type_ = QueryUpdate; @@ -423,10 +431,10 @@ Error RPCServer::UpdateQueryTx(cproto::Context &ctx, p_string queryBin, int64_t CATCH_AND_RETURN; } -Error RPCServer::CommitTx(cproto::Context &ctx, int64_t txId, std::optional flagsOpts) { +Error RPCServer::CommitTx(cproto::Context& ctx, int64_t txId, std::optional flagsOpts) { auto db = getDB(ctx, kRoleDataWrite); - Transaction &tr = getTx(ctx, txId); + Transaction& tr = getTx(ctx, txId); QueryResults qres; auto err = db.CommitTransaction(tr, qres); @@ -438,7 +446,9 @@ Error RPCServer::CommitTx(cproto::Context &ctx, int64_t txId, std::optional flags = *flagsOpts; } else { flags = kResultsWithItemID; - if (tr.IsTagsUpdated()) flags |= kResultsWithPayloadTypes; + if (tr.IsTagsUpdated()) { + flags |= kResultsWithPayloadTypes; + } } if (tr.IsTagsUpdated()) { opts = ResultFetchOpts{ @@ -453,16 +463,16 @@ Error RPCServer::CommitTx(cproto::Context &ctx, int64_t txId, std::optional return err; } -Error RPCServer::RollbackTx(cproto::Context &ctx, int64_t txId) { +Error RPCServer::RollbackTx(cproto::Context& ctx, int64_t txId) { auto db = getDB(ctx, kRoleDataWrite); - Transaction &tr = getTx(ctx, txId); + Transaction& tr = getTx(ctx, txId); auto err = db.RollBackTransaction(tr); clearTx(ctx, txId); return err; } -Error RPCServer::ModifyItem(cproto::Context &ctx, p_string ns, int format, p_string itemData, int mode, p_string perceptsPack, +Error RPCServer::ModifyItem(cproto::Context& ctx, p_string ns, int format, p_string itemData, int mode, p_string perceptsPack, int stateToken, int /*txID*/) { using std::chrono::milliseconds; using std::chrono::duration_cast; @@ -516,7 +526,9 @@ Error RPCServer::ModifyItem(cproto::Context &ctx, p_string ns, int format, p_str precepts.emplace_back(ser.GetVString()); } item.SetPrecepts(precepts); - if (preceptsCount) sendItemBack = true; + if (preceptsCount) { + sendItemBack = true; + } } QueryResults qres; if (sendItemBack) { @@ -536,7 +548,9 @@ Error RPCServer::ModifyItem(cproto::Context &ctx, p_string ns, int format, p_str default: return Error(errParams, "Unexpected ItemModifyMode: %d", mode); } - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } else { switch (mode) { case ModeUpsert: @@ -554,7 +568,9 @@ Error RPCServer::ModifyItem(cproto::Context &ctx, p_string ns, int format, p_str default: return Error(errParams, "Unexpected ItemModifyMode: %d", mode); } - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } qres.AddItem(item); } int32_t ptVers = -1; @@ -580,7 +596,7 @@ Error RPCServer::ModifyItem(cproto::Context &ctx, p_string ns, int format, p_str return sendResults(ctx, qres, RPCQrId(), opts); } -Error RPCServer::DeleteQuery(cproto::Context &ctx, p_string queryBin, std::optional flagsOpts) noexcept { +Error RPCServer::DeleteQuery(cproto::Context& ctx, p_string queryBin, std::optional flagsOpts) noexcept { try { Serializer ser(queryBin.data(), queryBin.size()); Query query = Query::Deserialize(ser); @@ -605,7 +621,7 @@ Error RPCServer::DeleteQuery(cproto::Context &ctx, p_string queryBin, std::optio CATCH_AND_RETURN; } -Error RPCServer::UpdateQuery(cproto::Context &ctx, p_string queryBin, std::optional flagsOpts) noexcept { +Error RPCServer::UpdateQuery(cproto::Context& ctx, p_string queryBin, std::optional flagsOpts) noexcept { try { Serializer ser(queryBin.data(), queryBin.size()); Query query = Query::Deserialize(ser); @@ -621,7 +637,9 @@ Error RPCServer::UpdateQuery(cproto::Context &ctx, p_string queryBin, std::optio int32_t ptVersion = -1; int flags = kResultsWithItemID | kResultsWithPayloadTypes | kResultsCJson; - if (flagsOpts) flags = *flagsOpts; + if (flagsOpts) { + flags = *flagsOpts; + } ResultFetchOpts opts{ .flags = flags, .ptVersions = {&ptVersion, 1}, .fetchOffset = 0, .fetchLimit = INT_MAX, .withAggregations = true}; return sendResults(ctx, qres, RPCQrId(), opts); @@ -629,10 +647,10 @@ Error RPCServer::UpdateQuery(cproto::Context &ctx, p_string queryBin, std::optio CATCH_AND_RETURN; } -Reindexer RPCServer::getDB(cproto::Context &ctx, UserRole role) { - auto clientData = dynamic_cast(ctx.GetClientData()); +Reindexer RPCServer::getDB(cproto::Context& ctx, UserRole role) { + auto clientData = dynamic_cast(ctx.GetClientData()); if (rx_likely(clientData)) { - Reindexer *db = nullptr; + Reindexer* db = nullptr; auto status = clientData->auth.GetDB(role, &db); if rx_unlikely (!status.ok()) { throw status; @@ -646,7 +664,7 @@ Reindexer RPCServer::getDB(cproto::Context &ctx, UserRole role) { throw Error(errParams, "Database is not opened, you should open it first"); } -Error RPCServer::sendResults(cproto::Context &ctx, QueryResults &qres, RPCQrId id, const ResultFetchOpts &opts) { +Error RPCServer::sendResults(cproto::Context& ctx, QueryResults& qres, RPCQrId id, const ResultFetchOpts& opts) { uint8_t serBuf[0x2000]; WrResultSerializer rser(serBuf, opts); try { @@ -658,7 +676,7 @@ Error RPCServer::sendResults(cproto::Context &ctx, QueryResults &qres, RPCQrId i } std::string_view resSlice = rser.Slice(); ctx.Return({cproto::Arg(p_string(&resSlice)), cproto::Arg(int(id.main)), cproto::Arg(int64_t(id.uid))}); - } catch (Error &err) { + } catch (Error& err) { if (id.main >= 0) { try { freeQueryResults(ctx, id); @@ -675,7 +693,7 @@ Error RPCServer::sendResults(cproto::Context &ctx, QueryResults &qres, RPCQrId i return errOK; } -Error RPCServer::processTxItem(DataFormat format, std::string_view itemData, Item &item, ItemModifyMode mode, +Error RPCServer::processTxItem(DataFormat format, std::string_view itemData, Item& item, ItemModifyMode mode, int stateToken) const noexcept { switch (format) { case FormatJson: @@ -696,7 +714,7 @@ Error RPCServer::processTxItem(DataFormat format, std::string_view itemData, Ite } } -RPCQrWatcher::Ref RPCServer::createQueryResults(cproto::Context &ctx, RPCQrId &id) { +RPCQrWatcher::Ref RPCServer::createQueryResults(cproto::Context& ctx, RPCQrId& id) { auto data = getClientDataSafe(ctx); assertrx(id.main < 0); @@ -704,7 +722,7 @@ RPCQrWatcher::Ref RPCServer::createQueryResults(cproto::Context &ctx, RPCQrId &i RPCQrWatcher::Ref qres; qres = qrWatcher_.GetQueryResults(id); - for (auto &qrId : data->results) { + for (auto& qrId : data->results) { if (qrId.main < 0 || qrId.main == id.main) { qrId = id; return qres; @@ -729,9 +747,9 @@ RPCQrWatcher::Ref RPCServer::createQueryResults(cproto::Context &ctx, RPCQrId &i return qres; } -void RPCServer::freeQueryResults(cproto::Context &ctx, RPCQrId id) { +void RPCServer::freeQueryResults(cproto::Context& ctx, RPCQrId id) { auto data = getClientDataSafe(ctx); - for (auto &qrId : data->results) { + for (auto& qrId : data->results) { if (qrId.main == id.main) { if (qrId.uid != id.uid) { if (!qrWatcher_.AreQueryResultsValid(RPCQrId{qrId.main, qrId.uid})) { @@ -748,7 +766,7 @@ void RPCServer::freeQueryResults(cproto::Context &ctx, RPCQrId id) { } } -Transaction &RPCServer::getTx(cproto::Context &ctx, int64_t id) { +Transaction& RPCServer::getTx(cproto::Context& ctx, int64_t id) { auto data = getClientDataSafe(ctx); if (size_t(id) >= data->txs.size() || data->txs[id].IsFree()) { @@ -757,7 +775,7 @@ Transaction &RPCServer::getTx(cproto::Context &ctx, int64_t id) { return data->txs[id]; } -int64_t RPCServer::addTx(cproto::Context &ctx, std::string_view nsName) { +int64_t RPCServer::addTx(cproto::Context& ctx, std::string_view nsName) { auto db = getDB(ctx, kRoleDataWrite); int64_t id = -1; auto data = getClientDataSafe(ctx); @@ -784,7 +802,7 @@ int64_t RPCServer::addTx(cproto::Context &ctx, std::string_view nsName) { data->txs.emplace_back(std::move(tr)); return int64_t(data->txs.size() - 1); } -void RPCServer::clearTx(cproto::Context &ctx, uint64_t txId) { +void RPCServer::clearTx(cproto::Context& ctx, uint64_t txId) { auto data = getClientDataSafe(ctx); if (txId >= data->txs.size()) { throw Error(errLogic, "Invalid tx id %d", txId); @@ -800,16 +818,18 @@ static h_vector pack2vec(p_string pack) { h_vector vec; int cnt = ser.GetVarUint(); vec.reserve(cnt); - for (int i = 0; i < cnt; i++) vec.emplace_back(ser.GetVarUint()); + for (int i = 0; i < cnt; i++) { + vec.emplace_back(ser.GetVarUint()); + } return vec; } -Error RPCServer::Select(cproto::Context &ctx, p_string queryBin, int flags, int limit, p_string ptVersionsPck) { +Error RPCServer::Select(cproto::Context& ctx, p_string queryBin, int flags, int limit, p_string ptVersionsPck) { Query query; Serializer ser(queryBin); try { query = Query::Deserialize(ser); - } catch (Error &err) { + } catch (Error& err) { return err; } @@ -824,7 +844,7 @@ Error RPCServer::Select(cproto::Context &ctx, p_string queryBin, int flags, int RPCQrId id{-1, (flags & kResultsSupportIdleTimeout) ? RPCQrWatcher::kUninitialized : RPCQrWatcher::kDisabled}; try { qres = createQueryResults(ctx, id); - } catch (Error &e) { + } catch (Error& e) { if (e.code() == errQrUIDMissmatch) { return e; } @@ -843,12 +863,12 @@ Error RPCServer::Select(cproto::Context &ctx, p_string queryBin, int flags, int return sendResults(ctx, *qres, id, opts); } -Error RPCServer::SelectSQL(cproto::Context &ctx, p_string querySql, int flags, int limit, p_string ptVersionsPck) { +Error RPCServer::SelectSQL(cproto::Context& ctx, p_string querySql, int flags, int limit, p_string ptVersionsPck) { RPCQrId id{-1, (flags & kResultsSupportIdleTimeout) ? RPCQrWatcher::kUninitialized : RPCQrWatcher::kDisabled}; RPCQrWatcher::Ref qres; try { qres = createQueryResults(ctx, id); - } catch (Error &e) { + } catch (Error& e) { if (e.code() == errQrUIDMissmatch) { return e; } @@ -869,13 +889,13 @@ Error RPCServer::SelectSQL(cproto::Context &ctx, p_string querySql, int flags, i return sendResults(ctx, *qres, id, opts); } -Error RPCServer::FetchResults(cproto::Context &ctx, int reqId, int flags, int offset, int limit, std::optional qrUID) { +Error RPCServer::FetchResults(cproto::Context& ctx, int reqId, int flags, int offset, int limit, std::optional qrUID) { flags &= ~kResultsWithPayloadTypes; RPCQrId id{reqId, qrUID ? *qrUID : RPCQrWatcher::kDisabled}; RPCQrWatcher::Ref qres; try { qres = qrWatcher_.GetQueryResults(id); - } catch (Error &e) { + } catch (Error& e) { if (e.code() == errQrUIDMissmatch) { return e; } @@ -887,35 +907,37 @@ Error RPCServer::FetchResults(cproto::Context &ctx, int reqId, int flags, int of return sendResults(ctx, *qres, id, opts); } -Error RPCServer::CloseResults(cproto::Context &ctx, int reqId, std::optional qrUID, std::optional doNotReply) { +Error RPCServer::CloseResults(cproto::Context& ctx, int reqId, std::optional qrUID, std::optional doNotReply) { if (doNotReply && *doNotReply) { ctx.respSent = true; } const RPCQrId id{reqId, qrUID ? *qrUID : RPCQrWatcher::kDisabled}; try { freeQueryResults(ctx, id); - } catch (Error &e) { + } catch (Error& e) { return e; } return errOK; } -Error RPCServer::GetSQLSuggestions(cproto::Context &ctx, p_string query, int pos) { +Error RPCServer::GetSQLSuggestions(cproto::Context& ctx, p_string query, int pos) { std::vector suggests; Error err = getDB(ctx, kRoleDataRead).GetSqlSuggestions(query, pos, suggests); if (err.ok()) { cproto::Args ret; ret.reserve(suggests.size()); - for (auto &suggest : suggests) ret.emplace_back(std::move(suggest)); + for (auto& suggest : suggests) { + ret.emplace_back(std::move(suggest)); + } ctx.Return(ret); } return err; } -Error RPCServer::Commit(cproto::Context &ctx, p_string ns) { return getDB(ctx, kRoleDataWrite).Commit(ns); } +Error RPCServer::Commit(cproto::Context& ctx, p_string ns) { return getDB(ctx, kRoleDataWrite).Commit(ns); } -Error RPCServer::GetMeta(cproto::Context &ctx, p_string ns, p_string key) { +Error RPCServer::GetMeta(cproto::Context& ctx, p_string ns, p_string key) { std::string data; auto err = getDB(ctx, kRoleDataRead).GetMeta(ns, key.toString(), data); if (!err.ok()) { @@ -926,29 +948,29 @@ Error RPCServer::GetMeta(cproto::Context &ctx, p_string ns, p_string key) { return errOK; } -Error RPCServer::PutMeta(cproto::Context &ctx, p_string ns, p_string key, p_string data) { +Error RPCServer::PutMeta(cproto::Context& ctx, p_string ns, p_string key, p_string data) { return getDB(ctx, kRoleDataWrite).PutMeta(ns, key.toString(), data); } -Error RPCServer::EnumMeta(cproto::Context &ctx, p_string ns) { +Error RPCServer::EnumMeta(cproto::Context& ctx, p_string ns) { std::vector keys; auto err = getDB(ctx, kRoleDataWrite).EnumMeta(ns, keys); if (!err.ok()) { return err; } cproto::Args ret; - for (auto &key : keys) { + for (auto& key : keys) { ret.emplace_back(std::move(key)); } ctx.Return(ret); return errOK; } -Error RPCServer::DeleteMeta(cproto::Context &ctx, p_string ns, p_string key) { +Error RPCServer::DeleteMeta(cproto::Context& ctx, p_string ns, p_string key) { return getDB(ctx, kRoleDataWrite).DeleteMeta(ns, key.toString()); } -Error RPCServer::SubscribeUpdates(cproto::Context &ctx, int flag, std::optional filterJson, std::optional options) { +Error RPCServer::SubscribeUpdates(cproto::Context& ctx, int flag, std::optional filterJson, std::optional options) { UpdatesFilters filters; Error ret; if (filterJson) { @@ -969,11 +991,13 @@ Error RPCServer::SubscribeUpdates(cproto::Context &ctx, int flag, std::optional< } else { ret = db.UnsubscribeUpdates(&clientData->pusher); } - if (ret.ok()) clientData->subscribed = bool(flag); + if (ret.ok()) { + clientData->subscribed = bool(flag); + } return ret; } -bool RPCServer::Start(const std::string &addr, ev::dynamic_loop &loop, RPCSocketT sockDomain, std::string_view threadingMode) { +bool RPCServer::Start(const std::string& addr, ev::dynamic_loop& loop, RPCSocketT sockDomain, std::string_view threadingMode) { dispatcher_.Register(cproto::kCmdPing, this, &RPCServer::Ping); dispatcher_.Register(cproto::kCmdLogin, this, &RPCServer::Login); dispatcher_.Register(cproto::kCmdOpenDatabase, this, &RPCServer::OpenDatabase); @@ -1034,7 +1058,7 @@ bool RPCServer::Start(const std::string &addr, ev::dynamic_loop &loop, RPCSocket assertrx(!qrWatcherThread_.joinable()); auto thLoop = std::make_unique(); - qrWatcherTerminateAsync_.set([](ev::async &a) { a.loop.break_loop(); }); + qrWatcherTerminateAsync_.set([](ev::async& a) { a.loop.break_loop(); }); qrWatcherTerminateAsync_.set(*thLoop); qrWatcherTerminateAsync_.start(); qrWatcherThread_ = std::thread([this, thLoop = std::move(thLoop)]() { @@ -1051,7 +1075,7 @@ bool RPCServer::Start(const std::string &addr, ev::dynamic_loop &loop, RPCSocket } RPCClientData::~RPCClientData() { - Reindexer *db = nullptr; + Reindexer* db = nullptr; auto err = auth.GetDB(kRoleNone, &db); if (subscribed && db && err.ok()) { err = db->UnsubscribeUpdates(&pusher); diff --git a/cpp_src/server/rpcserver.h b/cpp_src/server/rpcserver.h index a2d633e3d..d274ea48f 100644 --- a/cpp_src/server/rpcserver.h +++ b/cpp_src/server/rpcserver.h @@ -40,11 +40,11 @@ struct RPCClientData final : public cproto::ClientData { class RPCServer { public: - RPCServer(DBManager &dbMgr, LoggerWrapper &logger, IClientsStats *clientsStats, const ServerConfig &serverConfig, - IStatsWatcher *statsCollector = nullptr); + RPCServer(DBManager& dbMgr, LoggerWrapper& logger, IClientsStats* clientsStats, const ServerConfig& serverConfig, + IStatsWatcher* statsCollector = nullptr); ~RPCServer(); - bool Start(const std::string &addr, ev::dynamic_loop &loop, RPCSocketT sockDomain, std::string_view threadingMode); + bool Start(const std::string& addr, ev::dynamic_loop& loop, RPCSocketT sockDomain, std::string_view threadingMode); void Stop() { terminate_ = true; if (qrWatcherThread_.joinable()) { @@ -55,86 +55,86 @@ class RPCServer { terminate_ = false; } - Error Ping(cproto::Context &ctx); - Error Login(cproto::Context &ctx, p_string login, p_string password, p_string db, std::optional createDBIfMissing, + Error Ping(cproto::Context& ctx); + Error Login(cproto::Context& ctx, p_string login, p_string password, p_string db, std::optional createDBIfMissing, std::optional checkClusterID, std::optional expectedClusterID, std::optional clientRxVersion, std::optional appName); - Error OpenDatabase(cproto::Context &ctx, p_string db, std::optional createDBIfMissing); - Error CloseDatabase(cproto::Context &ctx); - Error DropDatabase(cproto::Context &ctx); + Error OpenDatabase(cproto::Context& ctx, p_string db, std::optional createDBIfMissing); + Error CloseDatabase(cproto::Context& ctx); + Error DropDatabase(cproto::Context& ctx); - Error OpenNamespace(cproto::Context &ctx, p_string ns); - Error DropNamespace(cproto::Context &ctx, p_string ns); - Error TruncateNamespace(cproto::Context &ctx, p_string ns); - Error RenameNamespace(cproto::Context &ctx, p_string srcNsName, p_string dstNsName); + Error OpenNamespace(cproto::Context& ctx, p_string ns); + Error DropNamespace(cproto::Context& ctx, p_string ns); + Error TruncateNamespace(cproto::Context& ctx, p_string ns); + Error RenameNamespace(cproto::Context& ctx, p_string srcNsName, p_string dstNsName); - Error CloseNamespace(cproto::Context &ctx, p_string ns); - Error EnumNamespaces(cproto::Context &ctx, std::optional opts, std::optional filter); - Error EnumDatabases(cproto::Context &ctx); + Error CloseNamespace(cproto::Context& ctx, p_string ns); + Error EnumNamespaces(cproto::Context& ctx, std::optional opts, std::optional filter); + Error EnumDatabases(cproto::Context& ctx); - Error AddIndex(cproto::Context &ctx, p_string ns, p_string indexDef); - Error UpdateIndex(cproto::Context &ctx, p_string ns, p_string indexDef); - Error DropIndex(cproto::Context &ctx, p_string ns, p_string index); + Error AddIndex(cproto::Context& ctx, p_string ns, p_string indexDef); + Error UpdateIndex(cproto::Context& ctx, p_string ns, p_string indexDef); + Error DropIndex(cproto::Context& ctx, p_string ns, p_string index); - Error SetSchema(cproto::Context &ctx, p_string ns, p_string schema); + Error SetSchema(cproto::Context& ctx, p_string ns, p_string schema); - Error Commit(cproto::Context &ctx, p_string ns); + Error Commit(cproto::Context& ctx, p_string ns); - Error ModifyItem(cproto::Context &ctx, p_string nsName, int format, p_string itemData, int mode, p_string percepsPack, int stateToken, + Error ModifyItem(cproto::Context& ctx, p_string nsName, int format, p_string itemData, int mode, p_string percepsPack, int stateToken, int txID); - Error StartTransaction(cproto::Context &ctx, p_string nsName); + Error StartTransaction(cproto::Context& ctx, p_string nsName); - Error AddTxItem(cproto::Context &ctx, int format, p_string itemData, int mode, p_string percepsPack, int stateToken, int64_t txID); - Error DeleteQueryTx(cproto::Context &ctx, p_string query, int64_t txID) noexcept; - Error UpdateQueryTx(cproto::Context &ctx, p_string query, int64_t txID) noexcept; + Error AddTxItem(cproto::Context& ctx, int format, p_string itemData, int mode, p_string percepsPack, int stateToken, int64_t txID); + Error DeleteQueryTx(cproto::Context& ctx, p_string query, int64_t txID) noexcept; + Error UpdateQueryTx(cproto::Context& ctx, p_string query, int64_t txID) noexcept; - Error CommitTx(cproto::Context &ctx, int64_t txId, std::optional flags); - Error RollbackTx(cproto::Context &ctx, int64_t txId); + Error CommitTx(cproto::Context& ctx, int64_t txId, std::optional flags); + Error RollbackTx(cproto::Context& ctx, int64_t txId); - Error DeleteQuery(cproto::Context &ctx, p_string query, std::optional flags) noexcept; - Error UpdateQuery(cproto::Context &ctx, p_string query, std::optional flags) noexcept; + Error DeleteQuery(cproto::Context& ctx, p_string query, std::optional flags) noexcept; + Error UpdateQuery(cproto::Context& ctx, p_string query, std::optional flags) noexcept; - Error Select(cproto::Context &ctx, p_string query, int flags, int limit, p_string ptVersions); - Error SelectSQL(cproto::Context &ctx, p_string query, int flags, int limit, p_string ptVersions); - Error FetchResults(cproto::Context &ctx, int reqId, int flags, int offset, int limit, std::optional qrUID); - Error CloseResults(cproto::Context &ctx, int reqId, std::optional qrUID, std::optional doNotReply); - Error GetSQLSuggestions(cproto::Context &ctx, p_string query, int pos); + Error Select(cproto::Context& ctx, p_string query, int flags, int limit, p_string ptVersions); + Error SelectSQL(cproto::Context& ctx, p_string query, int flags, int limit, p_string ptVersions); + Error FetchResults(cproto::Context& ctx, int reqId, int flags, int offset, int limit, std::optional qrUID); + Error CloseResults(cproto::Context& ctx, int reqId, std::optional qrUID, std::optional doNotReply); + Error GetSQLSuggestions(cproto::Context& ctx, p_string query, int pos); - Error GetMeta(cproto::Context &ctx, p_string ns, p_string key); - Error PutMeta(cproto::Context &ctx, p_string ns, p_string key, p_string data); - Error EnumMeta(cproto::Context &ctx, p_string ns); - Error DeleteMeta(cproto::Context &ctx, p_string ns, p_string key); - Error SubscribeUpdates(cproto::Context &ctx, int subscribe, std::optional filterJson, std::optional options); + Error GetMeta(cproto::Context& ctx, p_string ns, p_string key); + Error PutMeta(cproto::Context& ctx, p_string ns, p_string key, p_string data); + Error EnumMeta(cproto::Context& ctx, p_string ns); + Error DeleteMeta(cproto::Context& ctx, p_string ns, p_string key); + Error SubscribeUpdates(cproto::Context& ctx, int subscribe, std::optional filterJson, std::optional options); - Error CheckAuth(cproto::Context &ctx); - void Logger(cproto::Context &ctx, const Error &err, const cproto::Args &ret); - void OnClose(cproto::Context &ctx, const Error &err); - void OnResponse(cproto::Context &ctx); + Error CheckAuth(cproto::Context& ctx); + void Logger(cproto::Context& ctx, const Error& err, const cproto::Args& ret); + void OnClose(cproto::Context& ctx, const Error& err); + void OnResponse(cproto::Context& ctx); protected: - Error execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults &res, cproto::Context &ctx) noexcept; - Error sendResults(cproto::Context &ctx, QueryResults &qr, RPCQrId id, const ResultFetchOpts &opts); - Error processTxItem(DataFormat format, std::string_view itemData, Item &item, ItemModifyMode mode, int stateToken) const noexcept; + Error execSqlQueryByType(std::string_view sqlQuery, reindexer::QueryResults& res, cproto::Context& ctx) noexcept; + Error sendResults(cproto::Context& ctx, QueryResults& qr, RPCQrId id, const ResultFetchOpts& opts); + Error processTxItem(DataFormat format, std::string_view itemData, Item& item, ItemModifyMode mode, int stateToken) const noexcept; - RPCQrWatcher::Ref createQueryResults(cproto::Context &ctx, RPCQrId &id); - void freeQueryResults(cproto::Context &ctx, RPCQrId id); - Transaction &getTx(cproto::Context &ctx, int64_t id); - int64_t addTx(cproto::Context &ctx, std::string_view nsName); - void clearTx(cproto::Context &ctx, uint64_t txId); + RPCQrWatcher::Ref createQueryResults(cproto::Context& ctx, RPCQrId& id); + void freeQueryResults(cproto::Context& ctx, RPCQrId id); + Transaction& getTx(cproto::Context& ctx, int64_t id); + int64_t addTx(cproto::Context& ctx, std::string_view nsName); + void clearTx(cproto::Context& ctx, uint64_t txId); - Reindexer getDB(cproto::Context &ctx, UserRole role); + Reindexer getDB(cproto::Context& ctx, UserRole role); constexpr static std::string_view statsSourceName() noexcept { return std::string_view{"rpc"}; } - DBManager &dbMgr_; + DBManager& dbMgr_; cproto::Dispatcher dispatcher_; std::unique_ptr listener_; - const ServerConfig &serverConfig_; + const ServerConfig& serverConfig_; LoggerWrapper logger_; - IStatsWatcher *statsWatcher_; + IStatsWatcher* statsWatcher_; - IClientsStats *clientsStats_; + IClientsStats* clientsStats_; system_clock_w::time_point startTs_; std::thread qrWatcherThread_; diff --git a/cpp_src/server/rpcupdatespusher.cc b/cpp_src/server/rpcupdatespusher.cc index a7f7e279e..d6348b3ac 100644 --- a/cpp_src/server/rpcupdatespusher.cc +++ b/cpp_src/server/rpcupdatespusher.cc @@ -8,7 +8,7 @@ namespace cproto { RPCUpdatesPusher::RPCUpdatesPusher() : writer_(nullptr), seq_(0) {} -void RPCUpdatesPusher::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &walRec) { +void RPCUpdatesPusher::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& walRec) { SharedWALRecord pwalRec; if (filter_) { WALRecord rec = walRec; @@ -21,7 +21,7 @@ void RPCUpdatesPusher::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const pwalRec = walRec.GetShared(int64_t(LSNs.upstreamLSN_), int64_t(LSNs.originLSN_), nsName); } - writer_->CallRPC({[](IRPCCall *self, CmdCode &cmd, std::string_view &ns, Args &args) { + writer_->CallRPC({[](IRPCCall* self, CmdCode& cmd, std::string_view& ns, Args& args) { auto unpacked = SharedWALRecord(self->data_).Unpack(); cmd = kCmdUpdates; args = {Arg(unpacked.upstreamLSN), Arg(unpacked.nsName), Arg(unpacked.pwalRec), Arg(unpacked.originLSN)}; @@ -34,7 +34,7 @@ void RPCUpdatesPusher::OnWALUpdate(LSNPair LSNs, std::string_view nsName, const void RPCUpdatesPusher::OnUpdatesLost(std::string_view) {} -void RPCUpdatesPusher::OnConnectionState(const Error &) {} +void RPCUpdatesPusher::OnConnectionState(const Error&) {} } // namespace cproto } // namespace net diff --git a/cpp_src/server/rpcupdatespusher.h b/cpp_src/server/rpcupdatespusher.h index eda5fc2c5..f72ec952d 100644 --- a/cpp_src/server/rpcupdatespusher.h +++ b/cpp_src/server/rpcupdatespusher.h @@ -13,16 +13,16 @@ class Writer; class RPCUpdatesPusher : public reindexer::IUpdatesObserver { public: RPCUpdatesPusher(); - void SetWriter(Writer *writer) { writer_ = writer; } - void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord &walRec) override final; + void SetWriter(Writer* writer) { writer_ = writer; } + void OnWALUpdate(LSNPair LSNs, std::string_view nsName, const WALRecord& walRec) override final; void OnUpdatesLost(std::string_view nsName) override final; - void OnConnectionState(const Error &err) override final; - void SetFilter(std::function filter) { filter_ = std::move(filter); } + void OnConnectionState(const Error& err) override final; + void SetFilter(std::function filter) { filter_ = std::move(filter); } protected: - Writer *writer_; + Writer* writer_; std::atomic seq_; - std::function filter_; + std::function filter_; }; } // namespace cproto } // namespace net diff --git a/cpp_src/server/server.cc b/cpp_src/server/server.cc index 46801ff21..46d5082ae 100644 --- a/cpp_src/server/server.cc +++ b/cpp_src/server/server.cc @@ -5,16 +5,16 @@ namespace reindexer_server { Server::Server(ServerMode mode) : impl_(new ServerImpl(mode)) {} Server::~Server() {} -Error Server::InitFromCLI(int argc, char *argv[]) { return impl_->InitFromCLI(argc, argv); } -Error Server::InitFromFile(const char *filePath) { return impl_->InitFromFile(filePath); } -Error Server::InitFromYAML(const std::string &yaml) { return impl_->InitFromYAML(yaml); } +Error Server::InitFromCLI(int argc, char* argv[]) { return impl_->InitFromCLI(argc, argv); } +Error Server::InitFromFile(const char* filePath) { return impl_->InitFromFile(filePath); } +Error Server::InitFromYAML(const std::string& yaml) { return impl_->InitFromYAML(yaml); } int Server::Start() { return impl_->Start(); } void Server::Stop() { return impl_->Stop(); } void Server::EnableHandleSignals(bool enable) noexcept { impl_->EnableHandleSignals(enable); } -DBManager &Server::GetDBManager() noexcept { return impl_->GetDBManager(); } +DBManager& Server::GetDBManager() noexcept { return impl_->GetDBManager(); } bool Server::IsReady() const noexcept { return impl_->IsReady(); } bool Server::IsRunning() const noexcept { return impl_->IsRunning(); } void Server::ReopenLogFiles() { impl_->ReopenLogFiles(); } -std::string Server::GetCoreLogPath() const { return impl_->GetCoreLogPath(); }; +std::string Server::GetCoreLogPath() const { return impl_->GetCoreLogPath(); } } // namespace reindexer_server diff --git a/cpp_src/server/server.h b/cpp_src/server/server.h index 531d76722..cacd56b96 100644 --- a/cpp_src/server/server.h +++ b/cpp_src/server/server.h @@ -28,6 +28,7 @@ class Server { bool IsRunning() const noexcept; void ReopenLogFiles(); std::string GetCoreLogPath() const; + protected: std::unique_ptr impl_; }; diff --git a/cpp_src/server/serverimpl.cc b/cpp_src/server/serverimpl.cc index 6b2d15677..98ee4c095 100644 --- a/cpp_src/server/serverimpl.cc +++ b/cpp_src/server/serverimpl.cc @@ -15,6 +15,8 @@ #include "reindexer_version.h" #include "rpcserver.h" #include "serverimpl.h" +#include "spdlog/async.h" +#include "spdlog/sinks/stdout_color_sinks.h" #include "statscollect/prometheus.h" #include "statscollect/statscollector.h" #include "tools/alloc_ext/je_malloc_extension.h" @@ -61,7 +63,7 @@ ServerImpl::ServerImpl(ServerMode mode) async_.set(loop_); } -Error ServerImpl::InitFromCLI(int argc, char *argv[]) { +Error ServerImpl::InitFromCLI(int argc, char* argv[]) { Error err = config_.ParseCmd(argc, argv); if (!err.ok()) { if (err.code() == errParams) { @@ -75,7 +77,7 @@ Error ServerImpl::InitFromCLI(int argc, char *argv[]) { return init(); } -Error ServerImpl::InitFromFile(const char *filePath) { +Error ServerImpl::InitFromFile(const char* filePath) { Error err = config_.ParseFile(filePath); if (!err.ok()) { if (err.code() == errParams) { @@ -89,7 +91,7 @@ Error ServerImpl::InitFromFile(const char *filePath) { return init(); } -Error ServerImpl::InitFromYAML(const std::string &yaml) { +Error ServerImpl::InitFromYAML(const std::string& yaml) { Error err = config_.ParseYaml(yaml); if (!err.ok()) { if (err.code() == errParams) { @@ -118,19 +120,25 @@ Error ServerImpl::init() { GetDirPath(config_.CoreLog), GetDirPath(config_.HttpLog), GetDirPath(config_.RpcLog), GetDirPath(config_.ServerLog), config_.StoragePath}; - for (const std::string &dir : dirs) { + for (const std::string& dir : dirs) { err = TryCreateDirectory(dir); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } #ifndef _WIN32 err = ChownDir(dir, config_.UserName); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } #endif } #ifndef _WIN32 if (!config_.UserName.empty()) { err = ChangeUser(config_.UserName.c_str()); - if (!err.ok()) return err; + if (!err.ok()) { + return err; + } } signal(SIGPIPE, SIG_IGN); #endif @@ -166,7 +174,7 @@ int ServerImpl::Start() { }); if (config_.InstallSvc) { - auto &args = config_.Args(); + auto& args = config_.Args(); std::string cmdline = args.front(); for (size_t i = 1; i < args.size(); i++) { cmdline += " "; @@ -196,7 +204,7 @@ void ServerImpl::Stop() { void ServerImpl::ReopenLogFiles() { #ifndef _WIN32 - for (auto &sync : sinks_) { + for (auto& sync : sinks_) { sync.second->reopen(); } #endif @@ -212,7 +220,7 @@ int ServerImpl::run() { auto logger = spdlog::get("server"); if (logger) { logger->flush(); // Extra flush to avoid backtrace message drop due to logger overflow - logger->info("{}", out); + logger->critical("{}", out); logger->flush(); } else { std::cerr << out << std::endl; @@ -273,7 +281,7 @@ int ServerImpl::run() { heapWatcher = TCMallocHeapWathcher(alloc_ext::instance(), config_.AllocatorCacheLimit, config_.AllocatorCachePart, spdlog::get("server")); tcmallocHeapWatchDog.set(loop_); - tcmallocHeapWatchDog.set([&heapWatcher](ev::timer &, int) { heapWatcher.CheckHeapUsagePeriodic(); }); + tcmallocHeapWatchDog.set([&heapWatcher](ev::timer&, int) { heapWatcher.CheckHeapUsagePeriodic(); }); if (config_.AllocatorCacheLimit > 0 || config_.AllocatorCachePart > 0) { using fpSeconds = std::chrono::duration; @@ -342,7 +350,7 @@ int ServerImpl::run() { return EXIT_FAILURE; } #if defined(WITH_GRPC) - void *hGRPCService = nullptr; + void* hGRPCService = nullptr; #if REINDEX_WITH_LIBDL #ifdef __APPLE__ auto hGRPCServiceLib = dlopen("libreindexer_grpc_library.dylib", RTLD_NOW); @@ -366,7 +374,7 @@ int ServerImpl::run() { #endif #endif - auto sigCallback = [&](ev::sig &sig) { + auto sigCallback = [&](ev::sig& sig) { logger_.info("Signal received. Terminating..."); #ifndef REINDEX_WITH_ASAN if (config_.AllowNamespaceLeak && mode_ == ServerMode::Standalone) { @@ -377,7 +385,9 @@ int ServerImpl::run() { sig.loop.break_loop(); }; - if (statsCollector) statsCollector->Start(); + if (statsCollector) { + statsCollector->Start(); + } ev::sig sterm, sint, shup; @@ -389,7 +399,7 @@ int ServerImpl::run() { sint.set(sigCallback); sint.start(SIGINT); #ifndef _WIN32 - auto sigHupCallback = [&](ev::sig &sig) { + auto sigHupCallback = [&](ev::sig& sig) { (void)sig; ReopenLogFiles(); }; @@ -399,7 +409,7 @@ int ServerImpl::run() { #endif } - async_.set([](ev::async &a) { a.loop.break_loop(); }); + async_.set([](ev::async& a) { a.loop.break_loop(); }); async_.start(); running_ = true; @@ -408,7 +418,9 @@ int ServerImpl::run() { } logger_.info("Reindexer server terminating..."); - if (statsCollector) statsCollector->Stop(); + if (statsCollector) { + statsCollector->Stop(); + } logger_.info("Stats collector shutdown completed."); if (rpcServerUnix) { rpcServerUnix->Stop(); @@ -433,7 +445,7 @@ int ServerImpl::run() { #endif #endif - } catch (const Error &err) { + } catch (const Error& err) { logger_.error("Unhandled exception occurred: {0}", err.what()); } logger_.info("Reindexer server shutdown completed."); @@ -452,7 +464,9 @@ Error ServerImpl::daemonize() { switch (pid) { // child process case 0: - if (!pid_.Open(config_.DaemonPidFile.c_str())) return pid_.Status(); + if (!pid_.Open(config_.DaemonPidFile.c_str())) { + return pid_.Status(); + } umask(0); setsid(); if (chdir("/")) { @@ -480,27 +494,32 @@ Error ServerImpl::daemonize() { Error ServerImpl::loggerConfigure() { static std::once_flag loggerConfigured; std::call_once(loggerConfigured, [] { - spdlog::set_async_mode(16384, spdlog::async_overflow_policy::discard_log_msg, nullptr, std::chrono::seconds(2)); + spdlog::init_thread_pool(16384, 1); // Using single background thread with st-sinks + spdlog::flush_every(std::chrono::seconds(2)); spdlog::set_level(spdlog::level::trace); - spdlog::set_pattern("[%L%d/%m %T.%e %t] %v"); + spdlog::set_pattern("%^[%L%d/%m %T.%e %t] %v%$", spdlog::pattern_time_type::utc); }); - std::vector> loggers = { + const std::vector> loggers = { {"server", config_.ServerLog}, {"core", config_.CoreLog}, {"http", config_.HttpLog}, {"rpc", config_.RpcLog}}; - for (auto &logger : loggers) { - auto &fileName = logger.second; + for (auto& logger : loggers) { + auto& fileName = logger.second; try { if (fileName == "stdout" || fileName == "-") { - spdlog::stdout_color_mt(logger.first); + using LogFactoryT = spdlog::async_factory_impl; + LogFactoryT::create(logger.first); } else if (!fileName.empty() && fileName != "none") { auto sink = sinks_.find(fileName); if (sink == sinks_.end()) { - sink = sinks_.emplace(fileName, std::make_shared(fileName)).first; + auto sptr = std::make_shared(fileName); + sink = sinks_.emplace(fileName, std::move(sptr)).first; } - spdlog::create(logger.first, sink->second); + auto lptr = std::make_shared(logger.first, sink->second, spdlog::thread_pool(), + spdlog::async_overflow_policy::discard_new); + spdlog::initialize_logger(std::move(lptr)); } - } catch (const spdlog::spdlog_ex &e) { + } catch (const spdlog::spdlog_ex& e) { return Error(errLogic, "Can't create logger for '%s' to file '%s': %s\n", logger.first, logger.second, e.what()); } } @@ -511,7 +530,7 @@ Error ServerImpl::loggerConfigure() { void ServerImpl::initCoreLogger() { std::weak_ptr logger = spdlog::get("core"); - auto callback = [this, logger](int level, char *buf) { + auto callback = [this, logger](int level, char* buf) { auto slogger = logger.lock(); if (slogger && level <= coreLogLevel_) { switch (level) { @@ -536,7 +555,8 @@ void ServerImpl::initCoreLogger() { } }; if (coreLogLevel_ && logger.lock()) { - reindexer::logInstallWriter(callback, mode_ == ServerMode::Standalone ? LoggerPolicy::WithoutLocks : LoggerPolicy::WithLocks); + reindexer::logInstallWriter(callback, mode_ == ServerMode::Standalone ? LoggerPolicy::WithoutLocks : LoggerPolicy::WithLocks, + coreLogLevel_); } } @@ -546,9 +566,15 @@ ServerImpl::~ServerImpl() { rxAllowNamespaceLeak = true; } #endif +#ifdef _WIN32 + // Windows must to call shutdown explicitly, otherwise it will stuck + logInstallWriter(nullptr, mode_ == ServerMode::Standalone ? LoggerPolicy::WithoutLocks : LoggerPolicy::WithLocks, int(LogNone)); + spdlog::shutdown(); +#else // !_WIN32 if (coreLogLevel_) { - logInstallWriter(nullptr, mode_ == ServerMode::Standalone ? LoggerPolicy::WithoutLocks : LoggerPolicy::WithLocks); + logInstallWriter(nullptr, mode_ == ServerMode::Standalone ? LoggerPolicy::WithoutLocks : LoggerPolicy::WithLocks, int(LogNone)); } +#endif // !_WIN32 async_.reset(); } diff --git a/cpp_src/server/serverimpl.h b/cpp_src/server/serverimpl.h index bbd0e06c0..a0debb9b3 100644 --- a/cpp_src/server/serverimpl.h +++ b/cpp_src/server/serverimpl.h @@ -7,6 +7,7 @@ #include "config.h" #include "loggerwrapper.h" #include "net/ev/ev.h" +#include "spdlog/sinks/reopen_file_sink.h" #ifndef _WIN32 #include "pidfile.h" @@ -22,7 +23,7 @@ struct IDBManagerStatsCollector; struct IRPCServerStatsCollector; class ServerImpl { - using SinkMap = std::unordered_map>; + using SinkMap = std::unordered_map>; public: ServerImpl(ServerMode mode); diff --git a/cpp_src/server/statscollect/prometheus.h b/cpp_src/server/statscollect/prometheus.h index 36829a47d..921a17ad8 100644 --- a/cpp_src/server/statscollect/prometheus.h +++ b/cpp_src/server/statscollect/prometheus.h @@ -18,62 +18,62 @@ class Prometheus { using PRegistry = prometheus::Registry; using PCollectable = prometheus::Collectable; - void Attach(http::Router &router); - void RegisterQPS(const std::string &db, const std::string &ns, std::string_view queryType, size_t qps) { + void Attach(http::Router& router); + void RegisterQPS(const std::string& db, const std::string& ns, std::string_view queryType, size_t qps) { setMetricValue(qps_, qps, currentEpoch_, db, ns, queryType); } - void RegisterLatency(const std::string &db, const std::string &ns, std::string_view queryType, size_t latencyUS) { + void RegisterLatency(const std::string& db, const std::string& ns, std::string_view queryType, size_t latencyUS) { setMetricValue(latency_, static_cast(latencyUS) / 1e6, currentEpoch_, db, ns, queryType); } - void RegisterCachesSize(const std::string &db, const std::string &ns, size_t size) { + void RegisterCachesSize(const std::string& db, const std::string& ns, size_t size) { setMetricValue(caches_, size, currentEpoch_, db, ns); } - void RegisterIndexesSize(const std::string &db, const std::string &ns, size_t size) { + void RegisterIndexesSize(const std::string& db, const std::string& ns, size_t size) { setMetricValue(indexes_, size, currentEpoch_, db, ns); } - void RegisterDataSize(const std::string &db, const std::string &ns, size_t size) { setMetricValue(data_, size, currentEpoch_, db, ns); } - void RegisterItemsCount(const std::string &db, const std::string &ns, size_t count) { + void RegisterDataSize(const std::string& db, const std::string& ns, size_t size) { setMetricValue(data_, size, currentEpoch_, db, ns); } + void RegisterItemsCount(const std::string& db, const std::string& ns, size_t count) { setMetricValue(itemsCount_, count, currentEpoch_, db, ns); } void RegisterAllocatedMemory(size_t memoryConsumationBytes) { setMetricValue(memory_, memoryConsumationBytes, prometheus::kNoEpoch); } - void RegisterRPCClients(const std::string &db, std::string_view protocol, size_t count) { + void RegisterRPCClients(const std::string& db, std::string_view protocol, size_t count) { setNetMetricValue(rpcClients_, count, currentEpoch_, db, std::string_view(), protocol); } - void RegisterInputTraffic(const std::string &db, std::string_view type, std::string_view protocol, size_t bytes) { + void RegisterInputTraffic(const std::string& db, std::string_view type, std::string_view protocol, size_t bytes) { setNetMetricValue(inputTraffic_, bytes, prometheus::kNoEpoch, db, type, protocol); } - void RegisterOutputTraffic(const std::string &db, std::string_view type, std::string_view protocol, size_t bytes) { + void RegisterOutputTraffic(const std::string& db, std::string_view type, std::string_view protocol, size_t bytes) { setNetMetricValue(outputTraffic_, bytes, prometheus::kNoEpoch, db, type, protocol); } - void RegisterStorageStatus(const std::string &db, const std::string &ns, bool isOK) { + void RegisterStorageStatus(const std::string& db, const std::string& ns, bool isOK) { setMetricValue(storageStatus_, isOK ? 1.0 : 0.0, prometheus::kNoEpoch, db, ns); } void NextEpoch(); private: - static void setMetricValue(PFamily *metricFamily, double value, int64_t epoch); - static void setMetricValue(PFamily *metricFamily, double value, int64_t epoch, const std::string &db, const std::string &ns, + static void setMetricValue(PFamily* metricFamily, double value, int64_t epoch); + static void setMetricValue(PFamily* metricFamily, double value, int64_t epoch, const std::string& db, const std::string& ns, std::string_view queryType = ""); - static void setNetMetricValue(PFamily *metricFamily, double value, int64_t epoch, const std::string &db, std::string_view type, + static void setNetMetricValue(PFamily* metricFamily, double value, int64_t epoch, const std::string& db, std::string_view type, std::string_view protocol); void fillRxInfo(); - int collect(http::Context &ctx); + int collect(http::Context& ctx); PRegistry registry_; int64_t currentEpoch_ = 1; - PFamily *qps_{nullptr}; - PFamily *latency_{nullptr}; - PFamily *caches_{nullptr}; - PFamily *indexes_{nullptr}; - PFamily *data_{nullptr}; - PFamily *memory_{nullptr}; - PFamily *rpcClients_{nullptr}; - PFamily *inputTraffic_{nullptr}; - PFamily *outputTraffic_{nullptr}; - PFamily *storageStatus_{nullptr}; - PFamily *itemsCount_{nullptr}; - PFamily *rxInfo_{nullptr}; + PFamily* qps_{nullptr}; + PFamily* latency_{nullptr}; + PFamily* caches_{nullptr}; + PFamily* indexes_{nullptr}; + PFamily* data_{nullptr}; + PFamily* memory_{nullptr}; + PFamily* rpcClients_{nullptr}; + PFamily* inputTraffic_{nullptr}; + PFamily* outputTraffic_{nullptr}; + PFamily* storageStatus_{nullptr}; + PFamily* itemsCount_{nullptr}; + PFamily* rxInfo_{nullptr}; }; } // namespace reindexer_server diff --git a/cpp_src/server/winservice.cc b/cpp_src/server/winservice.cc index 3c36f8349..e9dd8892f 100644 --- a/cpp_src/server/winservice.cc +++ b/cpp_src/server/winservice.cc @@ -13,11 +13,13 @@ namespace reindexer_server { #define SERVER_STOP_WAIT 5000 #define SERVER_START_WAIT 5000 -WinService *g_Service; +WinService* g_Service; static std::string GetLastErrorAsString() { // Get the error message, if any. DWORD errorMessageID = ::GetLastError(); - if (errorMessageID == 0) return std::string(); // No error message has been recorded + if (errorMessageID == 0) { + return std::string(); // No error message has been recorded + } LPSTR messageBuffer = nullptr; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, @@ -30,7 +32,7 @@ static std::string GetLastErrorAsString() { return message; } -WinService::WinService(const std::string &name, const std::string &displayName, std::function run, +WinService::WinService(const std::string& name, const std::string& displayName, std::function run, std::function terminate, std::function status) : name_(name), displayName_(displayName), run_(run), terminate_(terminate), status_(status) { g_Service = this; @@ -39,7 +41,7 @@ WinService::WinService(const std::string &name, const std::string &displayName, WinService::~WinService() { g_Service = 0; } -void WinService::Message(bool bError, const char *fmt, ...) { +void WinService::Message(bool bError, const char* fmt, ...) { va_list va; va_start(va, fmt); char tempBuf[4096]; @@ -95,24 +97,26 @@ void WinService::MainInternal(DWORD dwArgc, LPTSTR lpszArgv[]) { bool WinService::ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { static DWORD dwCheckPoint = 1; - if (dwCurrentState == SERVICE_START_PENDING) + if (dwCurrentState == SERVICE_START_PENDING) { ssStatus_.dwControlsAccepted = 0; - else + } else { ssStatus_.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + } ssStatus_.dwCurrentState = dwCurrentState; ssStatus_.dwWin32ExitCode = dwWin32ExitCode; ssStatus_.dwWaitHint = dwWaitHint; - if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) + if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) { ssStatus_.dwCheckPoint = 0; - else + } else { ssStatus_.dwCheckPoint = dwCheckPoint++; + } return SetServiceStatus(sshStatusHandle_, &ssStatus_); } -bool WinService::Install(const char *cmdline) { +bool WinService::Install(const char* cmdline) { SC_HANDLE schService = NULL, schSCManager = NULL; Remove(true); @@ -136,8 +140,9 @@ bool WinService::Install(const char *cmdline) { CloseServiceHandle(schSCManager); return true; - } else + } else { Message(false, "CreateService failed:\n%s\n", GetLastErrorAsString().c_str()); + } CloseServiceHandle(schSCManager); } else { @@ -147,7 +152,7 @@ bool WinService::Install(const char *cmdline) { } int WinService::Start() { - SERVICE_TABLE_ENTRY DispTable[] = {{const_cast(name_.c_str()), ServiceMain}, {NULL, NULL}}; + SERVICE_TABLE_ENTRY DispTable[] = {{const_cast(name_.c_str()), ServiceMain}, {NULL, NULL}}; StartServiceCtrlDispatcher(DispTable); return 0; } @@ -165,8 +170,9 @@ bool WinService::Remove(bool silent) { while (QueryServiceStatus(schService, &ssStatus_)) { if (ssStatus_.dwCurrentState == SERVICE_STOP_PENDING) { Sleep(1000); - } else + } else { break; + } } } @@ -175,16 +181,19 @@ bool WinService::Remove(bool silent) { CloseServiceHandle(schSCManager); return true; - } else if (!silent) + } else if (!silent) { Message(true, "DeleteService failed:\n%s\n", GetLastErrorAsString().c_str()); + } CloseServiceHandle(schService); - } else if (!silent) + } else if (!silent) { Message(true, "OpenService failed:\n%s\n", GetLastErrorAsString().c_str()); + } CloseServiceHandle(schSCManager); - } else if (!silent) + } else if (!silent) { Message(true, "OpenSCManager failed:\n%s\n", GetLastErrorAsString().c_str()); + } return false; } diff --git a/cpp_src/server/winservice.h b/cpp_src/server/winservice.h index 1571d8497..262e7b898 100644 --- a/cpp_src/server/winservice.h +++ b/cpp_src/server/winservice.h @@ -12,12 +12,12 @@ namespace reindexer_server { class WinService { public: - WinService(const std::string &name, const std::string &displayName, std::function run, std::function terminate, + WinService(const std::string& name, const std::string& displayName, std::function run, std::function terminate, std::function status); virtual ~WinService(); - void Message(bool bError, const char *fmt, ...); + void Message(bool bError, const char* fmt, ...); int Start(); - bool Install(const char *cmdline); + bool Install(const char* cmdline); bool Remove(bool silent = false); void ServiceCtrl(DWORD dwCtrlCode); diff --git a/cpp_src/tools/alloc_ext/je_malloc_extension.cc b/cpp_src/tools/alloc_ext/je_malloc_extension.cc index b4baaee40..cdc5cbdff 100644 --- a/cpp_src/tools/alloc_ext/je_malloc_extension.cc +++ b/cpp_src/tools/alloc_ext/je_malloc_extension.cc @@ -6,8 +6,8 @@ #include #include #include -#endif // _WIN32 -#endif // REINDEX_WITH_JEMALLOC && !defined(_WIN32) +#endif // _WIN32 +#endif // REINDEX_WITH_JEMALLOC && !defined(_WIN32) namespace reindexer { namespace alloc_ext { @@ -20,14 +20,14 @@ bool JEMallocIsAvailable() { return true; } #elif REINDEX_WITH_JEMALLOC -using MallctlFn = int (*)(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); +using MallctlFn = int (*)(const char* name, void* oldp, size_t* oldlenp, void* newp, size_t newlen); static MallctlFn getMallctlFn() { static auto getInstanceFn = reinterpret_cast(dlsym(RTLD_DEFAULT, "mallctl")); return getInstanceFn; } -int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { +int mallctl(const char* name, void* oldp, size_t* oldlenp, void* newp, size_t newlen) { auto getInstanceFn = getMallctlFn(); if (getInstanceFn) { return getInstanceFn(name, oldp, oldlenp, newp, newlen); @@ -40,7 +40,7 @@ bool JEMallocIsAvailable() { return (getMallctlFn() != nullptr); } #else // suppress clang warngig int ___je_malloc_extension_dummy_suppress_warning; -#endif // REINDEX_WITH_JEMALLOC +#endif // REINDEX_WITH_JEMALLOC } // namespace alloc_ext } // namespace reindexer diff --git a/cpp_src/tools/alloc_ext/je_malloc_extension.h b/cpp_src/tools/alloc_ext/je_malloc_extension.h index af78b7a2a..b43b39ebe 100644 --- a/cpp_src/tools/alloc_ext/je_malloc_extension.h +++ b/cpp_src/tools/alloc_ext/je_malloc_extension.h @@ -7,11 +7,11 @@ namespace reindexer { namespace alloc_ext { -int mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); +int mallctl(const char* name, void* oldp, size_t* oldlenp, void* newp, size_t newlen); bool JEMallocIsAvailable(); } // namespace alloc_ext } // namespace reindexer -#endif // REINDEX_WITH_JEMALLOC +#endif // REINDEX_WITH_JEMALLOC diff --git a/cpp_src/tools/alloc_ext/tc_malloc_extension.cc b/cpp_src/tools/alloc_ext/tc_malloc_extension.cc index 32964d311..d6afdde4d 100644 --- a/cpp_src/tools/alloc_ext/tc_malloc_extension.cc +++ b/cpp_src/tools/alloc_ext/tc_malloc_extension.cc @@ -4,7 +4,7 @@ #include #include #include -#endif // REINDEX_WITH_GPERFTOOLS && !defined(_WIN32) +#endif // REINDEX_WITH_GPERFTOOLS && !defined(_WIN32) namespace reindexer { namespace alloc_ext { @@ -33,7 +33,7 @@ MallocExtension* instance() { bool TCMallocIsAvailable() { return (getGetInstanceFn() != nullptr); } -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS } // namespace alloc_ext } // namespace reindexer diff --git a/cpp_src/tools/alloc_ext/tc_malloc_extension.h b/cpp_src/tools/alloc_ext/tc_malloc_extension.h index 5fabb41db..fdc9f7550 100644 --- a/cpp_src/tools/alloc_ext/tc_malloc_extension.h +++ b/cpp_src/tools/alloc_ext/tc_malloc_extension.h @@ -17,4 +17,4 @@ int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook); } // namespace alloc_ext } // namespace reindexer -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS diff --git a/cpp_src/tools/alloc_ext/tc_malloc_hook.cc b/cpp_src/tools/alloc_ext/tc_malloc_hook.cc index 41abc0688..de2ddaa72 100644 --- a/cpp_src/tools/alloc_ext/tc_malloc_hook.cc +++ b/cpp_src/tools/alloc_ext/tc_malloc_hook.cc @@ -4,7 +4,7 @@ #include #include #include -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS namespace reindexer { namespace alloc_ext { @@ -44,7 +44,7 @@ int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook) { bool TCMallocHooksAreAvailable() { return (getAddNewHookFn() != nullptr) && (getAddDeleteHookFn() != nullptr); } -#endif // REINDEX_WITH_GPERFTOOLS +#endif // REINDEX_WITH_GPERFTOOLS } // namespace alloc_ext } // namespace reindexer diff --git a/cpp_src/tools/assertrx.cc b/cpp_src/tools/assertrx.cc index aa468d08b..30692d01f 100644 --- a/cpp_src/tools/assertrx.cc +++ b/cpp_src/tools/assertrx.cc @@ -3,12 +3,12 @@ #include #include #include "debug/backtrace.h" -#include "spdlog/fmt/bundled/printf.h" +#include "fmt/printf.h" #include "tools/errors.h" namespace reindexer { -void fail_assertrx(const char *assertion, const char *file, unsigned line, const char *function) noexcept { +void fail_assertrx(const char* assertion, const char* file, unsigned line, const char* function) noexcept { auto msg = fmt::sprintf("Assertion failed: %s (%s:%u: %s)", assertion, file, line, function); std::cerr << msg << "\n"; debug::backtrace_set_assertion_message(std::move(msg)); @@ -16,7 +16,7 @@ void fail_assertrx(const char *assertion, const char *file, unsigned line, const std::abort(); } -void fail_throwrx(const char *assertion, const char *file, unsigned line, const char *function) { +void fail_throwrx(const char* assertion, const char* file, unsigned line, const char* function) { std::string errText{fmt::sprintf("Assertion failed (handled via exception): %s (%s:%u: %s)\n", assertion, file, line, function)}; std::cerr << errText; debug::print_crash_query(std::cerr); diff --git a/cpp_src/tools/assertrx.h b/cpp_src/tools/assertrx.h index fc8d76875..a3c80388b 100644 --- a/cpp_src/tools/assertrx.h +++ b/cpp_src/tools/assertrx.h @@ -4,7 +4,7 @@ namespace reindexer { -[[noreturn]] void fail_throwrx (const char *assertion, const char *file, unsigned line, const char *function) noexcept(false); +[[noreturn]] void fail_throwrx(const char* assertion, const char* file, unsigned line, const char* function) noexcept(false); #define throw_assert(expr) reindexer::fail_throwrx(#expr, __FILE__, __LINE__, __FUNCTION__) #define throw_as_assert throw_assert(false) @@ -17,7 +17,7 @@ namespace reindexer { // fail_assertrx can actually throw, but this exception can not be handled properly, // so it was marked as 'noexcept' for the optimization purposes -[[noreturn]] void fail_assertrx(const char *assertion, const char *file, unsigned line, const char *function) noexcept; +[[noreturn]] void fail_assertrx(const char* assertion, const char* file, unsigned line, const char* function) noexcept; #ifdef __cplusplus #define assertrx(expr) (rx_likely(static_cast(expr)) ? void(0) : reindexer::fail_assertrx(#expr, __FILE__, __LINE__, __FUNCTION__)) diff --git a/cpp_src/tools/customlocal.cc b/cpp_src/tools/customlocal.cc index bd44b2ea4..4761e6cbe 100644 --- a/cpp_src/tools/customlocal.cc +++ b/cpp_src/tools/customlocal.cc @@ -201,7 +201,9 @@ constexpr std::pair kAlphabet[] = { constexpr int checkAlphabetSorted() { for (int i = 1; i < std::end(kAlphabet) - std::begin(kAlphabet); i++) { - if (kAlphabet[i - 1] >= kAlphabet[i]) return i; + if (kAlphabet[i - 1] >= kAlphabet[i]) { + return i; + } } return -1; } diff --git a/cpp_src/tools/errors.h b/cpp_src/tools/errors.h index 43376cba6..c899ace6b 100644 --- a/cpp_src/tools/errors.h +++ b/cpp_src/tools/errors.h @@ -3,20 +3,20 @@ #include #include #include -#include "core/type_consts.h" +#include "core/type_formats.h" #include "estl/intrusive_ptr.h" #ifdef REINDEX_CORE_BUILD #include "debug/backtrace.h" -#include "spdlog/fmt/bundled/printf.h" +#include "fmt/printf.h" #endif // REINDEX_CORE_BUILD namespace reindexer { #if defined(REINDEX_CORE_BUILD) template -void assertf_fmt(const char *fmt, const Args &...args) { - fmt::fprintf(std::cerr, fmt, args...); +void assertf_fmt(const char* fmt, const Args&... args) { + fmt::fprintf(stderr, fmt, args...); } #if defined(NDEBUG) #define assertf(...) ((void)0) @@ -75,7 +75,7 @@ class Error { // TODO: Enable nodiscard once python binding will be updated } } } - Error(ErrorCode code, const char *what) noexcept : code_{code} { + Error(ErrorCode code, const char* what) noexcept : code_{code} { if (code_ != errOK) { try { what_ = make_intrusive(what); @@ -84,26 +84,26 @@ class Error { // TODO: Enable nodiscard once python binding will be updated } } } - Error(const std::exception &e) noexcept : code_{errSystem} { + Error(const std::exception& e) noexcept : code_{errSystem} { try { what_ = make_intrusive(e.what()); } catch (...) { what_ = defaultErrorText_; } } - Error(const Error &) noexcept = default; - Error(Error &&) noexcept = default; - Error &operator=(const Error &) noexcept = default; - Error &operator=(Error &&) noexcept = default; + Error(const Error&) noexcept = default; + Error(Error&&) noexcept = default; + Error& operator=(const Error&) noexcept = default; + Error& operator=(Error&&) noexcept = default; #ifdef REINDEX_CORE_BUILD template - Error(ErrorCode code, const char *fmt, const Args &...args) noexcept : code_{code} { + Error(ErrorCode code, const char* fmt, const Args&... args) noexcept : code_{code} { if (code_ != errOK) { try { try { what_ = make_intrusive(fmt::sprintf(fmt, args...)); - } catch (const fmt::FormatError &) { + } catch (const std::exception&) { assertf_dbg(false, "Incorrect error format: '%s'", fmt); what_ = make_intrusive(fmt); } @@ -114,7 +114,7 @@ class Error { // TODO: Enable nodiscard once python binding will be updated } #endif // REINDEX_CORE_BUILD - [[nodiscard]] const std::string &what() const & noexcept { + [[nodiscard]] const std::string& what() const& noexcept { static const std::string noerr; return what_ ? *what_ : noerr; } @@ -129,8 +129,8 @@ class Error { // TODO: Enable nodiscard once python binding will be updated [[nodiscard]] bool ok() const noexcept { return code_ == errOK; } explicit operator bool() const noexcept { return !ok(); } - [[nodiscard]] bool operator==(const Error &other) const noexcept { return code() == other.code() && what() == other.what(); } - [[nodiscard]] bool operator!=(const Error &other) const noexcept { return !(*this == other); } + [[nodiscard]] bool operator==(const Error& other) const noexcept { return code() == other.code() && what() == other.what(); } + [[nodiscard]] bool operator!=(const Error& other) const noexcept { return !(*this == other); } private: WhatPtr what_; diff --git a/cpp_src/tools/frozen_str_tools.h b/cpp_src/tools/frozen_str_tools.h index 29075237b..505ad7374 100644 --- a/cpp_src/tools/frozen_str_tools.h +++ b/cpp_src/tools/frozen_str_tools.h @@ -10,7 +10,9 @@ namespace frozen { template constexpr std::size_t hash_ascii_string_nocase(const String& value, std::size_t seed) { std::size_t d = (0x811c9dc5 ^ seed) * static_cast(0x01000193); - for (const auto& c : value) d = (d ^ (static_cast(c) | 0x20)) * static_cast(0x01000193); + for (const auto& c : value) { + d = (d ^ (static_cast(c) | 0x20)) * static_cast(0x01000193); + } return d >> 8; } diff --git a/cpp_src/tools/fsops.cc b/cpp_src/tools/fsops.cc index bb3ba36a6..d76ba7f5d 100644 --- a/cpp_src/tools/fsops.cc +++ b/cpp_src/tools/fsops.cc @@ -13,31 +13,35 @@ namespace reindexer { namespace fs { -[[nodiscard]] int MkDirAll(const std::string &path) noexcept { +[[nodiscard]] int MkDirAll(const std::string& path) noexcept { try { std::string tmpStr = path; char *p = nullptr, *tmp = tmpStr.data(); int err; const auto len = tmpStr.size(); - if (tmp[len - 1] == '/' || tmp[len - 1] == '\\') tmp[len - 1] = 0; + if (tmp[len - 1] == '/' || tmp[len - 1] == '\\') { + tmp[len - 1] = 0; + } for (p = tmp + 1; *p; p++) { if (*p == '/' || *p == '\\') { *p = 0; err = mkdir(tmp, S_IRWXU); - if ((err < 0) && (errno != EEXIST)) return err; + if ((err < 0) && (errno != EEXIST)) { + return err; + } *p = '/'; } } return ((mkdir(tmp, S_IRWXU) < 0) && errno != EEXIST) ? -1 : 0; - } catch (std::exception &) { + } catch (std::exception&) { return -1; } } -int RmDirAll(const std::string &path) noexcept { +int RmDirAll(const std::string& path) noexcept { #ifndef _WIN32 return nftw( - path.c_str(), [](const char *fpath, const struct stat *, int, struct FTW *) { return ::remove(fpath); }, 64, FTW_DEPTH | FTW_PHYS); + path.c_str(), [](const char* fpath, const struct stat*, int, struct FTW*) { return ::remove(fpath); }, 64, FTW_DEPTH | FTW_PHYS); #else WIN32_FIND_DATA entry; if (HANDLE hFind = FindFirstFile((path + "/*.*").c_str(), &entry); hFind != INVALID_HANDLE_VALUE) { @@ -73,9 +77,9 @@ int RmDirAll(const std::string &path) noexcept { #endif } -[[nodiscard]] int ReadFile(const std::string &path, std::string &content) noexcept { +[[nodiscard]] int ReadFile(const std::string& path, std::string& content) noexcept { try { - FILE *f = fopen(path.c_str(), "rb"); + FILE* f = fopen(path.c_str(), "rb"); if (!f) { return -1; } @@ -86,13 +90,13 @@ int RmDirAll(const std::string &path) noexcept { auto nread = fread(&content[0], 1, sz, f); fclose(f); return nread; - } catch (std::exception &) { + } catch (std::exception&) { return -1; } } -[[nodiscard]] int64_t WriteFile(const std::string &path, std::string_view content) noexcept { - FILE *f = fopen(path.c_str(), "w"); +[[nodiscard]] int64_t WriteFile(const std::string& path, std::string_view content) noexcept { + FILE* f = fopen(path.c_str(), "w"); if (!f) { return -1; } @@ -102,9 +106,9 @@ int RmDirAll(const std::string &path) noexcept { return static_cast((written > 0) ? content.size() : written); } -[[nodiscard]] int ReadDir(const std::string &path, std::vector &content) noexcept { +[[nodiscard]] int ReadDir(const std::string& path, std::vector& content) noexcept { #ifndef _WIN32 - struct dirent *entry; + struct dirent* entry; auto dir = opendir(path.c_str()); if (!dir) { @@ -193,36 +197,44 @@ std::string GetTempDir() { ::GetTempPathA(sizeof(tmpBuf), tmpBuf); return tmpBuf; #else - const char *tmpDir = getenv("TMPDIR"); - if (tmpDir && *tmpDir) return tmpDir; + const char* tmpDir = getenv("TMPDIR"); + if (tmpDir && *tmpDir) { + return tmpDir; + } return "/tmp"; #endif } -void SetTempDir(std::string &&dir) noexcept { +void SetTempDir(std::string&& dir) noexcept { std::lock_guard lck(tmpDirMtx); tmpDir = std::move(dir); } std::string GetHomeDir() { - const char *homeDir = getenv("HOME"); - if (homeDir && *homeDir) return homeDir; + const char* homeDir = getenv("HOME"); + if (homeDir && *homeDir) { + return homeDir; + } return "."; } -FileStatus Stat(const std::string &path) { +FileStatus Stat(const std::string& path) { #ifdef _WIN32 struct _stat state; - if (_stat(path.c_str(), &state) < 0) return StatError; + if (_stat(path.c_str(), &state) < 0) { + return StatError; + } return (state.st_mode & _S_IFDIR) ? StatDir : StatFile; #else struct stat state; - if (stat(path.c_str(), &state) < 0) return StatError; + if (stat(path.c_str(), &state) < 0) { + return StatError; + } return S_ISDIR(state.st_mode) ? StatDir : StatFile; #endif } -TimeStats StatTime(const std::string &path) { +TimeStats StatTime(const std::string& path) { #ifdef _WIN32 FILETIME ftCreate, ftAccess, ftWrite; HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); @@ -256,32 +268,38 @@ TimeStats StatTime(const std::string &path) { return {-1, -1, -1}; } -[[nodiscard]] bool DirectoryExists(const std::string &directory) noexcept { +[[nodiscard]] bool DirectoryExists(const std::string& directory) noexcept { if (!directory.empty()) { #ifdef _WIN32 if (_access(directory.c_str(), 0) == 0) { struct _stat status; _stat(directory.c_str(), &status); - if (status.st_mode & _S_IFDIR) return true; + if (status.st_mode & _S_IFDIR) { + return true; + } } #else if (access(directory.c_str(), F_OK) == 0) { struct stat status; stat(directory.c_str(), &status); - if (status.st_mode & S_IFDIR) return true; + if (status.st_mode & S_IFDIR) { + return true; + } } #endif } return false; } -Error TryCreateDirectory(const std::string &dir) { +Error TryCreateDirectory(const std::string& dir) { using reindexer::fs::MkDirAll; using reindexer::fs::DirectoryExists; using reindexer::fs::GetTempDir; if (!dir.empty()) { if (!DirectoryExists(dir) && dir != GetTempDir()) { - if (MkDirAll(dir) < 0) return Error(errLogic, "Could not create '%s'. Reason: %s\n", dir.c_str(), strerror(errno)); + if (MkDirAll(dir) < 0) { + return Error(errLogic, "Could not create '%s'. Reason: %s\n", dir.c_str(), strerror(errno)); + } #ifdef _WIN32 } else if (_access(dir.c_str(), 6) < 0) { #else @@ -293,12 +311,12 @@ Error TryCreateDirectory(const std::string &dir) { return {}; } -std::string GetDirPath(const std::string &path) { +std::string GetDirPath(const std::string& path) { size_t lastSlashPos = path.find_last_of("/\\"); return lastSlashPos == std::string::npos ? std::string() : path.substr(0, lastSlashPos + 1); } -Error ChownDir(const std::string &path, const std::string &user) { +Error ChownDir(const std::string& path, const std::string& user) { #ifndef _WIN32 if (!user.empty() && !path.empty()) { struct passwd pwd, *usr; @@ -327,7 +345,7 @@ Error ChownDir(const std::string &path, const std::string &user) { return {}; } -Error ChangeUser(const char *userName) { +Error ChangeUser(const char* userName) { #ifndef _WIN32 struct passwd pwd, *result; char buf[0x4000]; @@ -342,30 +360,42 @@ Error ChangeUser(const char *userName) { } } - if (setgid(pwd.pw_gid) != 0) return Error(errLogic, "Could not change user to `%s`. Reason: %s", userName, strerror(errno)); - if (setuid(pwd.pw_uid) != 0) return Error(errLogic, "Could not change user to `%s`. Reason: %s", userName, strerror(errno)); + if (setgid(pwd.pw_gid) != 0) { + return Error(errLogic, "Could not change user to `%s`. Reason: %s", userName, strerror(errno)); + } + if (setuid(pwd.pw_uid) != 0) { + return Error(errLogic, "Could not change user to `%s`. Reason: %s", userName, strerror(errno)); + } #else (void)userName; #endif return {}; } -std::string GetRelativePath(const std::string &path, unsigned maxUp) { +std::string GetRelativePath(const std::string& path, unsigned maxUp) { std::string cwd = GetCwd(); unsigned same = 0, slashes = 0; for (; same < std::min(cwd.size(), path.size()) && cwd[same] == path[same]; ++same) { } for (unsigned i = same; i < cwd.size(); ++i) { - if (cwd[i] == '/' || i == same) slashes++; + if (cwd[i] == '/' || i == same) { + slashes++; + } + } + if (!slashes && same < path.size()) { + same++; } - if (!slashes && same < path.size()) same++; - if (same < 2 || (slashes > maxUp)) return path; + if (same < 2 || (slashes > maxUp)) { + return path; + } std::string rpath; rpath.reserve(slashes * 3 + path.size() - same + 1); - while (slashes--) rpath += "../"; + while (slashes--) { + rpath += "../"; + } rpath.append(path.begin() + same, path.end()); return rpath; } diff --git a/cpp_src/tools/fsops.h b/cpp_src/tools/fsops.h index 015ef0a66..7f615bbac 100644 --- a/cpp_src/tools/fsops.h +++ b/cpp_src/tools/fsops.h @@ -26,27 +26,27 @@ struct TimeStats { int64_t mtime; }; -[[nodiscard]] int MkDirAll(const std::string &path) noexcept; -int RmDirAll(const std::string &path) noexcept; -[[nodiscard]] int ReadFile(const std::string &path, std::string &content) noexcept; -[[nodiscard]] int64_t WriteFile(const std::string &path, std::string_view content) noexcept; -[[nodiscard]] int ReadDir(const std::string &path, std::vector &content) noexcept; -[[nodiscard]] bool DirectoryExists(const std::string &directory) noexcept; -FileStatus Stat(const std::string &path); -TimeStats StatTime(const std::string &path); +[[nodiscard]] int MkDirAll(const std::string& path) noexcept; +int RmDirAll(const std::string& path) noexcept; +[[nodiscard]] int ReadFile(const std::string& path, std::string& content) noexcept; +[[nodiscard]] int64_t WriteFile(const std::string& path, std::string_view content) noexcept; +[[nodiscard]] int ReadDir(const std::string& path, std::vector& content) noexcept; +[[nodiscard]] bool DirectoryExists(const std::string& directory) noexcept; +FileStatus Stat(const std::string& path); +TimeStats StatTime(const std::string& path); std::string GetCwd(); -std::string GetDirPath(const std::string &path); +std::string GetDirPath(const std::string& path); std::string GetTempDir(); -void SetTempDir(std::string &&dir) noexcept; +void SetTempDir(std::string&& dir) noexcept; std::string GetHomeDir(); -std::string GetRelativePath(const std::string &path, unsigned maxUp = 1024); -inline int Rename(const std::string &from, const std::string &to) { return rename(from.c_str(), to.c_str()); } +std::string GetRelativePath(const std::string& path, unsigned maxUp = 1024); +inline int Rename(const std::string& from, const std::string& to) { return rename(from.c_str(), to.c_str()); } -Error TryCreateDirectory(const std::string &dir); -Error ChangeUser(const char *userName); -Error ChownDir(const std::string &path, const std::string &user); +Error TryCreateDirectory(const std::string& dir); +Error ChangeUser(const char* userName); +Error ChownDir(const std::string& path, const std::string& user); -inline std::string JoinPath(const std::string &base, const std::string &name) { +inline std::string JoinPath(const std::string& base, const std::string& name) { return base + ((!base.empty() && base.back() != '/') ? "/" : "") + name; } } // namespace fs diff --git a/cpp_src/tools/json2kv.cc b/cpp_src/tools/json2kv.cc index e4aec7e2d..c22131e1f 100644 --- a/cpp_src/tools/json2kv.cc +++ b/cpp_src/tools/json2kv.cc @@ -7,7 +7,7 @@ namespace reindexer { -Variant jsonValue2Variant(const gason::JsonValue &v, KeyValueType t, std::string_view fieldName) { +Variant jsonValue2Variant(const gason::JsonValue& v, KeyValueType t, std::string_view fieldName) { switch (v.getTag()) { case gason::JSON_NUMBER: return t.EvaluateOneOf( @@ -61,7 +61,7 @@ Variant jsonValue2Variant(const gason::JsonValue &v, KeyValueType t, std::string [](KeyValueType::Double) noexcept { return Variant(0.0); }, [](KeyValueType::Bool) noexcept { return Variant(false); }, [](KeyValueType::Int) noexcept { return Variant(0); }, [](KeyValueType::Int64) noexcept { return Variant(static_cast(0)); }, - [](KeyValueType::String) { return Variant(static_cast(nullptr)); }, + [](KeyValueType::String) { return Variant(static_cast(nullptr)); }, [](KeyValueType::Uuid) noexcept { return Variant{Uuid{}}; }, [&](OneOf) -> Variant { throw Error(errLogic, "Error parsing json field '%s' - got null, expected %s", fieldName, t.Name()); @@ -70,7 +70,7 @@ Variant jsonValue2Variant(const gason::JsonValue &v, KeyValueType t, std::string throw Error(errLogic, "Error parsing json field '%s' - unable to use object in this context", fieldName); case gason::JSON_ARRAY: { VariantArray variants; - for (const auto &elem : v) { + for (const auto& elem : v) { if (elem.value.getTag() != gason::JSON_NULL) { variants.emplace_back(jsonValue2Variant(elem.value, KeyValueType::Undefined{}, fieldName)); } diff --git a/cpp_src/tools/jsonstring.h b/cpp_src/tools/jsonstring.h index 8df4bb0c8..da87622ca 100644 --- a/cpp_src/tools/jsonstring.h +++ b/cpp_src/tools/jsonstring.h @@ -21,7 +21,7 @@ namespace json_string { constexpr static unsigned kLargeJSONStrFlag = 0x80; template -inline size_t length(const uint8_t *p) noexcept { +inline size_t length(const uint8_t* p) noexcept { if constexpr (isLargeString) { return p[-1] | (unsigned(p[0]) << 8) | (unsigned(p[1]) << 16) | ((unsigned(p[2]) & ~kLargeJSONStrFlag) << 24); } else { @@ -29,14 +29,14 @@ inline size_t length(const uint8_t *p) noexcept { } } -inline size_t length(const uint8_t *p) noexcept { +inline size_t length(const uint8_t* p) noexcept { if (p[2] & kLargeJSONStrFlag) { return length(p); } return length(p); } -inline std::string_view to_string_view(const uint8_t *p) noexcept { +inline std::string_view to_string_view(const uint8_t* p) noexcept { if (p[2] & kLargeJSONStrFlag) { const auto len = length(p); uintptr_t uptr; @@ -49,13 +49,13 @@ inline std::string_view to_string_view(const uint8_t *p) noexcept { #else static_assert(false, "Unexpected uintptr_t size"); #endif - return std::string_view(reinterpret_cast(uptr), len); + return std::string_view(reinterpret_cast(uptr), len); } const auto len = length(p); - return std::string_view(reinterpret_cast(p - len), len); + return std::string_view(reinterpret_cast(p - len), len); } -inline void encode(uint8_t *p, uint64_t l, std::vector> &storage) { +inline void encode(uint8_t* p, uint64_t l, std::vector>& storage) { if (l >= (uint64_t(1) << 23)) { storage.emplace_back(new char[l]); std::copy(p - l, p, storage.back().get()); diff --git a/cpp_src/tools/jsontools.cc b/cpp_src/tools/jsontools.cc index 33b3031f1..a8fc8996e 100644 --- a/cpp_src/tools/jsontools.cc +++ b/cpp_src/tools/jsontools.cc @@ -5,7 +5,7 @@ namespace reindexer { -void jsonValueToString(gason::JsonValue o, WrSerializer &ser, int shift, int indent, bool escapeStrings) { +void jsonValueToString(gason::JsonValue o, WrSerializer& ser, int shift, int indent, bool escapeStrings) { using namespace std::string_view_literals; bool enableEol = (shift != 0) || (indent != 0); switch (o.getTag()) { @@ -28,13 +28,19 @@ void jsonValueToString(gason::JsonValue o, WrSerializer &ser, int shift, int ind break; } ser << '['; - if (enableEol) ser << '\n'; + if (enableEol) { + ser << '\n'; + } - for (const auto &i : o) { + for (const auto& i : o) { ser.Fill(' ', indent + shift); jsonValueToString(i.value, ser, shift, indent + shift); - if (i.next) ser << ','; - if (enableEol) ser << '\n'; + if (i.next) { + ser << ','; + } + if (enableEol) { + ser << '\n'; + } } ser.Fill(' ', indent); ser << ']'; @@ -45,15 +51,21 @@ void jsonValueToString(gason::JsonValue o, WrSerializer &ser, int shift, int ind break; } ser << '{'; - if (enableEol) ser << '\n'; + if (enableEol) { + ser << '\n'; + } - for (const auto &i : o) { + for (const auto& i : o) { ser.Fill(' ', indent + shift); ser.PrintJsonString(i.key); ser << ": "; jsonValueToString(i.value, ser, shift, indent + shift); - if (i.next) ser << ','; - if (enableEol) ser << '\n'; + if (i.next) { + ser << ','; + } + if (enableEol) { + ser << '\n'; + } } ser.Fill(' ', indent); ser << '}'; @@ -75,11 +87,11 @@ void jsonValueToString(gason::JsonValue o, WrSerializer &ser, int shift, int ind } } -void prettyPrintJSON(span json, WrSerializer &ser, int shift) { +void prettyPrintJSON(span json, WrSerializer& ser, int shift) { jsonValueToString(gason::JsonParser().Parse(json).value, ser, shift, 0); } -std::string stringifyJson(const gason::JsonNode &elem) { +std::string stringifyJson(const gason::JsonNode& elem) { WrSerializer ser; jsonValueToString(elem.value, ser, 0, 0); diff --git a/cpp_src/tools/jsontools.h b/cpp_src/tools/jsontools.h index f17222aed..fe186c1e3 100644 --- a/cpp_src/tools/jsontools.h +++ b/cpp_src/tools/jsontools.h @@ -9,9 +9,9 @@ class WrSerializer; constexpr int kJsonShiftWidth = 4; -void jsonValueToString(gason::JsonValue o, WrSerializer &ser, int shift = kJsonShiftWidth, int indent = 0, bool escapeStrings = true); -void prettyPrintJSON(span json, WrSerializer &ser, int shift = kJsonShiftWidth); +void jsonValueToString(gason::JsonValue o, WrSerializer& ser, int shift = kJsonShiftWidth, int indent = 0, bool escapeStrings = true); +void prettyPrintJSON(span json, WrSerializer& ser, int shift = kJsonShiftWidth); -std::string stringifyJson(const gason::JsonNode &elem); +std::string stringifyJson(const gason::JsonNode& elem); } // namespace reindexer diff --git a/cpp_src/tools/logger.cc b/cpp_src/tools/logger.cc index 437e8900a..3289e4651 100644 --- a/cpp_src/tools/logger.cc +++ b/cpp_src/tools/logger.cc @@ -5,9 +5,12 @@ namespace reindexer { +namespace logger_details { + static LogWriter g_logWriter; static read_write_spinlock g_LoggerMtx; static std::atomic g_MtLogger = {LoggerPolicy::NotInit}; +std::atomic g_LogLevel = LogTrace; RX_ALWAYS_INLINE void write(int level, char* buf) { if (g_logWriter) { @@ -15,7 +18,7 @@ RX_ALWAYS_INLINE void write(int level, char* buf) { } } -void logPrint(int level, char* buf) { +void logPrintImpl(int level, char* buf) { switch (g_MtLogger.load(std::memory_order_relaxed)) { case LoggerPolicy::NotInit: case LoggerPolicy::WithLocks: { @@ -27,14 +30,15 @@ void logPrint(int level, char* buf) { break; } } +} // namespace logger_details -void logInstallWriter(LogWriter writer, LoggerPolicy policy) { +void logInstallWriter(LogWriter writer, LoggerPolicy policy, int globalLogLevel) { std::string errorText; static std::mutex g_LoggerPolicyMtx; std::unique_lock lck(g_LoggerPolicyMtx); - const auto curPolicy = g_MtLogger.load(std::memory_order_relaxed); + const auto curPolicy = logger_details::g_MtLogger.load(std::memory_order_relaxed); if (curPolicy != LoggerPolicy::NotInit && policy != curPolicy) { errorText = fmt::sprintf("Attempt to switch logger's lock policy, which was previously set. Current: %d; new: %d. Logger was not changed", @@ -49,13 +53,14 @@ void logInstallWriter(LogWriter writer, LoggerPolicy policy) { #endif } - g_MtLogger.store(policy, std::memory_order_relaxed); + logger_details::g_MtLogger.store(policy, std::memory_order_relaxed); + logger_details::g_LogLevel.store(globalLogLevel, std::memory_order_relaxed); if (curPolicy == LoggerPolicy::WithLocks || policy == LoggerPolicy::WithLocks) { - std::lock_guard logLck(g_LoggerMtx); - g_logWriter = std::move(writer); + std::lock_guard logLck(logger_details::g_LoggerMtx); + logger_details::g_logWriter = std::move(writer); } else { - g_logWriter = std::move(writer); + logger_details::g_logWriter = std::move(writer); } } diff --git a/cpp_src/tools/logger.h b/cpp_src/tools/logger.h index 6597ae487..131ae9244 100644 --- a/cpp_src/tools/logger.h +++ b/cpp_src/tools/logger.h @@ -1,21 +1,55 @@ #pragma once +#include #include -#include "spdlog/fmt/bundled/printf.h" -#include "spdlog/fmt/fmt.h" +#include "fmt/printf.h" typedef std::function LogWriter; namespace reindexer { -void logPrint(int level, char* buf); -template -void logPrintf(int level, const char* fmt, const Args&... args) { - auto str = fmt::sprintf(fmt, args...); - logPrint(level, &str[0]); +namespace logger_details { + +extern std::atomic g_LogLevel; +void logPrintImpl(int level, char* buf); + +} // namespace logger_details + +inline void logPrint(int level, char* buf) { + if (logger_details::g_LogLevel.load(std::memory_order_relaxed) >= level) { + logger_details::logPrintImpl(level, buf); + } } +#if REINDEX_CORE_BUILD +// Core build should not contain macro duplication +#ifdef logPrintf +static_assert(false, "Macro conflict"); +#endif // logPrintf +#ifdef logFmt +static_assert(false, "Macro conflict"); +#endif // logFmt +#endif // REINDEX_CORE_BUILD + +#ifndef logPrintf +// Using macro to avoid arguments calculation before global log level check +#define logPrintf(__level, __fmt, ...) \ + if (reindexer::logger_details::g_LogLevel.load(std::memory_order_relaxed) >= __level) { \ + auto __str = fmt::sprintf(__fmt, ##__VA_ARGS__); \ + reindexer::logger_details::logPrintImpl(__level, &__str[0]); \ + } +#endif // logPrintf + +#ifndef logFmt +// Using macro to avoid arguments calculation before global log level check +#define logFmt(__level, __fmt, ...) \ + if (reindexer::logger_details::g_LogLevel.load(std::memory_order_relaxed) >= __level) { \ + auto __str = fmt::format(__fmt, ##__VA_ARGS__); \ + reindexer::logger_details::logPrintImpl(__level, &__str[0]); \ + } +#endif // logFmt + enum class LoggerPolicy : int { NotInit, WithLocks, WithoutLocks }; +void logInstallWriter(LogWriter writer, LoggerPolicy mode, int globalLogLevel); -void logInstallWriter(LogWriter writer, LoggerPolicy mode); } // namespace reindexer diff --git a/cpp_src/tools/md5crypt.cc b/cpp_src/tools/md5crypt.cc index 384ab8e13..1427388f9 100644 --- a/cpp_src/tools/md5crypt.cc +++ b/cpp_src/tools/md5crypt.cc @@ -16,8 +16,8 @@ namespace reindexer { constexpr std::string_view kMD5CryptDelimiter = "$"; -std::string MD5crypt(const std::string &passwd, const std::string &salt) noexcept { - static unsigned const char cov2char[64] = { +std::string MD5crypt(const std::string& passwd, const std::string& salt) noexcept { + static const unsigned char cov2char[64] = { /* from crypto/des/fcrypt.c */ 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, @@ -59,21 +59,21 @@ std::string MD5crypt(const std::string &passwd, const std::string &salt) noexcep for (size_t i = 0; i < 1000; i++) { MD5 md; - md.add((i & 1) ? reinterpret_cast(passwd.c_str()) : buf, (i & 1) ? passwd.size() : sizeof(buf)); + md.add((i & 1) ? reinterpret_cast(passwd.c_str()) : buf, (i & 1) ? passwd.size() : sizeof(buf)); if (i % 3) { md.add(trunkatedSalt, saltLen); } if (i % 7) { md.add(passwd.c_str(), passwd.size()); } - md.add((i & 1) ? buf : reinterpret_cast(passwd.c_str()), (i & 1) ? sizeof(buf) : passwd.size()); + md.add((i & 1) ? buf : reinterpret_cast(passwd.c_str()), (i & 1) ? sizeof(buf) : passwd.size()); md.getHash(buf); } char resultBuf[23] = {0}; /* transform buf into output string */ unsigned char bufPerm[sizeof(buf)]; - char *output = resultBuf; + char* output = resultBuf; for (int dest = 0, source = 0; dest < 14; dest++, source = (source + 6) % 17) { bufPerm[dest] = buf[source]; } @@ -93,7 +93,7 @@ std::string MD5crypt(const std::string &passwd, const std::string &salt) noexcep return std::string(resultBuf); } -Error ParseMd5CryptString(const std::string &input, std::string &outHash, std::string &outSalt) { +Error ParseMd5CryptString(const std::string& input, std::string& outHash, std::string& outSalt) { if (input.empty() || input.find(kMD5CryptDelimiter) != 0) { outHash = input; outSalt.clear(); diff --git a/cpp_src/tools/md5crypt.h b/cpp_src/tools/md5crypt.h index b018f13a8..33c8b441b 100644 --- a/cpp_src/tools/md5crypt.h +++ b/cpp_src/tools/md5crypt.h @@ -7,7 +7,7 @@ namespace reindexer { constexpr std::string_view kMD5CryptMagic{"1"}; -std::string MD5crypt(const std::string &passwd, const std::string &salt) noexcept; -Error ParseMd5CryptString(const std::string &input, std::string &outHash, std::string &outSalt); +std::string MD5crypt(const std::string& passwd, const std::string& salt) noexcept; +Error ParseMd5CryptString(const std::string& input, std::string& outHash, std::string& outSalt); } // namespace reindexer diff --git a/cpp_src/tools/semversion.h b/cpp_src/tools/semversion.h index 0e37f746f..c02a384b3 100644 --- a/cpp_src/tools/semversion.h +++ b/cpp_src/tools/semversion.h @@ -12,14 +12,14 @@ class SemVersion { SemVersion() = default; SemVersion(std::string_view version) { parse(version); } - bool operator<(const SemVersion &rVersion) const { + bool operator<(const SemVersion& rVersion) const { return std::lexicographical_compare(versionDigits_.begin(), versionDigits_.end(), rVersion.versionDigits_.begin(), rVersion.versionDigits_.end()); } - bool operator==(const SemVersion &rVersion) const { return (versionDigits_ == rVersion.versionDigits_); } - bool operator!=(const SemVersion &rVersion) const { return (versionDigits_ != rVersion.versionDigits_); } + bool operator==(const SemVersion& rVersion) const { return (versionDigits_ == rVersion.versionDigits_); } + bool operator!=(const SemVersion& rVersion) const { return (versionDigits_ != rVersion.versionDigits_); } - const std::string &StrippedString() const { return versionStr_; } + const std::string& StrippedString() const { return versionStr_; } private: void parse(std::string_view input) { @@ -37,7 +37,7 @@ class SemVersion { } version = splitted[0]; split(version, ".", false, splitted); - for (auto &it : splitted) { + for (auto& it : splitted) { bool valid = true; int res = jsteemann::atoi(it.data(), it.data() + it.size(), valid); if (!valid) { diff --git a/cpp_src/tools/serializer.cc b/cpp_src/tools/serializer.cc index c7016b7c9..46dbe79ea 100644 --- a/cpp_src/tools/serializer.cc +++ b/cpp_src/tools/serializer.cc @@ -9,7 +9,7 @@ namespace reindexer { p_string Serializer::GetPVString() { return p_string(getPVStringPtr()); } p_string Serializer::GetPSlice() { - auto ret = reinterpret_cast(buf_ + pos_); + auto ret = reinterpret_cast(buf_ + pos_); auto l = GetUInt32(); checkbound(pos_, l, len_); pos_ += l; @@ -30,8 +30,8 @@ p_string Serializer::GetPSlice() { Variant Serializer::getPVStringVariant() { return Variant(GetPVString()); } -const v_string_hdr *Serializer::getPVStringPtr() { - auto ret = reinterpret_cast(buf_ + pos_); +const v_string_hdr* Serializer::getPVStringPtr() { + auto ret = reinterpret_cast(buf_ + pos_); auto l = GetVarUint(); checkbound(pos_, l, len_); pos_ += l; @@ -80,10 +80,10 @@ void WrSerializer::VStringHelper::End() { } void WrSerializer::PrintJsonString(std::string_view str, PrintJsonStringMode mode) { - const char *s = str.data(); + const char* s = str.data(); size_t l = str.size(); grow(l * 6 + 3); - char *d = reinterpret_cast(buf_ + len_); + char* d = reinterpret_cast(buf_ + len_); *d++ = '"'; while (l--) { @@ -131,24 +131,24 @@ void WrSerializer::PrintJsonString(std::string_view str, PrintJsonStringMode mod } } *d++ = '"'; - len_ = d - reinterpret_cast(buf_); + len_ = d - reinterpret_cast(buf_); } void WrSerializer::PutStrUuid(Uuid uuid) { grow(Uuid::kStrFormLen + 10); len_ += uint32_pack(Uuid::kStrFormLen, buf_ + len_); - uuid.PutToStr({reinterpret_cast(buf_ + len_), cap_ - len_}); + uuid.PutToStr({reinterpret_cast(buf_ + len_), cap_ - len_}); len_ += Uuid::kStrFormLen; } void WrSerializer::PrintJsonUuid(Uuid uuid) { grow(Uuid::kStrFormLen + 2); - char *d = reinterpret_cast(buf_ + len_); + char* d = reinterpret_cast(buf_ + len_); *d++ = '"'; uuid.PutToStr({d, cap_ - len_}); d += Uuid::kStrFormLen; *d++ = '"'; - len_ = d - reinterpret_cast(buf_); + len_ = d - reinterpret_cast(buf_); } const int kHexDumpBytesInRow = 16; @@ -156,7 +156,7 @@ const int kHexDumpBytesInRow = 16; void WrSerializer::PrintHexDump(std::string_view str) { grow((kHexDumpBytesInRow * 4 + 12) * (1 + (str.size() / kHexDumpBytesInRow))); - char *d = reinterpret_cast(buf_ + len_); + char* d = reinterpret_cast(buf_ + len_); for (int row = 0; row < int(str.size()); row += kHexDumpBytesInRow) { d = u32toax(row, d, 8); @@ -178,11 +178,11 @@ void WrSerializer::PrintHexDump(std::string_view str) { } *d++ = '\n'; } - len_ = d - reinterpret_cast(buf_); + len_ = d - reinterpret_cast(buf_); } std::unique_ptr WrSerializer::DetachLStr() { - reinterpret_cast(buf_)->length = len_ - sizeof(uint32_t); + reinterpret_cast(buf_)->length = len_ - sizeof(uint32_t); return DetachBuf(); } diff --git a/cpp_src/tools/serializer.h b/cpp_src/tools/serializer.h index ecd52da7c..f6a532815 100644 --- a/cpp_src/tools/serializer.h +++ b/cpp_src/tools/serializer.h @@ -11,8 +11,8 @@ #include "tools/stringstools.h" #include "tools/varint.h" -char *i32toa(int32_t value, char *buffer); -char *i64toa(int64_t value, char *buffer); +char* i32toa(int32_t value, char* buffer); +char* i64toa(int64_t value, char* buffer); namespace reindexer { @@ -25,8 +25,8 @@ constexpr auto kFalseSV = std::string_view("false"); class Serializer { public: - Serializer(const void *buf, size_t len) noexcept : buf_(static_cast(buf)), len_(len), pos_(0) {} - explicit Serializer(std::string_view buf) noexcept : buf_(reinterpret_cast(buf.data())), len_(buf.length()), pos_(0) {} + Serializer(const void* buf, size_t len) noexcept : buf_(static_cast(buf)), len_(len), pos_(0) {} + explicit Serializer(std::string_view buf) noexcept : buf_(reinterpret_cast(buf.data())), len_(buf.length()), pos_(0) {} bool Eof() const noexcept { return pos_ >= len_; } [[nodiscard]] RX_ALWAYS_INLINE KeyValueType GetKeyValueType() { return KeyValueType::fromNumber(GetVarUint()); } [[nodiscard]] Variant GetVariant() { @@ -65,7 +65,7 @@ class Serializer { } RX_ALWAYS_INLINE std::string_view GetSlice() { auto l = GetUInt32(); - std::string_view b(reinterpret_cast(buf_ + pos_), l); + std::string_view b(reinterpret_cast(buf_ + pos_), l); checkbound(pos_, b.size(), len_); pos_ += b.size(); return b; @@ -123,7 +123,7 @@ class Serializer { auto l = GetVarUint(); checkbound(pos_, l, len_); pos_ += l; - return {reinterpret_cast(buf_ + pos_ - l), std::string_view::size_type(l)}; + return {reinterpret_cast(buf_ + pos_ - l), std::string_view::size_type(l)}; } p_string GetPVString(); p_string GetPSlice(); @@ -131,7 +131,7 @@ class Serializer { RX_ALWAYS_INLINE bool GetBool() { return bool(GetVarUint()); } size_t Pos() const noexcept { return pos_; } void SetPos(size_t p) noexcept { pos_ = p; } - const uint8_t *Buf() const noexcept { return buf_; } + const uint8_t* Buf() const noexcept { return buf_; } size_t Len() const noexcept { return len_; } void Reset() noexcept { pos_ = 0; } @@ -145,9 +145,9 @@ class Serializer { [[noreturn]] void throwScanIntError(std::string_view type); [[noreturn]] void throwUnknownTypeError(std::string_view type); Variant getPVStringVariant(); - const v_string_hdr *getPVStringPtr(); + const v_string_hdr* getPVStringPtr(); - const uint8_t *buf_; + const uint8_t* buf_; size_t len_; size_t pos_; }; @@ -157,15 +157,15 @@ class WrSerializer { WrSerializer() noexcept : buf_(inBuf_), len_(0), cap_(sizeof(inBuf_)) {} template explicit WrSerializer(uint8_t (&buf)[N]) noexcept : buf_(buf), len_(0), cap_(N), hasExternalBuf_(true) {} - explicit WrSerializer(chunk &&ch) noexcept : buf_(ch.release()), len_(ch.len()), cap_(ch.capacity()) { + explicit WrSerializer(chunk&& ch) noexcept : buf_(ch.release()), len_(ch.len()), cap_(ch.capacity()) { if (!buf_) { buf_ = inBuf_; cap_ = sizeof(inBuf_); len_ = 0; } } - WrSerializer(const WrSerializer &) = delete; - WrSerializer(WrSerializer &&other) noexcept : len_(other.len_), cap_(other.cap_), hasExternalBuf_(other.hasExternalBuf_) { + WrSerializer(const WrSerializer&) = delete; + WrSerializer(WrSerializer&& other) noexcept : len_(other.len_), cap_(other.cap_), hasExternalBuf_(other.hasExternalBuf_) { if (other.buf_ == other.inBuf_) { buf_ = inBuf_; memcpy(buf_, other.buf_, other.len_ * sizeof(other.inBuf_[0])); @@ -180,12 +180,16 @@ class WrSerializer { other.hasExternalBuf_ = false; } ~WrSerializer() { - if (HasAllocatedBuffer()) delete[] buf_; // NOLINT(*.NewDelete) False positive + if (HasAllocatedBuffer()) { + delete[] buf_; // NOLINT(*.NewDelete) False positive + } } - WrSerializer &operator=(const WrSerializer &) = delete; - WrSerializer &operator=(WrSerializer &&other) noexcept { + WrSerializer& operator=(const WrSerializer&) = delete; + WrSerializer& operator=(WrSerializer&& other) noexcept { if (this != &other) { - if (HasAllocatedBuffer()) delete[] buf_; + if (HasAllocatedBuffer()) { + delete[] buf_; + } len_ = other.len_; cap_ = other.cap_; @@ -209,13 +213,13 @@ class WrSerializer { bool HasAllocatedBuffer() const noexcept { return buf_ != inBuf_ && !hasExternalBuf_; } RX_ALWAYS_INLINE void PutKeyValueType(KeyValueType t) { PutVarUint(t.toNumber()); } - void PutVariant(const Variant &kv) { + void PutVariant(const Variant& kv) { PutKeyValueType(kv.Type()); kv.Type().EvaluateOneOf( [&](KeyValueType::Tuple) { auto compositeValues = kv.getCompositeValues(); PutVarUint(compositeValues.size()); - for (auto &v : compositeValues) { + for (auto& v : compositeValues) { PutVariant(v); } }, @@ -240,11 +244,11 @@ class WrSerializer { private: class [[nodiscard]] SliceHelper { public: - SliceHelper(WrSerializer *ser, size_t pos) noexcept : ser_(ser), pos_(pos) {} - SliceHelper(const SliceHelper &) = delete; - SliceHelper operator=(const SliceHelper &) = delete; - SliceHelper(SliceHelper &&other) noexcept : ser_(other.ser_), pos_(other.pos_) { other.ser_ = nullptr; } - SliceHelper &operator=(SliceHelper &&other) noexcept { + SliceHelper(WrSerializer* ser, size_t pos) noexcept : ser_(ser), pos_(pos) {} + SliceHelper(const SliceHelper&) = delete; + SliceHelper operator=(const SliceHelper&) = delete; + SliceHelper(SliceHelper&& other) noexcept : ser_(other.ser_), pos_(other.pos_) { other.ser_ = nullptr; } + SliceHelper& operator=(SliceHelper&& other) noexcept { if (this != &other) { ser_ = other.ser_; pos_ = other.pos_; @@ -261,7 +265,7 @@ class WrSerializer { } private: - WrSerializer *ser_; + WrSerializer* ser_; size_t pos_; }; @@ -269,11 +273,11 @@ class WrSerializer { class [[nodiscard]] VStringHelper { public: VStringHelper() noexcept : ser_(nullptr), pos_(0) {} - VStringHelper(WrSerializer *ser, size_t pos) noexcept : ser_(ser), pos_(pos) {} - VStringHelper(const VStringHelper &) = delete; - VStringHelper operator=(const VStringHelper &) = delete; - VStringHelper(VStringHelper &&other) noexcept : ser_(other.ser_), pos_(other.pos_) { other.ser_ = nullptr; } - VStringHelper &operator=(VStringHelper &&other) noexcept { + VStringHelper(WrSerializer* ser, size_t pos) noexcept : ser_(ser), pos_(pos) {} + VStringHelper(const VStringHelper&) = delete; + VStringHelper operator=(const VStringHelper&) = delete; + VStringHelper(VStringHelper&& other) noexcept : ser_(other.ser_), pos_(other.pos_) { other.ser_ = nullptr; } + VStringHelper& operator=(VStringHelper&& other) noexcept { if (this != &other) { ser_ = other.ser_; pos_ = other.pos_; @@ -285,7 +289,7 @@ class WrSerializer { void End(); private: - WrSerializer *ser_; + WrSerializer* ser_; size_t pos_; }; @@ -315,52 +319,54 @@ class WrSerializer { } void PutDoubleStrNoTrailing(double v) { grow(32); - len_ += double_to_str_no_trailing(v, reinterpret_cast(buf_ + len_), 32); + len_ += double_to_str_no_trailing(v, reinterpret_cast(buf_ + len_), 32); } - template ::value>::type * = nullptr> - WrSerializer &operator<<(T k) { + template ::value>::type* = nullptr> + WrSerializer& operator<<(T k) { grow(32); - char *b = i64toa(k, reinterpret_cast(buf_ + len_)); - len_ = b - reinterpret_cast(buf_); + char* b = i64toa(k, reinterpret_cast(buf_ + len_)); + len_ = b - reinterpret_cast(buf_); return *this; } - template ::value>::type * = nullptr> - WrSerializer &operator<<(T k) { + template ::value>::type* = nullptr> + WrSerializer& operator<<(T k) { grow(32); - char *b = i32toa(k, reinterpret_cast(buf_ + len_)); - len_ = b - reinterpret_cast(buf_); + char* b = i32toa(k, reinterpret_cast(buf_ + len_)); + len_ = b - reinterpret_cast(buf_); return *this; } - WrSerializer &operator<<(char c) { - if (len_ + 1 >= cap_) grow(1); + WrSerializer& operator<<(char c) { + if (len_ + 1 >= cap_) { + grow(1); + } buf_[len_++] = c; return *this; } - WrSerializer &operator<<(std::string_view sv) { + WrSerializer& operator<<(std::string_view sv) { Write(sv); return *this; } - WrSerializer &operator<<(const char *sv) { + WrSerializer& operator<<(const char* sv) { Write(std::string_view(sv)); return *this; } - WrSerializer &operator<<(bool v) { + WrSerializer& operator<<(bool v) { using namespace std::string_view_literals; Write(v ? kTrueSV : kFalseSV); return *this; } - WrSerializer &operator<<(double v) { + WrSerializer& operator<<(double v) { grow(32); - len_ += double_to_str(v, reinterpret_cast(buf_ + len_), 32); + len_ += double_to_str(v, reinterpret_cast(buf_ + len_), 32); return *this; } - WrSerializer &operator<<(Uuid uuid) { + WrSerializer& operator<<(Uuid uuid) { grow(Uuid::kStrFormLen + 2); buf_[len_] = '\''; ++len_; - uuid.PutToStr(span{reinterpret_cast(&buf_[len_]), Uuid::kStrFormLen}); + uuid.PutToStr(span{reinterpret_cast(&buf_[len_]), Uuid::kStrFormLen}); len_ += Uuid::kStrFormLen; buf_[len_] = '\''; ++len_; @@ -377,27 +383,27 @@ class WrSerializer { memset(&buf_[len_], c, count); len_ += count; } - template > * = nullptr> + template >* = nullptr> RX_ALWAYS_INLINE void PutVarint(T v) { grow(10); len_ += sint64_pack(v, buf_ + len_); } - template > * = nullptr> + template >* = nullptr> RX_ALWAYS_INLINE void PutVarUint(T v) { grow(10); len_ += uint64_pack(v, buf_ + len_); } - template > * = nullptr> + template >* = nullptr> RX_ALWAYS_INLINE void PutVarint(T v) { grow(10); len_ += sint32_pack(v, buf_ + len_); } - template > * = nullptr> + template >* = nullptr> RX_ALWAYS_INLINE void PutVarUint(T v) { grow(10); len_ += uint32_pack(v, buf_ + len_); } - template > * = nullptr> + template >* = nullptr> RX_ALWAYS_INLINE void PutVarUint(T v) { assertrx(v >= 0 && v < 128); grow(1); @@ -424,7 +430,7 @@ class WrSerializer { memcpy(&buf_[len_], slice.data(), slice.size()); len_ += slice.size(); } - RX_ALWAYS_INLINE uint8_t *Buf() const noexcept { return buf_; } + RX_ALWAYS_INLINE uint8_t* Buf() const noexcept { return buf_; } std::unique_ptr DetachBuf() { std::unique_ptr ret; @@ -460,20 +466,22 @@ class WrSerializer { void Reserve(size_t cap) { if (cap > cap_) { cap_ = cap; - uint8_t *b = new uint8_t[cap_]; + uint8_t* b = new uint8_t[cap_]; memcpy(b, buf_, len_); - if (HasAllocatedBuffer()) delete[] buf_; // NOLINT(*.NewDelete) False positive + if (HasAllocatedBuffer()) { + delete[] buf_; // NOLINT(*.NewDelete) False positive + } buf_ = b; hasExternalBuf_ = false; } } - RX_ALWAYS_INLINE std::string_view Slice() const noexcept { return {reinterpret_cast(buf_), len_}; } - const char *c_str() noexcept { + RX_ALWAYS_INLINE std::string_view Slice() const noexcept { return {reinterpret_cast(buf_), len_}; } + const char* c_str() noexcept { if (!len_ || buf_[len_] != 0) { grow(1); buf_[len_] = 0; } - return reinterpret_cast(buf_); + return reinterpret_cast(buf_); } protected: @@ -485,15 +493,15 @@ class WrSerializer { Reserve((newCap == newCapAligned) ? newCap : (newCapAligned + 0x1000)); } } - uint8_t *buf_ = nullptr; + uint8_t* buf_ = nullptr; size_t len_ = 0; size_t cap_ = 0; uint8_t inBuf_[0x100]; bool hasExternalBuf_ = false; }; -inline int msgpack_wrserializer_write(void *data, const char *buf, size_t len) { - reinterpret_cast(data)->Write(std::string_view(buf, len)); +inline int msgpack_wrserializer_write(void* data, const char* buf, size_t len) { + reinterpret_cast(data)->Write(std::string_view(buf, len)); return 0; } diff --git a/cpp_src/tools/string_regexp_functions.cc b/cpp_src/tools/string_regexp_functions.cc index f1b95044e..75de60ce8 100644 --- a/cpp_src/tools/string_regexp_functions.cc +++ b/cpp_src/tools/string_regexp_functions.cc @@ -8,11 +8,15 @@ namespace reindexer { std::string makeLikePattern(std::string_view utf8Str) { std::wstring utf16Str = reindexer::utf8_to_utf16(utf8Str); - for (wchar_t &ch : utf16Str) { - if (rand() % 4 == 0) ch = L'_'; + for (wchar_t& ch : utf16Str) { + if (rand() % 4 == 0) { + ch = L'_'; + } } std::wstring result; - if (rand() % 4 == 0) result += L'%'; + if (rand() % 4 == 0) { + result += L'%'; + } std::wstring::size_type next = rand() % (utf16Str.size() + 1); std::wstring::size_type last = next; for (std::wstring::size_type current = 0; current < utf16Str.size();) { @@ -22,9 +26,13 @@ std::string makeLikePattern(std::string_view utf8Str) { current = (rand() % (utf16Str.size() - last + 1)) + last; } next = (rand() % (utf16Str.size() - current + 1)) + current; - if (current > last || rand() % 4 == 0) result += L'%'; + if (current > last || rand() % 4 == 0) { + result += L'%'; + } + } + if (rand() % 4 == 0) { + result += L'%'; } - if (rand() % 4 == 0) result += L'%'; return reindexer::utf16_to_utf8(result); } @@ -35,7 +43,7 @@ std::string sqlLikePattern2ECMAScript(std::string pattern) { } else if (pattern[pos] == '%') { pattern.replace(pos, 1, ".*"); } - const char *ptr = &pattern[pos]; + const char* ptr = &pattern[pos]; utf8::unchecked::next(ptr); pos = ptr - pattern.data(); } @@ -44,10 +52,10 @@ std::string sqlLikePattern2ECMAScript(std::string pattern) { bool matchLikePattern(std::string_view utf8Str, std::string_view utf8Pattern) { constexpr static wchar_t anyChar = L'_', wildChar = L'%'; - const char *pIt = utf8Pattern.data(); - const char * const pEnd = utf8Pattern.data() + utf8Pattern.size(); - const char *sIt = utf8Str.data(); - const char * const sEnd = utf8Str.data() + utf8Str.size(); + const char* pIt = utf8Pattern.data(); + const char* const pEnd = utf8Pattern.data() + utf8Pattern.size(); + const char* sIt = utf8Str.data(); + const char* const sEnd = utf8Str.data() + utf8Str.size(); bool haveWildChar = false; while (pIt != pEnd && sIt != sEnd) { @@ -56,12 +64,14 @@ bool matchLikePattern(std::string_view utf8Str, std::string_view utf8Pattern) { haveWildChar = true; break; } - if (ToLower(pCh) != ToLower(utf8::unchecked::next(sIt)) && pCh != anyChar) return false; + if (ToLower(pCh) != ToLower(utf8::unchecked::next(sIt)) && pCh != anyChar) { + return false; + } } while (pIt != pEnd && sIt != sEnd) { - const char *tmpSIt = sIt; - const char *tmpPIt = pIt; + const char* tmpSIt = sIt; + const char* tmpPIt = pIt; while (tmpPIt != pEnd) { const wchar_t pCh = utf8::unchecked::next(tmpPIt); if (pCh == wildChar) { @@ -70,7 +80,9 @@ bool matchLikePattern(std::string_view utf8Str, std::string_view utf8Pattern) { haveWildChar = true; break; } - if (tmpSIt == sEnd) return false; + if (tmpSIt == sEnd) { + return false; + } if (ToLower(pCh) != ToLower(utf8::unchecked::next(tmpSIt)) && pCh != anyChar) { utf8::unchecked::next(sIt); break; @@ -83,16 +95,24 @@ bool matchLikePattern(std::string_view utf8Str, std::string_view utf8Pattern) { } while (pIt != pEnd) { - if (utf8::unchecked::next(pIt) != wildChar) return false; + if (utf8::unchecked::next(pIt) != wildChar) { + return false; + } haveWildChar = true; } - if (!haveWildChar && sIt != sEnd) return false; + if (!haveWildChar && sIt != sEnd) { + return false; + } for (pIt = pEnd, sIt = sEnd; pIt != utf8Pattern.data() && sIt != utf8Str.data();) { const wchar_t pCh = utf8::unchecked::prior(pIt); - if (pCh == wildChar) return true; - if (ToLower(pCh) != ToLower(utf8::unchecked::prior(sIt)) && pCh != anyChar) return false; + if (pCh == wildChar) { + return true; + } + if (ToLower(pCh) != ToLower(utf8::unchecked::prior(sIt)) && pCh != anyChar) { + return false; + } } return true; } diff --git a/cpp_src/tools/stringstools.cc b/cpp_src/tools/stringstools.cc index 2a9b1afd1..8637fffea 100644 --- a/cpp_src/tools/stringstools.cc +++ b/cpp_src/tools/stringstools.cc @@ -19,7 +19,7 @@ namespace reindexer { namespace stringtools_impl { -static int double_to_str(double v, char *buf, int capacity, int flags) { +static int double_to_str(double v, char* buf, int capacity, int flags) { double_conversion::StringBuilder builder(buf, capacity); double_conversion::DoubleToStringConverter dc(flags, NULL, NULL, 'e', -6, 21, 0, 0); @@ -47,14 +47,16 @@ static std::pair word2Pos(std::string_view str, int wordPos, int endPo while (IsAlpha(ch) || IsDigit(ch) || extraWordSymbols.find(ch) != std::string::npos) { wordEndIt = it; - if (it == endIt) break; + if (it == endIt) { + break; + } ch = utf8::unchecked::next(it); } if (wordStartIt != it) { - if (!wordPos) + if (!wordPos) { break; - else { + } else { wordPos--; wordStartIt = it; } @@ -70,7 +72,9 @@ static std::pair word2Pos(std::string_view str, int wordPos, int endPo while (IsAlpha(ch) || IsDigit(ch) || extraWordSymbols.find(ch) != std::string::npos) { wordEndIt = it; - if (it == endIt) break; + if (it == endIt) { + break; + } ch = utf8::unchecked::next(it); } } @@ -78,23 +82,29 @@ static std::pair word2Pos(std::string_view str, int wordPos, int endPo return {int(std::distance(str.begin(), wordStartIt)), int(std::distance(str.begin(), wordEndIt))}; } -static std::string_view urldecode2(char *buf, std::string_view str) { +static std::string_view urldecode2(char* buf, std::string_view str) { char a, b; - const char *src = str.data(); - char *dst = buf; + const char* src = str.data(); + char* dst = buf; for (size_t l = 0; l < str.length(); l++) { if (l + 2 < str.length() && (*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) { - if (a >= 'a') a -= 'a' - 'A'; - if (a >= 'A') + if (a >= 'a') { + a -= 'a' - 'A'; + } + if (a >= 'A') { a -= ('A' - 10); - else + } else { a -= '0'; - if (b >= 'a') b -= 'a' - 'A'; - if (b >= 'A') + } + if (b >= 'a') { + b -= 'a' - 'A'; + } + if (b >= 'A') { b -= ('A' - 10); - else + } else { b -= '0'; + } *dst++ = 16 * a + b; src += 3; l += 2; @@ -111,11 +121,13 @@ static std::string_view urldecode2(char *buf, std::string_view str) { // Sat Jul 15 14 : 18 : 56 2017 GMT -static const char *kDaysOfWeek[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -static const char *kMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static const char* kDaysOfWeek[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char* kMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -inline static char *strappend(char *dst, const char *src) noexcept { - while (*src) *dst++ = *src++; +inline static char* strappend(char* dst, const char* src) noexcept { + while (*src) { + *dst++ = *src++; + } return dst; } @@ -128,7 +140,9 @@ constexpr static auto kStrictModes = frozen::make_unordered_map calcUtf8AfterDelims(std::string_view str, size_t limit, std::string_view delims) noexcept { - const char *ptr; - const char *strEnd; - const char *ptrDelims; - const char *delimsEnd; + const char* ptr; + const char* strEnd; + const char* ptrDelims; + const char* delimsEnd; size_t charCounter = 0; for (ptr = str.data(), strEnd = str.data() + str.size(); limit && ptr < strEnd; limit--) { uint32_t c = utf8::unchecked::next(ptr); @@ -214,16 +232,18 @@ std::pair calcUtf8AfterDelims(std::string_view str, size_t limit } // This functions calculate how many bytes takes limit symbols in UTF8 backward -size_t calcUtf8Before(const char *str, int pos, size_t limit) noexcept { - const char *ptr = str + pos; - for (; limit && ptr > str; limit--) utf8::unchecked::prior(ptr); +size_t calcUtf8Before(const char* str, int pos, size_t limit) noexcept { + const char* ptr = str + pos; + for (; limit && ptr > str; limit--) { + utf8::unchecked::prior(ptr); + } return str + pos - ptr; } -std::pair calcUtf8BeforeDelims(const char *str, int pos, size_t limit, std::string_view delims) noexcept { - const char *ptr = str + pos; - const char *ptrDelim; - const char *delimsEnd; +std::pair calcUtf8BeforeDelims(const char* str, int pos, size_t limit, std::string_view delims) noexcept { + const char* ptr = str + pos; + const char* ptrDelim; + const char* delimsEnd; int charCounter = 0; for (; limit && ptr > str; limit--) { uint32_t c = utf8::unchecked::prior(ptr); @@ -239,7 +259,7 @@ std::pair calcUtf8BeforeDelims(const char *str, int pos, size_t return std::make_pair(str + pos - ptr, charCounter); } -void split(std::string_view str, std::string &buf, std::vector &words, std::string_view extraWordSymbols) { +void split(std::string_view str, std::string& buf, std::vector& words, std::string_view extraWordSymbols) { // assuming that the 'ToLower' function and the 'check for replacement' function should not change the character size in bytes buf.resize(str.length()); words.resize(0); @@ -341,11 +361,13 @@ std::pair Word2PosHelper::convert(int wordPos, int endPos) { return ret; } -void split(std::string_view utf8Str, std::wstring &utf16str, std::vector &words, std::string_view extraWordSymbols) { +void split(std::string_view utf8Str, std::wstring& utf16str, std::vector& words, std::string_view extraWordSymbols) { utf8_to_utf16(utf8Str, utf16str); words.resize(0); for (auto it = utf16str.begin(); it != utf16str.end();) { - while (it != utf16str.end() && !IsAlpha(*it) && !IsDigit(*it)) it++; + while (it != utf16str.end() && !IsAlpha(*it) && !IsDigit(*it)) { + it++; + } auto begIt = it; while (it != utf16str.end() && (IsAlpha(*it) || IsDigit(*it) || extraWordSymbols.find(*it) != std::string::npos)) { @@ -361,15 +383,23 @@ void split(std::string_view utf8Str, std::wstring &utf16str, std::vector bool checkIfStartsWith(std::string_view pattern, std::string_view str) noexcept { - if (pattern.empty() || str.empty()) return false; - if (pattern.length() > str.length()) return false; + if (pattern.empty() || str.empty()) { + return false; + } + if (pattern.length() > str.length()) { + return false; + } if constexpr (sensitivity == CaseSensitive::Yes) { for (size_t i = 0; i < pattern.length(); ++i) { - if (pattern[i] != str[i]) return false; + if (pattern[i] != str[i]) { + return false; + } } } else { for (size_t i = 0; i < pattern.length(); ++i) { - if (tolower(pattern[i]) != tolower(str[i])) return false; + if (tolower(pattern[i]) != tolower(str[i])) { + return false; + } } } return true; @@ -379,16 +409,24 @@ template bool checkIfStartsWith(std::string_view pattern, std template bool checkIfEndsWith(std::string_view pattern, std::string_view src) noexcept { - if (pattern.length() > src.length()) return false; - if (pattern.length() == 0) return true; + if (pattern.length() > src.length()) { + return false; + } + if (pattern.length() == 0) { + return true; + } const auto offset = src.length() - pattern.length(); if constexpr (sensitivity == CaseSensitive::Yes) { for (size_t i = 0; i < pattern.length(); ++i) { - if (src[offset + i] != pattern[i]) return false; + if (src[offset + i] != pattern[i]) { + return false; + } } } else { for (size_t i = 0; i < pattern.length(); ++i) { - if (tolower(src[offset + i]) != tolower(pattern[i])) return false; + if (tolower(src[offset + i]) != tolower(pattern[i])) { + return false; + } } } return true; @@ -397,7 +435,7 @@ template bool checkIfEndsWith(std::string_view pattern, std: template bool checkIfEndsWith(std::string_view pattern, std::string_view src) noexcept; template <> -ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable &) noexcept { +ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable&) noexcept { auto itl = lhs.begin(); auto itr = rhs.begin(); @@ -405,8 +443,12 @@ ComparationResult collateCompare(std::string_view lhs, std::string auto chl = tolower(*itl++); auto chr = tolower(*itr++); - if (chl > chr) return ComparationResult::Gt; - if (chl < chr) return ComparationResult::Lt; + if (chl > chr) { + return ComparationResult::Gt; + } + if (chl < chr) { + return ComparationResult::Lt; + } } if (lhs.size() > rhs.size()) { @@ -419,7 +461,7 @@ ComparationResult collateCompare(std::string_view lhs, std::string } template <> -ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable &) noexcept { +ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable&) noexcept { auto itl = lhs.data(); auto itr = rhs.data(); @@ -427,8 +469,12 @@ ComparationResult collateCompare(std::string_view lhs, std::string_ auto chl = ToLower(utf8::unchecked::next(itl)); auto chr = ToLower(utf8::unchecked::next(itr)); - if (chl > chr) return ComparationResult::Gt; - if (chl < chr) return ComparationResult::Lt; + if (chl > chr) { + return ComparationResult::Gt; + } + if (chl < chr) { + return ComparationResult::Lt; + } } if (lhs.size() > rhs.size()) { @@ -440,9 +486,9 @@ ComparationResult collateCompare(std::string_view lhs, std::string_ } template <> -ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable &) noexcept { - char *posl = nullptr; - char *posr = nullptr; +ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable&) noexcept { + char* posl = nullptr; + char* posr = nullptr; int numl = strtol(lhs.data(), &posl, 10); int numr = strtol(rhs.data(), &posr, 10); @@ -451,7 +497,9 @@ ComparationResult collateCompare(std::string_view lhs, std::stri auto minlen = std::min(lhs.size() - (posl - lhs.data()), rhs.size() - (posr - rhs.data())); auto res = strncmp(posl, posr, minlen); - if (res != 0) return res < 0 ? ComparationResult::Lt : ComparationResult::Gt; + if (res != 0) { + return res < 0 ? ComparationResult::Lt : ComparationResult::Gt; + } return lhs.size() > rhs.size() ? ComparationResult::Gt : (lhs.size() < rhs.size() ? ComparationResult::Lt : ComparationResult::Eq); } @@ -461,7 +509,7 @@ ComparationResult collateCompare(std::string_view lhs, std::stri template <> ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, - const SortingPrioritiesTable &sortOrderTable) noexcept { + const SortingPrioritiesTable& sortOrderTable) noexcept { auto itl = lhs.data(); auto itr = rhs.data(); @@ -472,8 +520,12 @@ ComparationResult collateCompare(std::string_view lhs, std::strin int chlPriority = sortOrderTable.GetPriority(chl); int chrPriority = sortOrderTable.GetPriority(chr); - if (chlPriority > chrPriority) return ComparationResult::Gt; - if (chlPriority < chrPriority) return ComparationResult::Lt; + if (chlPriority > chrPriority) { + return ComparationResult::Gt; + } + if (chlPriority < chrPriority) { + return ComparationResult::Lt; + } } if (lhs.size() > rhs.size()) { @@ -485,7 +537,7 @@ ComparationResult collateCompare(std::string_view lhs, std::strin } template <> -ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable &) noexcept { +ComparationResult collateCompare(std::string_view lhs, std::string_view rhs, const SortingPrioritiesTable&) noexcept { size_t l1 = lhs.size(); size_t l2 = rhs.size(); int res = memcmp(lhs.data(), rhs.data(), std::min(l1, l2)); @@ -503,16 +555,18 @@ std::string urldecode2(std::string_view str) { return ret; } -int fast_strftime(char *buf, const tm *tm) { - char *d = buf; +int fast_strftime(char* buf, const tm* tm) { + char* d = buf; - if (unsigned(tm->tm_wday) < sizeof(stringtools_impl::kDaysOfWeek) / sizeof stringtools_impl::kDaysOfWeek[0]) + if (unsigned(tm->tm_wday) < sizeof(stringtools_impl::kDaysOfWeek) / sizeof stringtools_impl::kDaysOfWeek[0]) { d = stringtools_impl::strappend(d, stringtools_impl::kDaysOfWeek[tm->tm_wday]); + } d = stringtools_impl::strappend(d, ", "); d = i32toa(tm->tm_mday, d); *d++ = ' '; - if (unsigned(tm->tm_mon) < sizeof(stringtools_impl::kMonths) / sizeof stringtools_impl::kMonths[0]) + if (unsigned(tm->tm_mon) < sizeof(stringtools_impl::kMonths) / sizeof stringtools_impl::kMonths[0]) { d = stringtools_impl::strappend(d, stringtools_impl::kMonths[tm->tm_mon]); + } *d++ = ' '; d = i32toa(tm->tm_year + 1900, d); *d++ = ' '; @@ -571,7 +625,7 @@ StrictMode strictModeFromString(std::string_view strStrictMode) { } std::string_view strictModeToString(StrictMode mode) { - for (auto &it : stringtools_impl::kStrictModes) { + for (auto& it : stringtools_impl::kStrictModes) { if (it.second == mode) { return it.first; } @@ -584,15 +638,21 @@ bool isPrintable(std::string_view str) noexcept { return false; } for (auto c : str) { - if (c < 0x20) return false; + if (c < 0x20) { + return false; + } } return true; } bool isBlank(std::string_view str) noexcept { - if (str.empty()) return true; + if (str.empty()) { + return true; + } for (auto c : str) { - if (!isspace(c)) return false; + if (!isspace(c)) { + return false; + } } return true; } @@ -603,7 +663,7 @@ int getUTF8StringCharactersCount(std::string_view str) noexcept { for (auto it = str.begin(); it != str.end(); ++len) { utf8::next(it, str.end()); } - } catch (const std::exception &) { + } catch (const std::exception&) { return str.length(); } return len; @@ -636,14 +696,14 @@ int64_t stoll(std::string_view sl) { return ret; } -int double_to_str(double v, char *buf, int capacity) { +int double_to_str(double v, char* buf, int capacity) { const int flags = double_conversion::DoubleToStringConverter::UNIQUE_ZERO | double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN | double_conversion::DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT | double_conversion::DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT; return stringtools_impl::double_to_str(v, buf, capacity, flags); } -int double_to_str_no_trailing(double v, char *buf, int capacity) { +int double_to_str_no_trailing(double v, char* buf, int capacity) { const int flags = double_conversion::DoubleToStringConverter::UNIQUE_ZERO | double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN; return stringtools_impl::double_to_str(v, buf, capacity, flags); @@ -668,7 +728,7 @@ std::string randStringAlph(size_t len) { } template -void toNextCh(std::string_view::iterator &it, std::string_view str) { +void toNextCh(std::string_view::iterator& it, std::string_view str) { if (isUtf8) { utf8::next(it, str.end()); } else { @@ -677,7 +737,7 @@ void toNextCh(std::string_view::iterator &it, std::string_view str) { } template -void toPrevCh(std::string_view::iterator &it, std::string_view str) { +void toPrevCh(std::string_view::iterator& it, std::string_view str) { if (isUtf8) { utf8::previous(it, str.begin()); } else { @@ -686,7 +746,7 @@ void toPrevCh(std::string_view::iterator &it, std::string_view str) { } template -Error getBytePosInMultilineString(std::string_view str, const size_t line, const size_t charPos, size_t &bytePos) { +Error getBytePosInMultilineString(std::string_view str, const size_t line, const size_t charPos, size_t& bytePos) { auto it = str.begin(); size_t currLine = 0, currCharPos = 0; for (size_t i = 0; it != str.end() && ((currLine != line) || (currCharPos != charPos)); toNextCh(it, str), ++i) { @@ -703,10 +763,10 @@ Error getBytePosInMultilineString(std::string_view str, const size_t line, const return Error(errNotValid, "Wrong cursor position: line=%d, pos=%d", line, charPos); } -Error cursosPosToBytePos(std::string_view str, size_t line, size_t charPos, size_t &bytePos) { +Error cursosPosToBytePos(std::string_view str, size_t line, size_t charPos, size_t& bytePos) { try { return getBytePosInMultilineString(str, line, charPos, bytePos); - } catch (const utf8::exception &) { + } catch (const utf8::exception&) { return getBytePosInMultilineString(str, line, charPos, bytePos); } } diff --git a/cpp_src/tools/stringstools.h b/cpp_src/tools/stringstools.h index b182a7436..ce91c74e4 100644 --- a/cpp_src/tools/stringstools.h +++ b/cpp_src/tools/stringstools.h @@ -43,7 +43,9 @@ Container& split(const typename Container::value_type& str, std::string_view del pos = str.find_first_of(delimiters, lastPos); if (pos == Container::value_type::npos) { pos = str.length(); - if (pos != lastPos || !trimEmpty) tokens.push_back(str.substr(lastPos, pos - lastPos)); + if (pos != lastPos || !trimEmpty) { + tokens.push_back(str.substr(lastPos, pos - lastPos)); + } break; } else if (pos != lastPos || !trimEmpty) { tokens.push_back(str.substr(lastPos, pos - lastPos)); @@ -174,9 +176,13 @@ StrictMode strictModeFromString(std::string_view strStrictMode); std::string_view strictModeToString(StrictMode mode); inline constexpr bool iequals(std::string_view lhs, std::string_view rhs) noexcept { - if (lhs.size() != rhs.size()) return false; + if (lhs.size() != rhs.size()) { + return false; + } for (auto itl = lhs.begin(), itr = rhs.begin(); itl != lhs.end() && itr != rhs.end();) { - if (tolower(*itl++) != tolower(*itr++)) return false; + if (tolower(*itl++) != tolower(*itr++)) { + return false; + } } return true; } diff --git a/cpp_src/tools/tcmallocheapwathcher.cc b/cpp_src/tools/tcmallocheapwathcher.cc index 2942e5f2d..2b284b2bf 100644 --- a/cpp_src/tools/tcmallocheapwathcher.cc +++ b/cpp_src/tools/tcmallocheapwathcher.cc @@ -13,7 +13,7 @@ static const size_t kHeapFreeMinThreshold = 200 * 1048576; ///< Do not release p TCMallocHeapWathcher::TCMallocHeapWathcher() : TCMallocHeapWathcher(nullptr, -1, -1.0) {} -TCMallocHeapWathcher::TCMallocHeapWathcher(MallocExtension *mallocExtention, int64_t cacheLimit, float maxCacheRatio, +TCMallocHeapWathcher::TCMallocHeapWathcher(MallocExtension* mallocExtention, int64_t cacheLimit, float maxCacheRatio, std::shared_ptr logger) : mallocExtention_(mallocExtention), cacheLimit_(cacheLimit), @@ -22,11 +22,11 @@ TCMallocHeapWathcher::TCMallocHeapWathcher(MallocExtension *mallocExtention, int heapChunkReleasePeriod_(std::chrono::milliseconds(100)), logger_(std::move(logger)) {} -TCMallocHeapWathcher::TCMallocHeapWathcher(MallocExtension *mallocExtention, int64_t cacheLimit, float maxCacheRatio) +TCMallocHeapWathcher::TCMallocHeapWathcher(MallocExtension* mallocExtention, int64_t cacheLimit, float maxCacheRatio) : TCMallocHeapWathcher(mallocExtention, cacheLimit, maxCacheRatio, nullptr) {} template -void TCMallocHeapWathcher::logDebug(Args &&...args) { +void TCMallocHeapWathcher::logDebug(Args&&... args) { if (logger_) { logger_->debug(std::forward(args)...); } @@ -47,7 +47,9 @@ void TCMallocHeapWathcher::CheckHeapUsagePeriodic() { std::chrono::duration_cast(deadline_.time_since_epoch()).count()); }); - if (!mallocExtention_) return; + if (!mallocExtention_) { + return; + } if ((cacheLimit_ > 0) || (maxCacheRatio_ > 0)) { if (ClockT::now_coarse() < deadline_) { diff --git a/cpp_src/tools/tcmallocheapwathcher.h b/cpp_src/tools/tcmallocheapwathcher.h index 3f2132f8e..0f4bec7db 100644 --- a/cpp_src/tools/tcmallocheapwathcher.h +++ b/cpp_src/tools/tcmallocheapwathcher.h @@ -17,14 +17,14 @@ namespace reindexer { class TCMallocHeapWathcher { public: TCMallocHeapWathcher(); - explicit TCMallocHeapWathcher(MallocExtension *mallocExtention, int64_t cacheLimit, float maxCacheRatio); - explicit TCMallocHeapWathcher(MallocExtension *mallocExtention, int64_t cacheLimit, float maxCacheRatio, + explicit TCMallocHeapWathcher(MallocExtension* mallocExtention, int64_t cacheLimit, float maxCacheRatio); + explicit TCMallocHeapWathcher(MallocExtension* mallocExtention, int64_t cacheLimit, float maxCacheRatio, std::shared_ptr logger); - TCMallocHeapWathcher(const TCMallocHeapWathcher &) = delete; - TCMallocHeapWathcher &operator=(const TCMallocHeapWathcher &) = delete; - TCMallocHeapWathcher(TCMallocHeapWathcher &&) = default; - TCMallocHeapWathcher &operator=(TCMallocHeapWathcher &&) = default; + TCMallocHeapWathcher(const TCMallocHeapWathcher&) = delete; + TCMallocHeapWathcher& operator=(const TCMallocHeapWathcher&) = delete; + TCMallocHeapWathcher(TCMallocHeapWathcher&&) = default; + TCMallocHeapWathcher& operator=(TCMallocHeapWathcher&&) = default; ~TCMallocHeapWathcher(); void CheckHeapUsagePeriodic(); @@ -32,7 +32,7 @@ class TCMallocHeapWathcher { private: using ClockT = steady_clock_w; - MallocExtension *mallocExtention_; + MallocExtension* mallocExtention_; int64_t cacheLimit_; float maxCacheRatio_; std::chrono::microseconds heapInspectionPeriod_; @@ -41,7 +41,7 @@ class TCMallocHeapWathcher { ClockT::time_point deadline_; template - void logDebug(Args &&...args); + void logDebug(Args&&... args); }; } // namespace reindexer diff --git a/cpp_src/tools/terminalutils.cc b/cpp_src/tools/terminalutils.cc index fa578a9b8..468836eb7 100644 --- a/cpp_src/tools/terminalutils.cc +++ b/cpp_src/tools/terminalutils.cc @@ -55,7 +55,9 @@ TerminalSize getTerminalSize() { const int fds[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; for (const int fd : fds) { err = getTerminalSize(fd, size.width, size.height); - if (err.ok()) break; + if (err.ok()) { + break; + } } #endif if (!err.ok()) { diff --git a/cpp_src/tools/varint.h b/cpp_src/tools/varint.h index 3ad36927d..1fbddd201 100644 --- a/cpp_src/tools/varint.h +++ b/cpp_src/tools/varint.h @@ -46,7 +46,7 @@ RX_ALWAYS_INLINE uint64_t zigzag64(int64_t v) noexcept { return (v < 0) ? (((-(u * \return * Number of bytes written to `out`. */ -inline size_t uint32_pack(uint32_t value, uint8_t *out) noexcept { +inline size_t uint32_pack(uint32_t value, uint8_t* out) noexcept { unsigned rv = 0; if (value >= 0x80) { @@ -81,7 +81,7 @@ inline size_t uint32_pack(uint32_t value, uint8_t *out) noexcept { * \return * Number of bytes written to `out`. */ -inline size_t int32_pack(int32_t value, uint8_t *out) noexcept { +inline size_t int32_pack(int32_t value, uint8_t* out) noexcept { if (value < 0) { out[0] = value | 0x80; out[1] = (value >> 7) | 0x80; @@ -107,7 +107,7 @@ inline size_t int32_pack(int32_t value, uint8_t *out) noexcept { * \return * Number of bytes written to `out`. */ -inline size_t sint32_pack(int32_t value, uint8_t *out) noexcept { return uint32_pack(zigzag32(value), out); } +inline size_t sint32_pack(int32_t value, uint8_t* out) noexcept { return uint32_pack(zigzag32(value), out); } /** * Pack a 64-bit unsigned integer using base-128 varint encoding and return the @@ -120,12 +120,14 @@ inline size_t sint32_pack(int32_t value, uint8_t *out) noexcept { return uint32_ * \return * Number of bytes written to `out`. */ -inline size_t uint64_pack(uint64_t value, uint8_t *out) noexcept { +inline size_t uint64_pack(uint64_t value, uint8_t* out) noexcept { uint32_t hi = (uint32_t)(value >> 32); uint32_t lo = (uint32_t)value; unsigned rv; - if (hi == 0) return uint32_pack((uint32_t)lo, out); + if (hi == 0) { + return uint32_pack((uint32_t)lo, out); + } out[0] = (lo) | 0x80; out[1] = (lo >> 7) | 0x80; out[2] = (lo >> 14) | 0x80; @@ -157,14 +159,14 @@ inline size_t uint64_pack(uint64_t value, uint8_t *out) noexcept { * \return * Number of bytes written to `out`. */ -inline size_t sint64_pack(int64_t value, uint8_t *out) noexcept { return uint64_pack(zigzag64(value), out); } +inline size_t sint64_pack(int64_t value, uint8_t* out) noexcept { return uint64_pack(zigzag64(value), out); } -inline size_t boolean_pack(bool value, uint8_t *out) noexcept { +inline size_t boolean_pack(bool value, uint8_t* out) noexcept { *out = value ? 1 : 0; return 1; } -inline size_t string_pack(const char *str, uint8_t *out) noexcept { +inline size_t string_pack(const char* str, uint8_t* out) noexcept { if (str == nullptr) { out[0] = 0; return 1; @@ -176,7 +178,7 @@ inline size_t string_pack(const char *str, uint8_t *out) noexcept { } } -inline size_t string_pack(const char *str, const size_t len, uint8_t *out) noexcept { +inline size_t string_pack(const char* str, const size_t len, uint8_t* out) noexcept { if (str == nullptr) { out[0] = 0; return 1; @@ -187,7 +189,7 @@ inline size_t string_pack(const char *str, const size_t len, uint8_t *out) noexc } } -inline uint32_t parse_uint32(unsigned len, const uint8_t *data) noexcept { +inline uint32_t parse_uint32(unsigned len, const uint8_t* data) noexcept { uint32_t rv = data[0] & 0x7f; if (len > 1) { rv |= ((uint32_t)(data[1] & 0x7f) << 7); @@ -195,28 +197,32 @@ inline uint32_t parse_uint32(unsigned len, const uint8_t *data) noexcept { rv |= ((uint32_t)(data[2] & 0x7f) << 14); if (len > 3) { rv |= ((uint32_t)(data[3] & 0x7f) << 21); - if (len > 4) rv |= ((uint32_t)(data[4]) << 28); + if (len > 4) { + rv |= ((uint32_t)(data[4]) << 28); + } } } } return rv; } -inline uint32_t parse_int32(unsigned len, const uint8_t *data) noexcept { return parse_uint32(len, data); } +inline uint32_t parse_int32(unsigned len, const uint8_t* data) noexcept { return parse_uint32(len, data); } RX_ALWAYS_INLINE int32_t unzigzag32(uint32_t v) noexcept { return (v & 1) ? (-(v >> 1) - 1) : (v >> 1); } -inline uint32_t parse_fixed_uint32(const uint8_t *data) noexcept { +inline uint32_t parse_fixed_uint32(const uint8_t* data) noexcept { uint32_t t; memcpy(&t, data, 4); return t; } -inline uint64_t parse_uint64(unsigned len, const uint8_t *data) noexcept { +inline uint64_t parse_uint64(unsigned len, const uint8_t* data) noexcept { unsigned shift, i; uint64_t rv; - if (len < 5) return parse_uint32(len, data); + if (len < 5) { + return parse_uint32(len, data); + } rv = ((uint64_t)(data[0] & 0x7f)) | ((uint64_t)(data[1] & 0x7f) << 7) | ((uint64_t)(data[2] & 0x7f) << 14) | ((uint64_t)(data[3] & 0x7f) << 21); shift = 28; @@ -229,18 +235,25 @@ inline uint64_t parse_uint64(unsigned len, const uint8_t *data) noexcept { RX_ALWAYS_INLINE int64_t unzigzag64(uint64_t v) noexcept { return (v & 1) ? (-(v >> 1) - 1) : (v >> 1); } -inline uint64_t parse_fixed_uint64(const uint8_t *data) noexcept { +inline uint64_t parse_fixed_uint64(const uint8_t* data) noexcept { uint64_t t; memcpy(&t, data, 8); return t; } -inline unsigned scan_varint(unsigned len, const uint8_t *data) noexcept { +inline unsigned scan_varint(unsigned len, const uint8_t* data) noexcept { unsigned i; - if (len > 10) len = 10; - for (i = 0; i < len; i++) - if ((data[i] & 0x80) == 0) break; - if (i == len) return 0; + if (len > 10) { + len = 10; + } + for (i = 0; i < len; i++) { + if ((data[i] & 0x80) == 0) { + break; + } + } + if (i == len) { + return 0; + } return i + 1; } diff --git a/cpp_src/vendor/fmt/args.h b/cpp_src/vendor/fmt/args.h new file mode 100644 index 000000000..31a60e8fa --- /dev/null +++ b/cpp_src/vendor/fmt/args.h @@ -0,0 +1,228 @@ +// Formatting library for C++ - dynamic argument lists +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_ARGS_H_ +#define FMT_ARGS_H_ + +#ifndef FMT_MODULE +# include // std::reference_wrapper +# include // std::unique_ptr +# include +#endif + +#include "format.h" // std_string_view + +FMT_BEGIN_NAMESPACE + +namespace detail { + +template struct is_reference_wrapper : std::false_type {}; +template +struct is_reference_wrapper> : std::true_type {}; + +template auto unwrap(const T& v) -> const T& { return v; } +template +auto unwrap(const std::reference_wrapper& v) -> const T& { + return static_cast(v); +} + +// node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC +// 2022 (v17.10.0). +// +// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for +// templates it doesn't complain about inability to deduce single translation +// unit for placing vtable. So node is made a fake template. +template struct node { + virtual ~node() = default; + std::unique_ptr> next; +}; + +class dynamic_arg_list { + template struct typed_node : node<> { + T value; + + template + FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} + + template + FMT_CONSTEXPR typed_node(const basic_string_view& arg) + : value(arg.data(), arg.size()) {} + }; + + std::unique_ptr> head_; + + public: + template auto push(const Arg& arg) -> const T& { + auto new_node = std::unique_ptr>(new typed_node(arg)); + auto& value = new_node->value; + new_node->next = std::move(head_); + head_ = std::move(new_node); + return value; + } +}; +} // namespace detail + +/** + * A dynamic list of formatting arguments with storage. + * + * It can be implicitly converted into `fmt::basic_format_args` for passing + * into type-erased formatting functions such as `fmt::vformat`. + */ +template +class dynamic_format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif +{ + private: + using char_type = typename Context::char_type; + + template struct need_copy { + static constexpr detail::type mapped_type = + detail::mapped_type_constant::value; + + enum { + value = !(detail::is_reference_wrapper::value || + std::is_same>::value || + std::is_same>::value || + (mapped_type != detail::type::cstring_type && + mapped_type != detail::type::string_type && + mapped_type != detail::type::custom_type)) + }; + }; + + template + using stored_type = conditional_t< + std::is_convertible>::value && + !detail::is_reference_wrapper::value, + std::basic_string, T>; + + // Storage of basic_format_arg must be contiguous. + std::vector> data_; + std::vector> named_info_; + + // Storage of arguments not fitting into basic_format_arg must grow + // without relocation because items in data_ refer to it. + detail::dynamic_arg_list dynamic_args_; + + friend class basic_format_args; + + auto get_types() const -> unsigned long long { + return detail::is_unpacked_bit | data_.size() | + (named_info_.empty() + ? 0ULL + : static_cast(detail::has_named_args_bit)); + } + + auto data() const -> const basic_format_arg* { + return named_info_.empty() ? data_.data() : data_.data() + 1; + } + + template void emplace_arg(const T& arg) { + data_.emplace_back(detail::make_arg(arg)); + } + + template + void emplace_arg(const detail::named_arg& arg) { + if (named_info_.empty()) { + constexpr const detail::named_arg_info* zero_ptr{nullptr}; + data_.insert(data_.begin(), {zero_ptr, 0}); + } + data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); + auto pop_one = [](std::vector>* data) { + data->pop_back(); + }; + std::unique_ptr>, decltype(pop_one)> + guard{&data_, pop_one}; + named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); + data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; + guard.release(); + } + + public: + constexpr dynamic_format_arg_store() = default; + + /** + * Adds an argument into the dynamic store for later passing to a formatting + * function. + * + * Note that custom types and string types (but not string views) are copied + * into the store dynamically allocating memory if necessary. + * + * **Example**: + * + * fmt::dynamic_format_arg_store store; + * store.push_back(42); + * store.push_back("abc"); + * store.push_back(1.5f); + * std::string result = fmt::vformat("{} and {} and {}", store); + */ + template void push_back(const T& arg) { + if (detail::const_check(need_copy::value)) + emplace_arg(dynamic_args_.push>(arg)); + else + emplace_arg(detail::unwrap(arg)); + } + + /** + * Adds a reference to the argument into the dynamic store for later passing + * to a formatting function. + * + * **Example**: + * + * fmt::dynamic_format_arg_store store; + * char band[] = "Rolling Stones"; + * store.push_back(std::cref(band)); + * band[9] = 'c'; // Changing str affects the output. + * std::string result = fmt::vformat("{}", store); + * // result == "Rolling Scones" + */ + template void push_back(std::reference_wrapper arg) { + static_assert( + need_copy::value, + "objects of built-in types and string views are always copied"); + emplace_arg(arg.get()); + } + + /** + * Adds named argument into the dynamic store for later passing to a + * formatting function. `std::reference_wrapper` is supported to avoid + * copying of the argument. The name is always copied into the store. + */ + template + void push_back(const detail::named_arg& arg) { + const char_type* arg_name = + dynamic_args_.push>(arg.name).c_str(); + if (detail::const_check(need_copy::value)) { + emplace_arg( + fmt::arg(arg_name, dynamic_args_.push>(arg.value))); + } else { + emplace_arg(fmt::arg(arg_name, arg.value)); + } + } + + /// Erase all elements from the store. + void clear() { + data_.clear(); + named_info_.clear(); + dynamic_args_ = detail::dynamic_arg_list(); + } + + /// Reserves space to store at least `new_cap` arguments including + /// `new_cap_named` named arguments. + void reserve(size_t new_cap, size_t new_cap_named) { + FMT_ASSERT(new_cap >= new_cap_named, + "Set of arguments includes set of named arguments"); + data_.reserve(new_cap); + named_info_.reserve(new_cap_named); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_ARGS_H_ diff --git a/cpp_src/vendor/fmt/base.h b/cpp_src/vendor/fmt/base.h new file mode 100644 index 000000000..5b6567acd --- /dev/null +++ b/cpp_src/vendor/fmt/base.h @@ -0,0 +1,3077 @@ +// Formatting library for C++ - the base API for char/UTF-8 +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_BASE_H_ +#define FMT_BASE_H_ + +#if defined(FMT_IMPORT_STD) && !defined(FMT_MODULE) +# define FMT_MODULE +#endif + +#ifndef FMT_MODULE +# include // CHAR_BIT +# include // FILE +# include // strlen + +// is also included transitively from . +# include // std::byte +# include // std::enable_if +#endif + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 110002 + +// Detect compiler versions. +#if defined(__clang__) && !defined(__ibmxl__) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif +#if defined(__ICL) +# define FMT_ICC_VERSION __ICL +#elif defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif +#if defined(_MSC_VER) +# define FMT_MSC_VERSION _MSC_VER +#else +# define FMT_MSC_VERSION 0 +#endif + +// Detect standard library versions. +#ifdef _GLIBCXX_RELEASE +# define FMT_GLIBCXX_RELEASE _GLIBCXX_RELEASE +#else +# define FMT_GLIBCXX_RELEASE 0 +#endif +#ifdef _LIBCPP_VERSION +# define FMT_LIBCPP_VERSION _LIBCPP_VERSION +#else +# define FMT_LIBCPP_VERSION 0 +#endif + +#ifdef _MSVC_LANG +# define FMT_CPLUSPLUS _MSVC_LANG +#else +# define FMT_CPLUSPLUS __cplusplus +#endif + +// Detect __has_*. +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif +#ifdef __has_include +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Detect C++14 relaxed constexpr. +#ifdef FMT_USE_CONSTEXPR +// Use the provided definition. +#elif FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L +// GCC only allows throw in constexpr since version 6: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67371. +# define FMT_USE_CONSTEXPR 1 +#elif FMT_ICC_VERSION +# define FMT_USE_CONSTEXPR 0 // https://github.com/fmtlib/fmt/issues/1628 +#elif FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 +# define FMT_USE_CONSTEXPR 1 +#else +# define FMT_USE_CONSTEXPR 0 +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +#else +# define FMT_CONSTEXPR +#endif + +// Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated. +#if !defined(__cpp_lib_is_constant_evaluated) +# define FMT_USE_CONSTEVAL 0 +#elif FMT_CPLUSPLUS < 201709L +# define FMT_USE_CONSTEVAL 0 +#elif FMT_GLIBCXX_RELEASE && FMT_GLIBCXX_RELEASE < 10 +# define FMT_USE_CONSTEVAL 0 +#elif FMT_LIBCPP_VERSION && FMT_LIBCPP_VERSION < 10000 +# define FMT_USE_CONSTEVAL 0 +#elif defined(__apple_build_version__) && __apple_build_version__ < 14000029L +# define FMT_USE_CONSTEVAL 0 // consteval is broken in Apple clang < 14. +#elif FMT_MSC_VERSION && FMT_MSC_VERSION < 1929 +# define FMT_USE_CONSTEVAL 0 // consteval is broken in MSVC VS2019 < 16.10. +#elif defined(__cpp_consteval) +# define FMT_USE_CONSTEVAL 1 +#elif FMT_GCC_VERSION >= 1002 || FMT_CLANG_VERSION >= 1101 +# define FMT_USE_CONSTEVAL 1 +#else +# define FMT_USE_CONSTEVAL 0 +#endif +#if FMT_USE_CONSTEVAL +# define FMT_CONSTEVAL consteval +# define FMT_CONSTEXPR20 constexpr +#else +# define FMT_CONSTEVAL +# define FMT_CONSTEXPR20 +#endif + +#if defined(FMT_USE_NONTYPE_TEMPLATE_ARGS) +// Use the provided definition. +#elif defined(__NVCOMPILER) +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#elif FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif defined(__cpp_nontype_template_args) && \ + __cpp_nontype_template_args >= 201911L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#elif FMT_CLANG_VERSION >= 1200 && FMT_CPLUSPLUS >= 202002L +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 +#else +# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 +#endif + +#ifdef FMT_USE_CONCEPTS +// Use the provided definition. +#elif defined(__cpp_concepts) +# define FMT_USE_CONCEPTS 1 +#else +# define FMT_USE_CONCEPTS 0 +#endif + +// Check if exceptions are disabled. +#ifdef FMT_EXCEPTIONS +// Use the provided definition. +#elif defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +#elif FMT_MSC_VERSION && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#else +# define FMT_EXCEPTIONS 1 +#endif +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) +# define FMT_FALLTHROUGH [[fallthrough]] +#elif defined(__clang__) +# define FMT_FALLTHROUGH [[clang::fallthrough]] +#elif FMT_GCC_VERSION >= 700 && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) +# define FMT_FALLTHROUGH [[gnu::fallthrough]] +#else +# define FMT_FALLTHROUGH +#endif + +// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. +#if FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && !defined(__NVCC__) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifndef FMT_NODISCARD +# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) +# define FMT_NODISCARD [[nodiscard]] +# else +# define FMT_NODISCARD +# endif +#endif + +#ifdef FMT_DEPRECATED +// Use the provided definition. +#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated) +# define FMT_DEPRECATED [[deprecated]] +#else +# define FMT_DEPRECATED /* deprecated */ +#endif + +#ifdef FMT_INLINE +// Use the provided definition. +#elif FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_ALWAYS_INLINE inline __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE inline +#endif +// A version of FMT_INLINE to prevent code bloat in debug mode. +#ifdef NDEBUG +# define FMT_INLINE FMT_ALWAYS_INLINE +#else +# define FMT_INLINE inline +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_VISIBILITY(value) __attribute__((visibility(value))) +#else +# define FMT_VISIBILITY(value) +#endif + +#ifndef FMT_GCC_PRAGMA +// Workaround a _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884 +// and an nvhpc warning: https://github.com/fmtlib/fmt/pull/2582. +# if FMT_GCC_VERSION >= 504 && !defined(__NVCOMPILER) +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +# else +# define FMT_GCC_PRAGMA(arg) +# endif +#endif + +// GCC < 5 requires this-> in decltype. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +# define FMT_DECLTYPE_THIS this-> +#else +# define FMT_DECLTYPE_THIS +#endif + +#if FMT_MSC_VERSION +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +# define FMT_UNCHECKED_ITERATOR(It) \ + using _Unchecked_type = It // Mark iterator as checked. +#else +# define FMT_MSC_WARNING(...) +# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + inline namespace v11 { +# define FMT_END_NAMESPACE \ + } \ + } +#endif + +#ifndef FMT_EXPORT +# define FMT_EXPORT +# define FMT_BEGIN_EXPORT +# define FMT_END_EXPORT +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# if defined(FMT_LIB_EXPORT) +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#elif defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_API FMT_VISIBILITY("default") +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE !FMT_MSC_VERSION +#endif + +// Check if rtti is available. +#ifndef FMT_USE_RTTI +// __RTTI is for EDG compilers. _CPPRTTI is for MSVC. +# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \ + defined(__INTEL_RTTI__) || defined(__RTTI) +# define FMT_USE_RTTI 1 +# else +# define FMT_USE_RTTI 0 +# endif +#endif + +#define FMT_FWD(...) static_cast(__VA_ARGS__) + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#if !defined(__OPTIMIZE__) && !defined(__CUDACC__) +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE + +// Implementations of enable_if_t and other metafunctions for older systems. +template +using enable_if_t = typename std::enable_if::type; +template +using conditional_t = typename std::conditional::type; +template using bool_constant = std::integral_constant; +template +using remove_reference_t = typename std::remove_reference::type; +template +using remove_const_t = typename std::remove_const::type; +template +using remove_cvref_t = typename std::remove_cv>::type; +template struct type_identity { + using type = T; +}; +template using type_identity_t = typename type_identity::type; +template +using make_unsigned_t = typename std::make_unsigned::type; +template +using underlying_t = typename std::underlying_type::type; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 +// A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { + using type = void; +}; +template using void_t = typename void_t_impl::type; +#else +template using void_t = void; +#endif + +struct monostate { + constexpr monostate() {} +}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 +#endif + +// This is defined in base.h instead of format.h to avoid injecting in std. +// It is a template to avoid undesirable implicit conversions to std::byte. +#ifdef __cpp_lib_byte +template ::value)> +inline auto format_as(T b) -> unsigned char { + return static_cast(b); +} +#endif + +namespace detail { +// Suppresses "unused variable" warnings with the method described in +// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. +// (void)var does not work on many Intel compilers. +template FMT_CONSTEXPR void ignore_unused(const T&...) {} + +constexpr auto is_constant_evaluated(bool default_value = false) noexcept + -> bool { +// Workaround for incompatibility between libstdc++ consteval-based +// std::is_constant_evaluated() implementation and clang-14: +// https://github.com/fmtlib/fmt/issues/3247. +#if FMT_CPLUSPLUS >= 202002L && FMT_GLIBCXX_RELEASE >= 12 && \ + (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) + ignore_unused(default_value); + return __builtin_is_constant_evaluated(); +#elif defined(__cpp_lib_is_constant_evaluated) + ignore_unused(default_value); + return std::is_constant_evaluated(); +#else + return default_value; +#endif +} + +// Suppresses "conditional expression is constant" warnings. +template constexpr auto const_check(T value) -> T { return value; } + +FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#if defined(FMT_ASSERT) +// Use the provided definition. +#elif defined(NDEBUG) +// FMT_ASSERT is not empty to avoid -Wempty-body. +# define FMT_ASSERT(condition, message) \ + fmt::detail::ignore_unused((condition), (message)) +#else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +#endif + +#ifdef FMT_USE_INT128 +// Do nothing. +#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ + !(FMT_CLANG_VERSION && FMT_MSC_VERSION) +# define FMT_USE_INT128 1 +using int128_opt = __int128_t; // An optional native 128-bit integer. +using uint128_opt = __uint128_t; +template inline auto convert_for_visit(T value) -> T { + return value; +} +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 +enum class int128_opt {}; +enum class uint128_opt {}; +// Reduce template instantiations. +template auto convert_for_visit(T) -> monostate { return {}; } +#endif + +// Casts a nonnegative integer to unsigned. +template +FMT_CONSTEXPR auto to_unsigned(Int value) -> make_unsigned_t { + FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); + return static_cast>(value); +} + +// A heuristic to detect std::string and std::[experimental::]string_view. +// It is mainly used to avoid dependency on <[experimental/]string_view>. +template +struct is_std_string_like : std::false_type {}; +template +struct is_std_string_like().find_first_of( + typename T::value_type(), 0))>> + : std::is_convertible().data()), + const typename T::value_type*> {}; + +// Returns true iff the literal encoding is UTF-8. +constexpr auto is_utf8_enabled() -> bool { + // Avoid an MSVC sign extension bug: https://github.com/fmtlib/fmt/pull/2297. + using uchar = unsigned char; + return sizeof("\u00A7") == 3 && uchar("\u00A7"[0]) == 0xC2 && + uchar("\u00A7"[1]) == 0xA7; +} +constexpr auto use_utf8() -> bool { + return !FMT_MSC_VERSION || is_utf8_enabled(); +} + +static_assert(!FMT_UNICODE || use_utf8(), + "Unicode support requires compiling with /utf-8"); + +template FMT_CONSTEXPR auto length(const Char* s) -> size_t { + size_t len = 0; + while (*s++) ++len; + return len; +} + +template +FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n) + -> int { + if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n); + for (; n != 0; ++s1, ++s2, --n) { + if (*s1 < *s2) return -1; + if (*s1 > *s2) return 1; + } + return 0; +} + +namespace adl { +using namespace std; + +template +auto invoke_back_inserter() + -> decltype(back_inserter(std::declval())); +} // namespace adl + +template +struct is_back_insert_iterator : std::false_type {}; + +template +struct is_back_insert_iterator< + It, bool_constant()), + It>::value>> : std::true_type {}; + +// Extracts a reference to the container from *insert_iterator. +template +inline auto get_container(OutputIt it) -> typename OutputIt::container_type& { + struct accessor : OutputIt { + accessor(OutputIt base) : OutputIt(base) {} + using OutputIt::container; + }; + return *accessor(it).container; +} +} // namespace detail + +// Checks whether T is a container with contiguous storage. +template struct is_contiguous : std::false_type {}; + +/** + * An implementation of `std::basic_string_view` for pre-C++17. It provides a + * subset of the API. `fmt::basic_string_view` is used for format strings even + * if `std::basic_string_view` is available to prevent issues when a library is + * compiled with a different `-std` option than the client code (which is not + * recommended). + */ +FMT_EXPORT +template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {} + + /// Constructs a string reference object from a C string and a size. + constexpr basic_string_view(const Char* s, size_t count) noexcept + : data_(s), size_(count) {} + + constexpr basic_string_view(std::nullptr_t) = delete; + + /// Constructs a string reference object from a C string. + FMT_CONSTEXPR20 + basic_string_view(const Char* s) + : data_(s), + size_(detail::const_check(std::is_same::value && + !detail::is_constant_evaluated(false)) + ? strlen(reinterpret_cast(s)) + : detail::length(s)) {} + + /// Constructs a string reference from a `std::basic_string` or a + /// `std::basic_string_view` object. + template ::value&& std::is_same< + typename S::value_type, Char>::value)> + FMT_CONSTEXPR basic_string_view(const S& s) noexcept + : data_(s.data()), size_(s.size()) {} + + /// Returns a pointer to the string data. + constexpr auto data() const noexcept -> const Char* { return data_; } + + /// Returns the string size. + constexpr auto size() const noexcept -> size_t { return size_; } + + constexpr auto begin() const noexcept -> iterator { return data_; } + constexpr auto end() const noexcept -> iterator { return data_ + size_; } + + constexpr auto operator[](size_t pos) const noexcept -> const Char& { + return data_[pos]; + } + + FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { + data_ += n; + size_ -= n; + } + + FMT_CONSTEXPR auto starts_with(basic_string_view sv) const noexcept + -> bool { + return size_ >= sv.size_ && detail::compare(data_, sv.data_, sv.size_) == 0; + } + FMT_CONSTEXPR auto starts_with(Char c) const noexcept -> bool { + return size_ >= 1 && *data_ == c; + } + FMT_CONSTEXPR auto starts_with(const Char* s) const -> bool { + return starts_with(basic_string_view(s)); + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR auto compare(basic_string_view other) const -> int { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = detail::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR friend auto operator==(basic_string_view lhs, + basic_string_view rhs) -> bool { + return lhs.compare(rhs) == 0; + } + friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) != 0; + } + friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) < 0; + } + friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) <= 0; + } + friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) > 0; + } + friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { + return lhs.compare(rhs) >= 0; + } +}; + +FMT_EXPORT +using string_view = basic_string_view; + +/// Specifies if `T` is a character type. Can be specialized by users. +FMT_EXPORT +template struct is_char : std::false_type {}; +template <> struct is_char : std::true_type {}; + +namespace detail { + +// Constructs fmt::basic_string_view from types implicitly convertible +// to it, deducing Char. Explicitly convertible types such as the ones returned +// from FMT_STRING are intentionally excluded. +template ::value)> +constexpr auto to_string_view(const Char* s) -> basic_string_view { + return s; +} +template ::value)> +constexpr auto to_string_view(const T& s) + -> basic_string_view { + return s; +} +template +constexpr auto to_string_view(basic_string_view s) + -> basic_string_view { + return s; +} + +template +struct has_to_string_view : std::false_type {}; +// detail:: is intentional since to_string_view is not an extension point. +template +struct has_to_string_view< + T, void_t()))>> + : std::true_type {}; + +template struct string_literal { + static constexpr Char value[sizeof...(C)] = {C...}; + constexpr operator basic_string_view() const { + return {value, sizeof...(C)}; + } +}; +#if FMT_CPLUSPLUS < 201703L +template +constexpr Char string_literal::value[sizeof...(C)]; +#endif + +enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type +}; + +// Maps core type T to the corresponding type enum constant. +template +struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + +FMT_TYPE_CONSTANT(int, int_type); +FMT_TYPE_CONSTANT(unsigned, uint_type); +FMT_TYPE_CONSTANT(long long, long_long_type); +FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); +FMT_TYPE_CONSTANT(int128_opt, int128_type); +FMT_TYPE_CONSTANT(uint128_opt, uint128_type); +FMT_TYPE_CONSTANT(bool, bool_type); +FMT_TYPE_CONSTANT(Char, char_type); +FMT_TYPE_CONSTANT(float, float_type); +FMT_TYPE_CONSTANT(double, double_type); +FMT_TYPE_CONSTANT(long double, long_double_type); +FMT_TYPE_CONSTANT(const Char*, cstring_type); +FMT_TYPE_CONSTANT(basic_string_view, string_type); +FMT_TYPE_CONSTANT(const void*, pointer_type); + +constexpr auto is_integral_type(type t) -> bool { + return t > type::none_type && t <= type::last_integer_type; +} +constexpr auto is_arithmetic_type(type t) -> bool { + return t > type::none_type && t <= type::last_numeric_type; +} + +constexpr auto set(type rhs) -> int { return 1 << static_cast(rhs); } +constexpr auto in(type t, int set) -> bool { + return ((set >> static_cast(t)) & 1) != 0; +} + +// Bitsets of types. +enum { + sint_set = + set(type::int_type) | set(type::long_long_type) | set(type::int128_type), + uint_set = set(type::uint_type) | set(type::ulong_long_type) | + set(type::uint128_type), + bool_set = set(type::bool_type), + char_set = set(type::char_type), + float_set = set(type::float_type) | set(type::double_type) | + set(type::long_double_type), + string_set = set(type::string_type), + cstring_set = set(type::cstring_type), + pointer_set = set(type::pointer_type) +}; +} // namespace detail + +/// Reports a format error at compile time or, via a `format_error` exception, +/// at runtime. +// This function is intentionally not constexpr to give a compile-time error. +FMT_NORETURN FMT_API void report_error(const char* message); + +FMT_DEPRECATED FMT_NORETURN inline void throw_format_error( + const char* message) { + report_error(message); +} + +/// String's character (code unit) type. +template ()))> +using char_t = typename V::value_type; + +/** + * Parsing context consisting of a format string range being parsed and an + * argument counter for automatic indexing. + * You can use the `format_parse_context` type alias for `char` instead. + */ +FMT_EXPORT +template class basic_format_parse_context { + private: + basic_string_view format_str_; + int next_arg_id_; + + FMT_CONSTEXPR void do_check_arg_id(int id); + + public: + using char_type = Char; + using iterator = const Char*; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, int next_arg_id = 0) + : format_str_(format_str), next_arg_id_(next_arg_id) {} + + /// Returns an iterator to the beginning of the format string range being + /// parsed. + constexpr auto begin() const noexcept -> iterator { + return format_str_.begin(); + } + + /// Returns an iterator past the end of the format string range being parsed. + constexpr auto end() const noexcept -> iterator { return format_str_.end(); } + + /// Advances the begin iterator to `it`. + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /// Reports an error if using the manual argument indexing; otherwise returns + /// the next argument index and switches to the automatic indexing. + FMT_CONSTEXPR auto next_arg_id() -> int { + if (next_arg_id_ < 0) { + report_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + int id = next_arg_id_++; + do_check_arg_id(id); + return id; + } + + /// Reports an error if using the automatic argument indexing; otherwise + /// switches to the manual indexing. + FMT_CONSTEXPR void check_arg_id(int id) { + if (next_arg_id_ > 0) { + report_error("cannot switch from automatic to manual argument indexing"); + return; + } + next_arg_id_ = -1; + do_check_arg_id(id); + } + FMT_CONSTEXPR void check_arg_id(basic_string_view) { + next_arg_id_ = -1; + } + FMT_CONSTEXPR void check_dynamic_spec(int arg_id); +}; + +FMT_EXPORT +using format_parse_context = basic_format_parse_context; + +namespace detail { +// A parse context with extra data used only in compile-time checks. +template +class compile_parse_context : public basic_format_parse_context { + private: + int num_args_; + const type* types_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args, const type* types, + int next_arg_id = 0) + : base(format_str, next_arg_id), num_args_(num_args), types_(types) {} + + constexpr auto num_args() const -> int { return num_args_; } + constexpr auto arg_type(int id) const -> type { return types_[id]; } + + FMT_CONSTEXPR auto next_arg_id() -> int { + int id = base::next_arg_id(); + if (id >= num_args_) report_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) report_error("argument not found"); + } + using base::check_arg_id; + + FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { + detail::ignore_unused(arg_id); + if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) + report_error("width/precision is not integer"); + } +}; + +/// A contiguous memory buffer with an optional growing ability. It is an +/// internal class and shouldn't be used directly, only via `memory_buffer`. +template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + using grow_fun = void (*)(buffer& buf, size_t capacity); + grow_fun grow_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + FMT_CONSTEXPR20 buffer(grow_fun grow, size_t sz) noexcept + : size_(sz), capacity_(sz), grow_(grow) {} + + constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0, + size_t cap = 0) noexcept + : ptr_(p), size_(sz), capacity_(cap), grow_(grow) {} + + FMT_CONSTEXPR20 ~buffer() = default; + buffer(buffer&&) = default; + + /// Sets the buffer data and capacity. + FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + auto begin() noexcept -> T* { return ptr_; } + auto end() noexcept -> T* { return ptr_ + size_; } + + auto begin() const noexcept -> const T* { return ptr_; } + auto end() const noexcept -> const T* { return ptr_ + size_; } + + /// Returns the size of this buffer. + constexpr auto size() const noexcept -> size_t { return size_; } + + /// Returns the capacity of this buffer. + constexpr auto capacity() const noexcept -> size_t { return capacity_; } + + /// Returns a pointer to the buffer data (not null-terminated). + FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } + FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } + + /// Clears this buffer. + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain `count` elements. If T is a POD type + // the new elements may not be initialized. + FMT_CONSTEXPR void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to `new_capacity`. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + FMT_CONSTEXPR void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow_(*this, new_capacity); + } + + FMT_CONSTEXPR void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /// Appends data to the end of the buffer. + template void append(const U* begin, const U* end) { + while (begin != end) { + auto count = to_unsigned(end - begin); + try_reserve(size_ + count); + auto free_cap = capacity_ - size_; + if (free_cap < count) count = free_cap; + // A loop is faster than memcpy on small sizes. + T* out = ptr_ + size_; + for (size_t i = 0; i < count; ++i) out[i] = begin[i]; + size_ += count; + begin += count; + } + } + + template FMT_CONSTEXPR auto operator[](Idx index) -> T& { + return ptr_[index]; + } + template + FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { + return ptr_[index]; + } +}; + +struct buffer_traits { + explicit buffer_traits(size_t) {} + auto count() const -> size_t { return 0; } + auto limit(size_t size) -> size_t { return size; } +}; + +class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + auto count() const -> size_t { return count_; } + auto limit(size_t size) -> size_t { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } +}; + +// A buffer that writes to an output iterator when flushed. +template +class iterator_buffer : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buffer_size) static_cast(buf).flush(); + } + + void flush() { + auto size = this->size(); + this->clear(); + const T* begin = data_; + const T* end = begin + this->limit(size); + while (begin != end) *out_++ = *begin++; + } + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(grow, data_, 0, buffer_size), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : Traits(other), + buffer(grow, data_, 0, buffer_size), + out_(other.out_) {} + ~iterator_buffer() { + // Don't crash if flush fails during unwinding. + FMT_TRY { flush(); } + FMT_CATCH(...) {} + } + + auto out() -> OutputIt { + flush(); + return out_; + } + auto count() const -> size_t { return Traits::count() + this->size(); } +}; + +template +class iterator_buffer : public fixed_buffer_traits, + public buffer { + private: + T* out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() == buf.capacity()) + static_cast(buf).flush(); + } + + void flush() { + size_t n = this->limit(this->size()); + if (this->data() == out_) { + out_ += n; + this->set(data_, buffer_size); + } + this->clear(); + } + + public: + explicit iterator_buffer(T* out, size_t n = buffer_size) + : fixed_buffer_traits(n), buffer(grow, out, 0, n), out_(out) {} + iterator_buffer(iterator_buffer&& other) noexcept + : fixed_buffer_traits(other), + buffer(static_cast(other)), + out_(other.out_) { + if (this->data() != out_) { + this->set(data_, buffer_size); + this->clear(); + } + } + ~iterator_buffer() { flush(); } + + auto out() -> T* { + flush(); + return out_; + } + auto count() const -> size_t { + return fixed_buffer_traits::count() + this->size(); + } +}; + +template class iterator_buffer : public buffer { + public: + explicit iterator_buffer(T* out, size_t = 0) + : buffer([](buffer&, size_t) {}, out, 0, ~size_t()) {} + + auto out() -> T* { return &*this->end(); } +}; + +// A buffer that writes to a container with the contiguous storage. +template +class iterator_buffer< + OutputIt, + enable_if_t::value && + is_contiguous::value, + typename OutputIt::container_type::value_type>> + : public buffer { + private: + using container_type = typename OutputIt::container_type; + using value_type = typename container_type::value_type; + container_type& container_; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t capacity) { + auto& self = static_cast(buf); + self.container_.resize(capacity); + self.set(&self.container_[0], capacity); + } + + public: + explicit iterator_buffer(container_type& c) + : buffer(grow, c.size()), container_(c) {} + explicit iterator_buffer(OutputIt out, size_t = 0) + : iterator_buffer(get_container(out)) {} + + auto out() -> OutputIt { return back_inserter(container_); } +}; + +// A buffer that counts the number of code units written discarding the output. +template class counting_buffer : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + static FMT_CONSTEXPR void grow(buffer& buf, size_t) { + if (buf.size() != buffer_size) return; + static_cast(buf).count_ += buf.size(); + buf.clear(); + } + + public: + counting_buffer() : buffer(grow, data_, 0, buffer_size) {} + + auto count() -> size_t { return count_ + this->size(); } +}; +} // namespace detail + +template +FMT_CONSTEXPR void basic_format_parse_context::do_check_arg_id(int id) { + // Argument id is only checked at compile-time during parsing because + // formatting has its own validation. + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + if (id >= static_cast(this)->num_args()) + report_error("argument not found"); + } +} + +template +FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( + int arg_id) { + if (detail::is_constant_evaluated() && + (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { + using context = detail::compile_parse_context; + static_cast(this)->check_dynamic_spec(arg_id); + } +} + +FMT_EXPORT template class basic_format_arg; +FMT_EXPORT template class basic_format_args; +FMT_EXPORT template class dynamic_format_arg_store; + +// A formatter for objects of type T. +FMT_EXPORT +template +struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; +}; + +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. +template +using has_formatter = + std::is_constructible>; + +// An output iterator that appends to a buffer. It is used instead of +// back_insert_iterator to reduce symbol sizes and avoid dependency. +template class basic_appender { + private: + detail::buffer* buffer_; + + friend auto get_container(basic_appender app) -> detail::buffer& { + return *app.buffer_; + } + + public: + using iterator_category = int; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; + using container_type = detail::buffer; + FMT_UNCHECKED_ITERATOR(basic_appender); + + FMT_CONSTEXPR basic_appender(detail::buffer& buf) : buffer_(&buf) {} + + auto operator=(T c) -> basic_appender& { + buffer_->push_back(c); + return *this; + } + auto operator*() -> basic_appender& { return *this; } + auto operator++() -> basic_appender& { return *this; } + auto operator++(int) -> basic_appender { return *this; } +}; + +using appender = basic_appender; + +namespace detail { +template +struct is_back_insert_iterator> : std::true_type {}; + +template +struct locking : std::true_type {}; +template +struct locking>::nonlocking>> + : std::false_type {}; + +template FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value; +} +template +FMT_CONSTEXPR inline auto is_locking() -> bool { + return locking::value || is_locking(); +} + +// An optimized version of std::copy with the output value type (T). +template ::value)> +auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { + get_container(out).append(begin, end); + return out; +} + +template ::value)> +FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { + while (begin != end) *out++ = static_cast(*begin++); + return out; +} + +template +FMT_CONSTEXPR auto copy(basic_string_view s, OutputIt out) -> OutputIt { + return copy(s.begin(), s.end(), out); +} + +template +constexpr auto has_const_formatter_impl(T*) + -> decltype(typename Context::template formatter_type().format( + std::declval(), std::declval()), + true) { + return true; +} +template +constexpr auto has_const_formatter_impl(...) -> bool { + return false; +} +template +constexpr auto has_const_formatter() -> bool { + return has_const_formatter_impl(static_cast(nullptr)); +} + +template +struct is_buffer_appender : std::false_type {}; +template +struct is_buffer_appender< + It, bool_constant< + is_back_insert_iterator::value && + std::is_base_of, + typename It::container_type>::value>> + : std::true_type {}; + +// Maps an output iterator to a buffer. +template ::value)> +auto get_buffer(OutputIt out) -> iterator_buffer { + return iterator_buffer(out); +} +template ::value)> +auto get_buffer(OutputIt out) -> buffer& { + return get_container(out); +} + +template +auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) { + return buf.out(); +} +template +auto get_iterator(buffer&, OutputIt out) -> OutputIt { + return out; +} + +struct view {}; + +template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} +}; + +template struct named_arg_info { + const Char* name; + int id; +}; + +template struct is_named_arg : std::false_type {}; +template struct is_statically_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +template constexpr auto count() -> size_t { return B ? 1 : 0; } +template constexpr auto count() -> size_t { + return (B1 ? 1 : 0) + count(); +} + +template constexpr auto count_named_args() -> size_t { + return count::value...>(); +} + +template +constexpr auto count_statically_named_args() -> size_t { + return count::value...>(); +} + +struct unformattable {}; +struct unformattable_char : unformattable {}; +struct unformattable_pointer : unformattable {}; + +template struct string_value { + const Char* data; + size_t size; +}; + +template struct named_arg_value { + const named_arg_info* data; + size_t size; +}; + +template struct custom_value { + using parse_context = typename Context::parse_context_type; + void* value; + void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); +}; + +// A formatting argument value. +template class value { + public: + using char_type = typename Context::char_type; + + union { + monostate no_value; + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_opt int128_value; + uint128_opt uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_ALWAYS_INLINE value() : no_value() {} + constexpr FMT_ALWAYS_INLINE value(int val) : int_value(val) {} + constexpr FMT_ALWAYS_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_ALWAYS_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_ALWAYS_INLINE value(unsigned long long val) + : ulong_long_value(val) {} + FMT_ALWAYS_INLINE value(int128_opt val) : int128_value(val) {} + FMT_ALWAYS_INLINE value(uint128_opt val) : uint128_value(val) {} + constexpr FMT_ALWAYS_INLINE value(float val) : float_value(val) {} + constexpr FMT_ALWAYS_INLINE value(double val) : double_value(val) {} + FMT_ALWAYS_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_ALWAYS_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_ALWAYS_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_ALWAYS_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_ALWAYS_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_ALWAYS_INLINE value(const void* val) : pointer(val) {} + FMT_ALWAYS_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_CONSTEXPR20 FMT_ALWAYS_INLINE value(T& val) { + using value_type = remove_const_t; + // T may overload operator& e.g. std::vector::reference in libc++. +#if defined(__cpp_if_constexpr) + if constexpr (std::is_same::value) + custom.value = const_cast(&val); +#endif + if (!is_constant_evaluated()) + custom.value = const_cast(&reinterpret_cast(val)); + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + value_type, typename Context::template formatter_type>; + } + value(unformattable); + value(unformattable_char); + value(unformattable_pointer); + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + auto f = Formatter(); + parse_ctx.advance_to(f.parse(parse_ctx)); + using qualified_type = + conditional_t(), const T, T>; + // format must be const for compatibility with std::format and compilation. + const auto& cf = f; + ctx.advance_to(cf.format(*static_cast(arg), ctx)); + } +}; + +// 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. +enum { long_short = sizeof(long) == sizeof(int) }; +using long_type = conditional_t; +using ulong_type = conditional_t; + +template struct format_as_result { + template ::value || std::is_class::value)> + static auto map(U*) -> remove_cvref_t()))>; + static auto map(...) -> void; + + using type = decltype(map(static_cast(nullptr))); +}; +template using format_as_t = typename format_as_result::type; + +template +struct has_format_as + : bool_constant, void>::value> {}; + +#define FMT_MAP_API FMT_CONSTEXPR FMT_ALWAYS_INLINE + +// Maps formatting arguments to core types. +// arg_mapper reports errors by returning unformattable instead of using +// static_assert because it's used in the is_formattable trait. +template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_MAP_API auto map(signed char val) -> int { return val; } + FMT_MAP_API auto map(unsigned char val) -> unsigned { return val; } + FMT_MAP_API auto map(short val) -> int { return val; } + FMT_MAP_API auto map(unsigned short val) -> unsigned { return val; } + FMT_MAP_API auto map(int val) -> int { return val; } + FMT_MAP_API auto map(unsigned val) -> unsigned { return val; } + FMT_MAP_API auto map(long val) -> long_type { return val; } + FMT_MAP_API auto map(unsigned long val) -> ulong_type { return val; } + FMT_MAP_API auto map(long long val) -> long long { return val; } + FMT_MAP_API auto map(unsigned long long val) -> unsigned long long { + return val; + } + FMT_MAP_API auto map(int128_opt val) -> int128_opt { return val; } + FMT_MAP_API auto map(uint128_opt val) -> uint128_opt { return val; } + FMT_MAP_API auto map(bool val) -> bool { return val; } + + template ::value || + std::is_same::value)> + FMT_MAP_API auto map(T val) -> char_type { + return val; + } + template ::value || +#ifdef __cpp_char8_t + std::is_same::value || +#endif + std::is_same::value || + std::is_same::value) && + !std::is_same::value, + int> = 0> + FMT_MAP_API auto map(T) -> unformattable_char { + return {}; + } + + FMT_MAP_API auto map(float val) -> float { return val; } + FMT_MAP_API auto map(double val) -> double { return val; } + FMT_MAP_API auto map(long double val) -> long double { return val; } + + FMT_MAP_API auto map(char_type* val) -> const char_type* { return val; } + FMT_MAP_API auto map(const char_type* val) -> const char_type* { return val; } + template , + FMT_ENABLE_IF(std::is_same::value && + !std::is_pointer::value)> + FMT_MAP_API auto map(const T& val) -> basic_string_view { + return to_string_view(val); + } + template , + FMT_ENABLE_IF(!std::is_same::value && + !std::is_pointer::value)> + FMT_MAP_API auto map(const T&) -> unformattable_char { + return {}; + } + + FMT_MAP_API auto map(void* val) -> const void* { return val; } + FMT_MAP_API auto map(const void* val) -> const void* { return val; } + FMT_MAP_API auto map(volatile void* val) -> const void* { + return const_cast(val); + } + FMT_MAP_API auto map(const volatile void* val) -> const void* { + return const_cast(val); + } + FMT_MAP_API auto map(std::nullptr_t val) -> const void* { return val; } + + // Use SFINAE instead of a const T* parameter to avoid a conflict with the + // array overload. + template < + typename T, + FMT_ENABLE_IF( + std::is_pointer::value || std::is_member_pointer::value || + std::is_function::type>::value || + (std::is_array::value && + !std::is_convertible::value))> + FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { + return {}; + } + + template ::value)> + FMT_MAP_API auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + // Only map owning types because mapping views can be unsafe. + template , + FMT_ENABLE_IF(std::is_arithmetic::value)> + FMT_MAP_API auto map(const T& val) -> decltype(FMT_DECLTYPE_THIS map(U())) { + return map(format_as(val)); + } + + template > + struct formattable : bool_constant() || + (has_formatter::value && + !std::is_const::value)> {}; + + template ::value)> + FMT_MAP_API auto do_map(T& val) -> T& { + return val; + } + template ::value)> + FMT_MAP_API auto do_map(T&) -> unformattable { + return {}; + } + + // is_fundamental is used to allow formatters for extended FP types. + template , + FMT_ENABLE_IF( + (std::is_class::value || std::is_enum::value || + std::is_union::value || std::is_fundamental::value) && + !has_to_string_view::value && !is_char::value && + !is_named_arg::value && !std::is_integral::value && + !std::is_arithmetic>::value)> + FMT_MAP_API auto map(T& val) -> decltype(FMT_DECLTYPE_THIS do_map(val)) { + return do_map(val); + } + + template ::value)> + FMT_MAP_API auto map(const T& named_arg) + -> decltype(FMT_DECLTYPE_THIS map(named_arg.value)) { + return map(named_arg.value); + } + + auto map(...) -> unformattable { return {}; } +}; + +// A type constant after applying arg_mapper. +template +using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + +enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. +enum { max_packed_args = 62 / packed_arg_bits }; +enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; +enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + +template +struct is_output_iterator : std::false_type {}; + +template <> struct is_output_iterator : std::true_type {}; + +template +struct is_output_iterator< + It, T, void_t()++ = std::declval())>> + : std::true_type {}; + +// A type-erased reference to an std::locale to avoid a heavy include. +class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const noexcept { return locale_ != nullptr; } + + template auto get() const -> Locale; +}; + +template constexpr auto encode_types() -> unsigned long long { + return 0; +} + +template +constexpr auto encode_types() -> unsigned long long { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); +} + +template +constexpr unsigned long long make_descriptor() { + return NUM_ARGS <= max_packed_args ? encode_types() + : is_unpacked_bit | NUM_ARGS; +} + +// This type is intentionally undefined, only used for errors. +template +#if FMT_CLANG_VERSION && FMT_CLANG_VERSION <= 1500 +// https://github.com/fmtlib/fmt/issues/3796 +struct type_is_unformattable_for { +}; +#else +struct type_is_unformattable_for; +#endif + +template +FMT_CONSTEXPR auto make_arg(T& val) -> value { + using arg_type = remove_cvref_t().map(val))>; + + // Use enum instead of constexpr because the latter may generate code. + enum { + formattable_char = !std::is_same::value + }; + static_assert(formattable_char, "Mixing character types is disallowed."); + + // Formatting of arbitrary pointers is disallowed. If you want to format a + // pointer cast it to `void*` or `const void*`. In particular, this forbids + // formatting of `[const] volatile char*` printed as bool by iostreams. + enum { + formattable_pointer = !std::is_same::value + }; + static_assert(formattable_pointer, + "Formatting of non-void pointers is disallowed."); + + enum { formattable = !std::is_same::value }; +#if defined(__cpp_if_constexpr) + if constexpr (!formattable) + type_is_unformattable_for _; +#endif + static_assert( + formattable, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return {arg_mapper().map(val)}; +} + +template +FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg { + auto arg = basic_format_arg(); + arg.type_ = mapped_type_constant::value; + arg.value_ = make_arg(val); + return arg; +} + +template +FMT_CONSTEXPR inline auto make_arg(T& val) -> basic_format_arg { + return make_arg(val); +} + +template +using arg_t = conditional_t, + basic_format_arg>; + +template ::value)> +void init_named_arg(named_arg_info*, int& arg_index, int&, const T&) { + ++arg_index; +} +template ::value)> +void init_named_arg(named_arg_info* named_args, int& arg_index, + int& named_arg_index, const T& arg) { + named_args[named_arg_index++] = {arg.name, arg_index++}; +} + +// An array of references to arguments. It can be implicitly converted to +// `fmt::basic_format_args` for passing into type-erased formatting functions +// such as `fmt::vformat`. +template +struct format_arg_store { + // args_[0].named_args points to named_args to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + static constexpr size_t ARGS_ARR_SIZE = 1 + (NUM_ARGS != 0 ? NUM_ARGS : +1); + + arg_t args[ARGS_ARR_SIZE]; + named_arg_info named_args[NUM_NAMED_ARGS]; + + template + FMT_MAP_API format_arg_store(T&... values) + : args{{named_args, NUM_NAMED_ARGS}, + make_arg(values)...} { + using dummy = int[]; + int arg_index = 0, named_arg_index = 0; + (void)dummy{ + 0, + (init_named_arg(named_args, arg_index, named_arg_index, values), 0)...}; + } + + format_arg_store(format_arg_store&& rhs) { + args[0] = {named_args, NUM_NAMED_ARGS}; + for (size_t i = 1; i < ARGS_ARR_SIZE; ++i) args[i] = rhs.args[i]; + for (size_t i = 0; i < NUM_NAMED_ARGS; ++i) + named_args[i] = rhs.named_args[i]; + } + + format_arg_store(const format_arg_store& rhs) = delete; + format_arg_store& operator=(const format_arg_store& rhs) = delete; + format_arg_store& operator=(format_arg_store&& rhs) = delete; +}; + +// A specialization of format_arg_store without named arguments. +// It is a plain struct to reduce binary size in debug mode. +template +struct format_arg_store { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + arg_t args[NUM_ARGS != 0 ? NUM_ARGS : +1]; +}; + +} // namespace detail +FMT_BEGIN_EXPORT + +// A formatting argument. Context is a template parameter for the compiled API +// where output can be unbuffered. +template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR auto detail::make_arg(T& value) + -> basic_format_arg; + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::format_arg_store; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const noexcept { + return type_ != detail::type::none_type; + } + + auto type() const -> detail::type { return type_; } + + auto is_integral() const -> bool { return detail::is_integral_type(type_); } + auto is_arithmetic() const -> bool { + return detail::is_arithmetic_type(type_); + } + + /** + * Visits an argument dispatching to the appropriate visit method based on + * the argument type. For example, if the argument type is `double` then + * `vis(value)` will be called with the value of type `double`. + */ + template + FMT_CONSTEXPR FMT_INLINE auto visit(Visitor&& vis) const -> decltype(vis(0)) { + switch (type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(value_.int_value); + case detail::type::uint_type: + return vis(value_.uint_value); + case detail::type::long_long_type: + return vis(value_.long_long_value); + case detail::type::ulong_long_type: + return vis(value_.ulong_long_value); + case detail::type::int128_type: + return vis(detail::convert_for_visit(value_.int128_value)); + case detail::type::uint128_type: + return vis(detail::convert_for_visit(value_.uint128_value)); + case detail::type::bool_type: + return vis(value_.bool_value); + case detail::type::char_type: + return vis(value_.char_value); + case detail::type::float_type: + return vis(value_.float_value); + case detail::type::double_type: + return vis(value_.double_value); + case detail::type::long_double_type: + return vis(value_.long_double_value); + case detail::type::cstring_type: + return vis(value_.string.data); + case detail::type::string_type: + using sv = basic_string_view; + return vis(sv(value_.string.data, value_.string.size)); + case detail::type::pointer_type: + return vis(value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(value_.custom)); + } + return vis(monostate()); + } + + auto format_custom(const char_type* parse_begin, + typename Context::parse_context_type& parse_ctx, + Context& ctx) -> bool { + if (type_ != detail::type::custom_type) return false; + parse_ctx.advance_to(parse_begin); + value_.custom.format(value_.custom.value, parse_ctx, ctx); + return true; + } +}; + +template +FMT_DEPRECATED FMT_CONSTEXPR auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + return arg.visit(static_cast(vis)); +} + +/** + * A view of a collection of formatting arguments. To avoid lifetime issues it + * should only be used as a parameter type in type-erased functions such as + * `vformat`: + * + * void vlog(fmt::string_view fmt, fmt::format_args args); // OK + * fmt::format_args args = fmt::make_format_args(); // Dangling reference + */ +template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr auto is_packed() const -> bool { + return (desc_ & detail::is_unpacked_bit) == 0; + } + constexpr auto has_named_args() const -> bool { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR auto type(int index) const -> detail::type { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /// Constructs a `basic_format_args` object from `format_arg_store`. + template + constexpr FMT_ALWAYS_INLINE basic_format_args( + const detail::format_arg_store& + store) + : desc_(DESC), values_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {} + + template detail::max_packed_args)> + constexpr basic_format_args( + const detail::format_arg_store& + store) + : desc_(DESC), args_(store.args + (NUM_NAMED_ARGS != 0 ? 1 : 0)) {} + + /// Constructs a `basic_format_args` object from `dynamic_format_arg_store`. + constexpr basic_format_args(const dynamic_format_arg_store& store) + : desc_(store.get_types()), args_(store.data()) {} + + /// Constructs a `basic_format_args` object from a dynamic list of arguments. + constexpr basic_format_args(const format_arg* args, int count) + : desc_(detail::is_unpacked_bit | detail::to_unsigned(count)), + args_(args) {} + + /// Returns the argument with the specified id. + FMT_CONSTEXPR auto get(int id) const -> format_arg { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (static_cast(id) >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template + auto get(basic_string_view name) const -> format_arg { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template + FMT_CONSTEXPR auto get_id(basic_string_view name) const -> int { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + auto max_size() const -> int { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } +}; + +// A formatting context. +class context { + private: + appender out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + /// The character type for the output. + using char_type = char; + + using iterator = appender; + using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + /// Constructs a `basic_format_context` object. References to the arguments + /// are stored in the object so make sure they have appropriate lifetimes. + FMT_CONSTEXPR context(iterator out, basic_format_args ctx_args, + detail::locale_ref loc = {}) + : out_(out), args_(ctx_args), loc_(loc) {} + context(context&&) = default; + context(const context&) = delete; + void operator=(const context&) = delete; + + FMT_CONSTEXPR auto arg(int id) const -> format_arg { return args_.get(id); } + auto arg(string_view name) -> format_arg { return args_.get(name); } + FMT_CONSTEXPR auto arg_id(string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const basic_format_args& { return args_; } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + // Advances the begin iterator to `it`. + void advance_to(iterator) {} + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +}; + +template class generic_context; + +// Longer aliases for C++20 compatibility. +template +using basic_format_context = + conditional_t::value, context, + generic_context>; +using format_context = context; + +template +using buffered_context = basic_format_context, Char>; + +template +using is_formattable = bool_constant>() + .map(std::declval()))>::value>; + +#if FMT_USE_CONCEPTS +template +concept formattable = is_formattable, Char>::value; +#endif + +/** + * Constructs an object that stores references to arguments and can be + * implicitly converted to `format_args`. `Context` can be omitted in which case + * it defaults to `format_context`. See `arg` for lifetime considerations. + */ +// Take arguments by lvalue references to avoid some lifetime issues, e.g. +// auto args = make_format_args(std::string()); +template (), + unsigned long long DESC = detail::make_descriptor(), + FMT_ENABLE_IF(NUM_NAMED_ARGS == 0)> +constexpr FMT_ALWAYS_INLINE auto make_format_args(T&... args) + -> detail::format_arg_store { + return {{detail::make_arg( + args)...}}; +} + +#ifndef FMT_DOC +template (), + unsigned long long DESC = + detail::make_descriptor() | + static_cast(detail::has_named_args_bit), + FMT_ENABLE_IF(NUM_NAMED_ARGS != 0)> +constexpr auto make_format_args(T&... args) + -> detail::format_arg_store { + return {args...}; +} +#endif + +/** + * Returns a named argument to be used in a formatting function. + * It should only be used in a call to a formatting function or + * `dynamic_format_arg_store::push_back`. + * + * **Example**: + * + * fmt::print("The answer is {answer}.", fmt::arg("answer", 42)); + */ +template +inline auto arg(const Char* name, const T& arg) -> detail::named_arg { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; +} +FMT_END_EXPORT + +/// An alias for `basic_format_args`. +// A separate type would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). +FMT_EXPORT using format_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug, so we put them +// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414). +// Additionally, if an underlying type is specified, older gcc incorrectly warns +// that the type is too small. Both bugs are fixed in gcc 9.3. +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903 +# define FMT_ENUM_UNDERLYING_TYPE(type) +#else +# define FMT_ENUM_UNDERLYING_TYPE(type) : type +#endif +namespace align { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center, + numeric}; +} +using align_t = align::type; +namespace sign { +enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space}; +} +using sign_t = sign::type; + +namespace detail { + +template +using unsigned_char = typename conditional_t::value, + std::make_unsigned, + type_identity>::type; + +// Character (code unit) type is erased to prevent template bloat. +struct fill_t { + private: + enum { max_size = 4 }; + char data_[max_size] = {' '}; + unsigned char size_ = 1; + + public: + template + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + size_ = static_cast(size); + if (size == 1) { + unsigned uchar = static_cast>(s[0]); + data_[0] = static_cast(uchar); + data_[1] = static_cast(uchar >> 8); + return; + } + FMT_ASSERT(size <= max_size, "invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = static_cast(s[i]); + } + + FMT_CONSTEXPR void operator=(char c) { + data_[0] = c; + size_ = 1; + } + + constexpr auto size() const -> size_t { return size_; } + + template constexpr auto get() const -> Char { + using uchar = unsigned char; + return static_cast(static_cast(data_[0]) | + (static_cast(data_[1]) << 8)); + } + + template ::value)> + constexpr auto data() const -> const Char* { + return data_; + } + template ::value)> + constexpr auto data() const -> const Char* { + return nullptr; + } +}; +} // namespace detail + +enum class presentation_type : unsigned char { + // Common specifiers: + none = 0, + debug = 1, // '?' + string = 2, // 's' (string, bool) + + // Integral, bool and character specifiers: + dec = 3, // 'd' + hex, // 'x' or 'X' + oct, // 'o' + bin, // 'b' or 'B' + chr, // 'c' + + // String and pointer specifiers: + pointer = 3, // 'p' + + // Floating-point specifiers: + exp = 1, // 'e' or 'E' (1 since there is no FP debug presentation) + fixed, // 'f' or 'F' + general, // 'g' or 'G' + hexfloat // 'a' or 'A' +}; + +// Format specifiers for built-in and string types. +struct format_specs { + int width; + int precision; + presentation_type type; + align_t align : 4; + sign_t sign : 3; + bool upper : 1; // An uppercase version e.g. 'X' for 'x'. + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr format_specs() + : width(0), + precision(-1), + type(presentation_type::none), + align(align::none), + sign(sign::none), + upper(false), + alt(false), + localized(false) {} +}; + +namespace detail { + +enum class arg_id_kind { none, index, name }; + +// An argument reference. +template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int idx = 0) : index(idx) {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; +}; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow reusing the same parsed specifiers with +// different sets of arguments (precompilation of format strings). +template struct dynamic_format_specs : format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +// Converts a character to ASCII. Returns '\0' on conversion failure. +template ::value)> +constexpr auto to_ascii(Char c) -> char { + return c <= 0xff ? static_cast(c) : '\0'; +} + +// Returns the number of code units in a code point or 1 on error. +template +FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { + if (const_check(sizeof(Char) != 1)) return 1; + auto c = static_cast(*begin); + return static_cast((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1; +} + +// Return the result via the out param to workaround gcc bug 77539. +template +FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; +} + +template <> +inline auto find(const char* first, const char* last, char value, + const char*& out) -> bool { + out = + static_cast(memchr(first, value, to_unsigned(last - first))); + return out != nullptr; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, + int error_value) noexcept -> int { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0, prev = 0; + auto p = begin; + do { + prev = value; + value = value * 10 + unsigned(*p - '0'); + ++p; + } while (p != end && '0' <= *p && *p <= '9'); + auto num_digits = p - begin; + begin = p; + int digits10 = static_cast(sizeof(int) * CHAR_BIT * 3 / 10); + if (num_digits <= digits10) return static_cast(value); + // Check for overflow. + unsigned max = INT_MAX; + return num_digits == digits10 + 1 && + prev * 10ull + unsigned(p[-1] - '0') <= max + ? static_cast(value) + : error_value; +} + +FMT_CONSTEXPR inline auto parse_align(char c) -> align_t { + switch (c) { + case '<': + return align::left; + case '>': + return align::right; + case '^': + return align::center; + } + return align::none; +} + +template constexpr auto is_name_start(Char c) -> bool { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_'; +} + +template +FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, INT_MAX); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + report_error("invalid format string"); + else + handler.on_index(index); + return begin; + } + if (!is_name_start(c)) { + report_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9'))); + handler.on_name({begin, to_unsigned(it - begin)}); + return it; +} + +template +FMT_CONSTEXPR auto parse_arg_id(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler.on_auto(); + return begin; +} + +template struct dynamic_spec_id_handler { + basic_format_parse_context& ctx; + arg_ref& ref; + + FMT_CONSTEXPR void on_auto() { + int id = ctx.next_arg_id(); + ref = arg_ref(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_index(int id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + ctx.check_dynamic_spec(id); + } + FMT_CONSTEXPR void on_name(basic_string_view id) { + ref = arg_ref(id); + ctx.check_arg_id(id); + } +}; + +// Parses [integer | "{" [arg_id] "}"]. +template +FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + int val = parse_nonnegative_int(begin, end, -1); + if (val != -1) + value = val; + else + report_error("number is too big"); + } else if (*begin == '{') { + ++begin; + auto handler = dynamic_spec_id_handler{ctx, ref}; + if (begin != end) begin = parse_arg_id(begin, end, handler); + if (begin != end && *begin == '}') return ++begin; + report_error("invalid format string"); + } + return begin; +} + +template +FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, + int& value, arg_ref& ref, + basic_format_parse_context& ctx) + -> const Char* { + ++begin; + if (begin == end || *begin == '}') { + report_error("invalid precision"); + return begin; + } + return parse_dynamic_spec(begin, end, value, ref, ctx); +} + +enum class state { start, align, sign, hash, zero, width, precision, locale }; + +// Parses standard format specifiers. +template +FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end, + dynamic_format_specs& specs, + basic_format_parse_context& ctx, + type arg_type) -> const Char* { + auto c = '\0'; + if (end - begin > 1) { + auto next = to_ascii(begin[1]); + c = parse_align(next) == align::none ? to_ascii(*begin) : '\0'; + } else { + if (begin == end) return begin; + c = to_ascii(*begin); + } + + struct { + state current_state = state::start; + FMT_CONSTEXPR void operator()(state s, bool valid = true) { + if (current_state >= s || !valid) + report_error("invalid format specifier"); + current_state = s; + } + } enter_state; + + using pres = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + struct { + const Char*& begin; + dynamic_format_specs& specs; + type arg_type; + + FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* { + if (!in(arg_type, set)) { + if (arg_type == type::none_type) return begin; + report_error("invalid format specifier"); + } + specs.type = pres_type; + return begin + 1; + } + } parse_presentation_type{begin, specs, arg_type}; + + for (;;) { + switch (c) { + case '<': + case '>': + case '^': + enter_state(state::align); + specs.align = parse_align(c); + ++begin; + break; + case '+': + case '-': + case ' ': + if (arg_type == type::none_type) return begin; + enter_state(state::sign, in(arg_type, sint_set | float_set)); + switch (c) { + case '+': + specs.sign = sign::plus; + break; + case '-': + specs.sign = sign::minus; + break; + case ' ': + specs.sign = sign::space; + break; + } + ++begin; + break; + case '#': + if (arg_type == type::none_type) return begin; + enter_state(state::hash, is_arithmetic_type(arg_type)); + specs.alt = true; + ++begin; + break; + case '0': + enter_state(state::zero); + if (!is_arithmetic_type(arg_type)) { + if (arg_type == type::none_type) return begin; + report_error("format specifier requires numeric argument"); + } + if (specs.align == align::none) { + // Ignore 0 if align is specified for compatibility with std::format. + specs.align = align::numeric; + specs.fill = '0'; + } + ++begin; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '{': + enter_state(state::width); + begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); + break; + case '.': + if (arg_type == type::none_type) return begin; + enter_state(state::precision, + in(arg_type, float_set | string_set | cstring_set)); + begin = parse_precision(begin, end, specs.precision, specs.precision_ref, + ctx); + break; + case 'L': + if (arg_type == type::none_type) return begin; + enter_state(state::locale, is_arithmetic_type(arg_type)); + specs.localized = true; + ++begin; + break; + case 'd': + return parse_presentation_type(pres::dec, integral_set); + case 'X': + specs.upper = true; + FMT_FALLTHROUGH; + case 'x': + return parse_presentation_type(pres::hex, integral_set); + case 'o': + return parse_presentation_type(pres::oct, integral_set); + case 'B': + specs.upper = true; + FMT_FALLTHROUGH; + case 'b': + return parse_presentation_type(pres::bin, integral_set); + case 'E': + specs.upper = true; + FMT_FALLTHROUGH; + case 'e': + return parse_presentation_type(pres::exp, float_set); + case 'F': + specs.upper = true; + FMT_FALLTHROUGH; + case 'f': + return parse_presentation_type(pres::fixed, float_set); + case 'G': + specs.upper = true; + FMT_FALLTHROUGH; + case 'g': + return parse_presentation_type(pres::general, float_set); + case 'A': + specs.upper = true; + FMT_FALLTHROUGH; + case 'a': + return parse_presentation_type(pres::hexfloat, float_set); + case 'c': + if (arg_type == type::bool_type) report_error("invalid format specifier"); + return parse_presentation_type(pres::chr, integral_set); + case 's': + return parse_presentation_type(pres::string, + bool_set | string_set | cstring_set); + case 'p': + return parse_presentation_type(pres::pointer, pointer_set | cstring_set); + case '?': + return parse_presentation_type(pres::debug, + char_set | string_set | cstring_set); + case '}': + return begin; + default: { + if (*begin == '}') return begin; + // Parse fill and alignment. + auto fill_end = begin + code_point_length(begin); + if (end - fill_end <= 0) { + report_error("invalid format specifier"); + return begin; + } + if (*begin == '{') { + report_error("invalid fill character '{'"); + return begin; + } + auto align = parse_align(to_ascii(*fill_end)); + enter_state(state::align, align != align::none); + specs.fill = + basic_string_view(begin, to_unsigned(fill_end - begin)); + specs.align = align; + begin = fill_end + 1; + } + } + if (begin == end) return begin; + c = to_ascii(*begin); + } +} + +template +FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void on_name(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + }; + + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; +} + +template +FMT_CONSTEXPR void parse_format_string(basic_string_view format_str, + Handler&& handler) { + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { + if (from == to) return; + for (;;) { + const Char* p = nullptr; + if (!find(from, to, Char('}'), p)) + return handler_.on_text(from, to); + ++p; + if (p == to || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(from, p); + from = p + 1; + } + } + Handler& handler_; + } write = {handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } +} + +template ::value> struct strip_named_arg { + using type = T; +}; +template struct strip_named_arg { + using type = remove_cvref_t; +}; + +template +FMT_VISIBILITY("hidden") // Suppress an ld warning on macOS (#3769). +FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) + -> decltype(ctx.begin()) { + using char_type = typename ParseContext::char_type; + using context = buffered_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), + typename strip_named_arg::type>; +#if defined(__cpp_if_constexpr) + if constexpr (std::is_default_constructible< + formatter>::value) { + return formatter().parse(ctx); + } else { + type_is_unformattable_for _; + return ctx.begin(); + } +#else + return formatter().parse(ctx); +#endif +} + +// Checks char specs and returns true iff the presentation type is char-like. +FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool { + if (specs.type != presentation_type::none && + specs.type != presentation_type::chr && + specs.type != presentation_type::debug) { + return false; + } + if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) + report_error("invalid format specifier for char"); + return true; +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template +constexpr auto get_arg_index_by_name(basic_string_view name) -> int { + if constexpr (is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + (void)name; // Workaround an MSVC bug about "unused" parameter. + return -1; +} +#endif + +template +FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return -1; +} + +template class format_string_checker { + private: + using parse_context_type = compile_parse_context; + static constexpr int num_args = sizeof...(Args); + + // Format specifier parsing function. + // In the future basic_format_parse_context will replace compile_parse_context + // here and will use is_constant_evaluated and downcasting to access the data + // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. + using parse_func = const Char* (*)(parse_context_type&); + + type types_[num_args > 0 ? static_cast(num_args) : 1]; + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; + + public: + explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt) + : types_{mapped_type_constant>::value...}, + context_(fmt, num_args, types_), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + return context_.check_arg_id(id), id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS + auto index = get_arg_index_by_name(id); + if (index < 0) on_error("named argument is not found"); + return index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { + on_format_specs(id, begin, begin); // Call parse() on empty specs. + } + + FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) + -> const Char* { + context_.advance_to(begin); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_NORETURN FMT_CONSTEXPR void on_error(const char* message) { + report_error(message); + } +}; + +// A base class for compile-time strings. +struct compile_string {}; + +template +using is_compile_string = std::is_base_of; + +// Reports a compile-time error if S is not a valid format string. +template ::value)> +FMT_ALWAYS_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif +} +template ::value)> +void check_format_string(S format_str) { + using char_t = typename S::char_type; + FMT_CONSTEXPR auto s = basic_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR bool error = (parse_format_string(s, checker(s)), true); + ignore_unused(error); +} + +// Report truncation to prevent silent data loss. +inline void report_truncation(bool truncated) { + if (truncated) report_error("output is truncated"); +} + +// Use vformat_args and avoid type_identity to keep symbols short and workaround +// a GCC <= 4.8 bug. +template struct vformat_args { + using type = basic_format_args>; +}; +template <> struct vformat_args { + using type = format_args; +}; + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc = {}); + +FMT_API void vprint_mojibake(FILE*, string_view, format_args, bool = false); +#ifndef _WIN32 +inline void vprint_mojibake(FILE*, string_view, format_args, bool) {} +#endif + +template struct native_formatter { + private: + dynamic_format_specs specs_; + + public: + using nonlocking = void; + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); + auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, TYPE); + if (const_check(TYPE == type::char_type)) check_char_specs(specs_); + return end; + } + + template + FMT_CONSTEXPR void set_debug_format(bool set = true) { + specs_.type = set ? presentation_type::debug : presentation_type::none; + } + + template + FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const + -> decltype(ctx.out()); +}; +} // namespace detail + +FMT_BEGIN_EXPORT + +// A formatter specialization for natively supported types. +template +struct formatter::value != + detail::type::custom_type>> + : detail::native_formatter::value> { +}; + +template struct runtime_format_string { + basic_string_view str; +}; + +/// A compile-time format string. +template class basic_format_string { + private: + basic_string_view str_; + + public: + template < + typename S, + FMT_ENABLE_IF( + std::is_convertible>::value || + (detail::is_compile_string::value && + std::is_constructible, const S&>::value))> + FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_format_string(const S& s) : str_(s) { + static_assert( + detail::count< + (std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); +#if FMT_USE_CONSTEVAL + if constexpr (detail::count_named_args() == + detail::count_statically_named_args()) { + using checker = + detail::format_string_checker...>; + detail::parse_format_string(str_, checker(s)); + } +#else + detail::check_format_string(s); +#endif + } + basic_format_string(runtime_format_string fmt) : str_(fmt.str) {} + + FMT_ALWAYS_INLINE operator basic_string_view() const { return str_; } + auto get() const -> basic_string_view { return str_; } +}; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using format_string = string_view; +inline auto runtime(string_view s) -> string_view { return s; } +#else +template +using format_string = basic_format_string...>; +/** + * Creates a runtime format string. + * + * **Example**: + * + * // Check format string at runtime instead of compile-time. + * fmt::print(fmt::runtime("{:d}"), "I am not a number"); + */ +inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; } +#endif + +/// Formats a string and writes the output to `out`. +template , + char>::value)> +auto vformat_to(OutputIt&& out, string_view fmt, format_args args) + -> remove_cvref_t { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, fmt, args, {}); + return detail::get_iterator(buf, out); +} + +/** + * Formats `args` according to specifications in `fmt`, writes the result to + * the output iterator `out` and returns the iterator past the end of the output + * range. `format_to` does not append a terminating null character. + * + * **Example**: + * + * auto out = std::vector(); + * fmt::format_to(std::back_inserter(out), "{}", 42); + */ +template , + char>::value)> +FMT_INLINE auto format_to(OutputIt&& out, format_string fmt, T&&... args) + -> remove_cvref_t { + return vformat_to(FMT_FWD(out), fmt, fmt::make_format_args(args...)); +} + +template struct format_to_n_result { + /// Iterator past the end of the output range. + OutputIt out; + /// Total (not truncated) output size. + size_t size; +}; + +template ::value)> +auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, fmt, args, {}); + return {buf.out(), buf.count()}; +} + +/** + * Formats `args` according to specifications in `fmt`, writes up to `n` + * characters of the result to the output iterator `out` and returns the total + * (not truncated) output size and the iterator past the end of the output + * range. `format_to_n` does not append a terminating null character. + */ +template ::value)> +FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, + T&&... args) -> format_to_n_result { + return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); +} + +template +struct format_to_result { + /// Iterator pointing to just after the last successful write in the range. + OutputIt out; + /// Specifies if the output was truncated. + bool truncated; + + FMT_CONSTEXPR operator OutputIt&() & { + detail::report_truncation(truncated); + return out; + } + FMT_CONSTEXPR operator const OutputIt&() const& { + detail::report_truncation(truncated); + return out; + } + FMT_CONSTEXPR operator OutputIt&&() && { + detail::report_truncation(truncated); + return static_cast(out); + } +}; + +template +auto vformat_to(char (&out)[N], string_view fmt, format_args args) + -> format_to_result { + auto result = vformat_to_n(out, N, fmt, args); + return {result.out, result.size > N}; +} + +template +FMT_INLINE auto format_to(char (&out)[N], format_string fmt, T&&... args) + -> format_to_result { + auto result = fmt::format_to_n(out, N, fmt, static_cast(args)...); + return {result.out, result.size > N}; +} + +/// Returns the number of chars in the output of `format(fmt, args...)`. +template +FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); + return buf.count(); +} + +FMT_API void vprint(string_view fmt, format_args args); +FMT_API void vprint(FILE* f, string_view fmt, format_args args); +FMT_API void vprint_buffered(FILE* f, string_view fmt, format_args args); +FMT_API void vprintln(FILE* f, string_view fmt, format_args args); + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `stdout`. + * + * **Example**: + * + * fmt::print("The answer is {}.", 42); + */ +template +FMT_INLINE void print(format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (!detail::use_utf8()) return detail::vprint_mojibake(stdout, fmt, vargs); + return detail::is_locking() ? vprint_buffered(stdout, fmt, vargs) + : vprint(fmt, vargs); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the + * output to the file `f`. + * + * **Example**: + * + * fmt::print(stderr, "Don't {}!", "panic"); + */ +template +FMT_INLINE void print(FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (!detail::use_utf8()) return detail::vprint_mojibake(f, fmt, vargs); + return detail::is_locking() ? vprint_buffered(f, fmt, vargs) + : vprint(f, fmt, vargs); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to the file `f` followed by a newline. +template +FMT_INLINE void println(FILE* f, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + return detail::use_utf8() ? vprintln(f, fmt, vargs) + : detail::vprint_mojibake(f, fmt, vargs, true); +} + +/// Formats `args` according to specifications in `fmt` and writes the output +/// to `stdout` followed by a newline. +template +FMT_INLINE void println(format_string fmt, T&&... args) { + return fmt::println(stdout, fmt, static_cast(args)...); +} + +FMT_END_EXPORT +FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_BASE_H_ diff --git a/cpp_src/vendor/fmt/chrono.h b/cpp_src/vendor/fmt/chrono.h new file mode 100644 index 000000000..c93123fd3 --- /dev/null +++ b/cpp_src/vendor/fmt/chrono.h @@ -0,0 +1,2432 @@ +// Formatting library for C++ - chrono support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CHRONO_H_ +#define FMT_CHRONO_H_ + +#ifndef FMT_MODULE +# include +# include +# include // std::isfinite +# include // std::memcpy +# include +# include +# include +# include +# include +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +// Check if std::chrono::local_t is available. +#ifndef FMT_USE_LOCAL_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_LOCAL_TIME 0 +# endif +#endif + +// Check if std::chrono::utc_timestamp is available. +#ifndef FMT_USE_UTC_TIME +# ifdef __cpp_lib_chrono +# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) +# else +# define FMT_USE_UTC_TIME 0 +# endif +#endif + +// Enable tzset. +#ifndef FMT_USE_TZSET +// UWP doesn't provide _tzset. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# define FMT_USE_TZSET 1 +# else +# define FMT_USE_TZSET 0 +# endif +#endif + +// Enable safe chrono durations, unless explicitly disabled. +#ifndef FMT_SAFE_DURATION_CAST +# define FMT_SAFE_DURATION_CAST 1 +#endif +#if FMT_SAFE_DURATION_CAST + +// For conversion between std::chrono::durations without undefined +// behaviour or erroneous results. +// This is a stripped down version of duration_cast, for inclusion in fmt. +// See https://github.com/pauldreik/safe_duration_cast +// +// Copyright Paul Dreik 2019 +namespace safe_duration_cast { + +template ::value && + std::numeric_limits::is_signed == + std::numeric_limits::is_signed)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + // A and B are both signed, or both unsigned. + if (detail::const_check(F::digits <= T::digits)) { + // From fits in To without any problem. + } else { + // From does not always fit in To, resort to a dynamic check. + if (from < (T::min)() || from > (T::max)()) { + // outside range. + ec = 1; + return {}; + } + } + return static_cast(from); +} + +/// Converts From to To, without loss. If the dynamic value of from +/// can't be converted to To without loss, ec is set. +template ::value && + std::numeric_limits::is_signed != + std::numeric_limits::is_signed)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + using F = std::numeric_limits; + using T = std::numeric_limits; + static_assert(F::is_integer, "From must be integral"); + static_assert(T::is_integer, "To must be integral"); + + if (detail::const_check(F::is_signed && !T::is_signed)) { + // From may be negative, not allowed! + if (fmt::detail::is_negative(from)) { + ec = 1; + return {}; + } + // From is positive. Can it always fit in To? + if (detail::const_check(F::digits > T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + } + + if (detail::const_check(!F::is_signed && T::is_signed && + F::digits >= T::digits) && + from > static_cast(detail::max_value())) { + ec = 1; + return {}; + } + return static_cast(from); // Lossless conversion. +} + +template ::value)> +FMT_CONSTEXPR auto lossless_integral_conversion(const From from, int& ec) + -> To { + ec = 0; + return from; +} // function + +// clang-format off +/** + * converts From to To if possible, otherwise ec is set. + * + * input | output + * ---------------------------------|--------------- + * NaN | NaN + * Inf | Inf + * normal, fits in output | converted (possibly lossy) + * normal, does not fit in output | ec is set + * subnormal | best effort + * -Inf | -Inf + */ +// clang-format on +template ::value)> +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { + ec = 0; + using T = std::numeric_limits; + static_assert(std::is_floating_point::value, "From must be floating"); + static_assert(std::is_floating_point::value, "To must be floating"); + + // catch the only happy case + if (std::isfinite(from)) { + if (from >= T::lowest() && from <= (T::max)()) { + return static_cast(from); + } + // not within range. + ec = 1; + return {}; + } + + // nan and inf will be preserved + return static_cast(from); +} // function + +template ::value)> +FMT_CONSTEXPR auto safe_float_conversion(const From from, int& ec) -> To { + ec = 0; + static_assert(std::is_floating_point::value, "From must be floating"); + return from; +} + +/// Safe duration cast between integral durations +template ::value), + FMT_ENABLE_IF(std::is_integral::value)> +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { + using From = std::chrono::duration; + ec = 0; + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // safe conversion to IntermediateRep + IntermediateRep count = + lossless_integral_conversion(from.count(), ec); + if (ec) return {}; + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + const auto max1 = detail::max_value() / Factor::num; + if (count > max1) { + ec = 1; + return {}; + } + const auto min1 = + (std::numeric_limits::min)() / Factor::num; + if (detail::const_check(!std::is_unsigned::value) && + count < min1) { + ec = 1; + return {}; + } + count *= Factor::num; + } + + if (detail::const_check(Factor::den != 1)) count /= Factor::den; + auto tocount = lossless_integral_conversion(count, ec); + return ec ? To() : To(tocount); +} + +/// Safe duration_cast between floating point durations +template ::value), + FMT_ENABLE_IF(std::is_floating_point::value)> +auto safe_duration_cast(std::chrono::duration from, + int& ec) -> To { + using From = std::chrono::duration; + ec = 0; + if (std::isnan(from.count())) { + // nan in, gives nan out. easy. + return To{std::numeric_limits::quiet_NaN()}; + } + // maybe we should also check if from is denormal, and decide what to do about + // it. + + // +-inf should be preserved. + if (std::isinf(from.count())) { + return To{from.count()}; + } + + // the basic idea is that we need to convert from count() in the from type + // to count() in the To type, by multiplying it with this: + struct Factor + : std::ratio_divide {}; + + static_assert(Factor::num > 0, "num must be positive"); + static_assert(Factor::den > 0, "den must be positive"); + + // the conversion is like this: multiply from.count() with Factor::num + // /Factor::den and convert it to To::rep, all this without + // overflow/underflow. let's start by finding a suitable type that can hold + // both To, From and Factor::num + using IntermediateRep = + typename std::common_type::type; + + // force conversion of From::rep -> IntermediateRep to be safe, + // even if it will never happen be narrowing in this context. + IntermediateRep count = + safe_float_conversion(from.count(), ec); + if (ec) { + return {}; + } + + // multiply with Factor::num without overflow or underflow + if (detail::const_check(Factor::num != 1)) { + constexpr auto max1 = detail::max_value() / + static_cast(Factor::num); + if (count > max1) { + ec = 1; + return {}; + } + constexpr auto min1 = std::numeric_limits::lowest() / + static_cast(Factor::num); + if (count < min1) { + ec = 1; + return {}; + } + count *= static_cast(Factor::num); + } + + // this can't go wrong, right? den>0 is checked earlier. + if (detail::const_check(Factor::den != 1)) { + using common_t = typename std::common_type::type; + count /= static_cast(Factor::den); + } + + // convert to the to type, safely + using ToRep = typename To::rep; + + const ToRep tocount = safe_float_conversion(count, ec); + if (ec) { + return {}; + } + return To{tocount}; +} +} // namespace safe_duration_cast +#endif + +// Prevents expansion of a preceding token as a function-style macro. +// Usage: f FMT_NOMACRO() +#define FMT_NOMACRO + +namespace detail { +template struct null {}; +inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); } +inline auto localtime_s(...) -> null<> { return null<>(); } +inline auto gmtime_r(...) -> null<> { return null<>(); } +inline auto gmtime_s(...) -> null<> { return null<>(); } + +// It is defined here and not in ostream.h because the latter has expensive +// includes. +template class formatbuf : public Streambuf { + private: + using char_type = typename Streambuf::char_type; + using streamsize = decltype(std::declval().sputn(nullptr, 0)); + using int_type = typename Streambuf::int_type; + using traits_type = typename Streambuf::traits_type; + + buffer& buffer_; + + public: + explicit formatbuf(buffer& buf) : buffer_(buf) {} + + protected: + // The put area is always empty. This makes the implementation simpler and has + // the advantage that the streambuf and the buffer are always in sync and + // sputc never writes into uninitialized memory. A disadvantage is that each + // call to sputc always results in a (virtual) call to overflow. There is no + // disadvantage here for sputn since this always results in a call to xsputn. + + auto overflow(int_type ch) -> int_type override { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); + return ch; + } + + auto xsputn(const char_type* s, streamsize count) -> streamsize override { + buffer_.append(s, s + count); + return count; + } +}; + +inline auto get_classic_locale() -> const std::locale& { + static const auto& locale = std::locale::classic(); + return locale; +} + +template struct codecvt_result { + static constexpr const size_t max_size = 32; + CodeUnit buf[max_size]; + CodeUnit* end; +}; + +template +void write_codecvt(codecvt_result& out, string_view in_buf, + const std::locale& loc) { +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet>(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet>(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, + std::begin(out.buf), std::end(out.buf), out.end); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); +} + +template +auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) + -> OutputIt { + if (detail::use_utf8() && loc != get_classic_locale()) { + // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and + // gcc-4. +#if FMT_MSC_VERSION != 0 || \ + (defined(__GLIBCXX__) && \ + (!defined(_GLIBCXX_USE_DUAL_ABI) || _GLIBCXX_USE_DUAL_ABI == 0)) + // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 + // and newer. + using code_unit = wchar_t; +#else + using code_unit = char32_t; +#endif + + using unit_t = codecvt_result; + unit_t unit; + write_codecvt(unit, in, loc); + // In UTF-8 is used one to four one-byte code units. + auto u = + to_utf8>(); + if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) + FMT_THROW(format_error("failed to format time")); + return copy(u.c_str(), u.c_str() + u.size(), out); + } + return copy(in.data(), in.data() + in.size(), out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + codecvt_result unit; + write_codecvt(unit, sv, loc); + return copy(unit.buf, unit.end, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + return write_encoded_tm_str(out, sv, loc); +} + +template +inline void do_write(buffer& buf, const std::tm& time, + const std::locale& loc, char format, char modifier) { + auto&& format_buf = formatbuf>(buf); + auto&& os = std::basic_ostream(&format_buf); + os.imbue(loc); + const auto& facet = std::use_facet>(loc); + auto end = facet.put(os, os, Char(' '), &time, format, modifier); + if (end.failed()) FMT_THROW(format_error("failed to format time")); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = get_buffer(out); + do_write(buf, time, loc, format, modifier); + return get_iterator(buf, out); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buf = basic_memory_buffer(); + do_write(buf, time, loc, format, modifier); + return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); +} + +template +struct is_same_arithmetic_type + : public std::integral_constant::value && + std::is_integral::value) || + (std::is_floating_point::value && + std::is_floating_point::value)> { +}; + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { +#if FMT_SAFE_DURATION_CAST + // Throwing version of safe_duration_cast is only available for + // integer to integer or float to float casts. + int ec; + To to = safe_duration_cast::safe_duration_cast(from, ec); + if (ec) FMT_THROW(format_error("cannot format duration")); + return to; +#else + // Standard duration cast, may overflow. + return std::chrono::duration_cast(from); +#endif +} + +template < + typename To, typename FromRep, typename FromPeriod, + FMT_ENABLE_IF(!is_same_arithmetic_type::value)> +auto fmt_duration_cast(std::chrono::duration from) -> To { + // Mixed integer <-> float cast is not supported by safe_duration_cast. + return std::chrono::duration_cast(from); +} + +template +auto to_time_t( + std::chrono::time_point time_point) + -> std::time_t { + // Cannot use std::chrono::system_clock::to_time_t since this would first + // require a cast to std::chrono::system_clock::time_point, which could + // overflow. + return fmt_duration_cast>( + time_point.time_since_epoch()) + .count(); +} +} // namespace detail + +FMT_BEGIN_EXPORT + +/** + * Converts given time since epoch as `std::time_t` value into calendar time, + * expressed in local time. Unlike `std::localtime`, this function is + * thread-safe on most platforms. + */ +inline auto localtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + auto run() -> bool { + using namespace fmt::detail; + return handle(localtime_r(&time_, &tm_)); + } + + auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(localtime_s(&tm_, &time_)); + } + + auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { + using namespace fmt::detail; + std::tm* tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + dispatcher lt(time); + // Too big time values may be unsupported. + if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); + return lt.tm_; +} + +#if FMT_USE_LOCAL_TIME +template +inline auto localtime(std::chrono::local_time time) -> std::tm { + return localtime( + detail::to_time_t(std::chrono::current_zone()->to_sys(time))); +} +#endif + +/** + * Converts given time since epoch as `std::time_t` value into calendar time, + * expressed in Coordinated Universal Time (UTC). Unlike `std::gmtime`, this + * function is thread-safe on most platforms. + */ +inline auto gmtime(std::time_t time) -> std::tm { + struct dispatcher { + std::time_t time_; + std::tm tm_; + + dispatcher(std::time_t t) : time_(t) {} + + auto run() -> bool { + using namespace fmt::detail; + return handle(gmtime_r(&time_, &tm_)); + } + + auto handle(std::tm* tm) -> bool { return tm != nullptr; } + + auto handle(detail::null<>) -> bool { + using namespace fmt::detail; + return fallback(gmtime_s(&tm_, &time_)); + } + + auto fallback(int res) -> bool { return res == 0; } + +#if !FMT_MSC_VERSION + auto fallback(detail::null<>) -> bool { + std::tm* tm = std::gmtime(&time_); + if (tm) tm_ = *tm; + return tm != nullptr; + } +#endif + }; + auto gt = dispatcher(time); + // Too big time values may be unsupported. + if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); + return gt.tm_; +} + +template +inline auto gmtime( + std::chrono::time_point time_point) + -> std::tm { + return gmtime(detail::to_time_t(time_point)); +} + +namespace detail { + +// Writes two-digit numbers a, b and c separated by sep to buf. +// The method by Pavel Novikov based on +// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. +inline void write_digit2_separated(char* buf, unsigned a, unsigned b, + unsigned c, char sep) { + unsigned long long digits = + a | (b << 24) | (static_cast(c) << 48); + // Convert each value to BCD. + // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. + // The difference is + // y - x = a * 6 + // a can be found from x: + // a = floor(x / 10) + // then + // y = x + a * 6 = x + floor(x / 10) * 6 + // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). + digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; + // Put low nibbles to high bytes and high nibbles to low bytes. + digits = ((digits & 0x00f00000f00000f0) >> 4) | + ((digits & 0x000f00000f00000f) << 8); + auto usep = static_cast(sep); + // Add ASCII '0' to each digit byte and insert separators. + digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); + + constexpr const size_t len = 8; + if (const_check(is_big_endian())) { + char tmp[len]; + std::memcpy(tmp, &digits, len); + std::reverse_copy(tmp, tmp + len, buf); + } else { + std::memcpy(buf, &digits, len); + } +} + +template +FMT_CONSTEXPR inline auto get_units() -> const char* { + if (std::is_same::value) return "as"; + if (std::is_same::value) return "fs"; + if (std::is_same::value) return "ps"; + if (std::is_same::value) return "ns"; + if (std::is_same::value) return "µs"; + if (std::is_same::value) return "ms"; + if (std::is_same::value) return "cs"; + if (std::is_same::value) return "ds"; + if (std::is_same>::value) return "s"; + if (std::is_same::value) return "das"; + if (std::is_same::value) return "hs"; + if (std::is_same::value) return "ks"; + if (std::is_same::value) return "Ms"; + if (std::is_same::value) return "Gs"; + if (std::is_same::value) return "Ts"; + if (std::is_same::value) return "Ps"; + if (std::is_same::value) return "Es"; + if (std::is_same>::value) return "min"; + if (std::is_same>::value) return "h"; + if (std::is_same>::value) return "d"; + return nullptr; +} + +enum class numeric_system { + standard, + // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. + alternative +}; + +// Glibc extensions for formatting numeric values. +enum class pad_type { + // Pad a numeric result string with zeros (the default). + zero, + // Do not pad a numeric result string. + none, + // Pad a numeric result string with spaces. + space, +}; + +template +auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { + if (pad == pad_type::none) return out; + return detail::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); +} + +template +auto write_padding(OutputIt out, pad_type pad) -> OutputIt { + if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; + return out; +} + +// Parses a put_time-like format string and invokes handler actions. +template +FMT_CONSTEXPR auto parse_chrono_format(const Char* begin, const Char* end, + Handler&& handler) -> const Char* { + if (begin == end || *begin == '}') return begin; + if (*begin != '%') FMT_THROW(format_error("invalid format")); + auto ptr = begin; + while (ptr != end) { + pad_type pad = pad_type::zero; + auto c = *ptr; + if (c == '}') break; + if (c != '%') { + ++ptr; + continue; + } + if (begin != ptr) handler.on_text(begin, ptr); + ++ptr; // consume '%' + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr; + switch (c) { + case '_': + pad = pad_type::space; + ++ptr; + break; + case '-': + pad = pad_type::none; + ++ptr; + break; + } + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case '%': + handler.on_text(ptr - 1, ptr); + break; + case 'n': { + const Char newline[] = {'\n'}; + handler.on_text(newline, newline + 1); + break; + } + case 't': { + const Char tab[] = {'\t'}; + handler.on_text(tab, tab + 1); + break; + } + // Year: + case 'Y': + handler.on_year(numeric_system::standard); + break; + case 'y': + handler.on_short_year(numeric_system::standard); + break; + case 'C': + handler.on_century(numeric_system::standard); + break; + case 'G': + handler.on_iso_week_based_year(); + break; + case 'g': + handler.on_iso_week_based_short_year(); + break; + // Day of the week: + case 'a': + handler.on_abbr_weekday(); + break; + case 'A': + handler.on_full_weekday(); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::standard); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::standard); + break; + // Month: + case 'b': + case 'h': + handler.on_abbr_month(); + break; + case 'B': + handler.on_full_month(); + break; + case 'm': + handler.on_dec_month(numeric_system::standard); + break; + // Day of the year/month: + case 'U': + handler.on_dec0_week_of_year(numeric_system::standard, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::standard, pad); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::standard, pad); + break; + case 'j': + handler.on_day_of_year(); + break; + case 'd': + handler.on_day_of_month(numeric_system::standard, pad); + break; + case 'e': + handler.on_day_of_month(numeric_system::standard, pad_type::space); + break; + // Hour, minute, second: + case 'H': + handler.on_24_hour(numeric_system::standard, pad); + break; + case 'I': + handler.on_12_hour(numeric_system::standard, pad); + break; + case 'M': + handler.on_minute(numeric_system::standard, pad); + break; + case 'S': + handler.on_second(numeric_system::standard, pad); + break; + // Other: + case 'c': + handler.on_datetime(numeric_system::standard); + break; + case 'x': + handler.on_loc_date(numeric_system::standard); + break; + case 'X': + handler.on_loc_time(numeric_system::standard); + break; + case 'D': + handler.on_us_date(); + break; + case 'F': + handler.on_iso_date(); + break; + case 'r': + handler.on_12_hour_time(); + break; + case 'R': + handler.on_24_hour_time(); + break; + case 'T': + handler.on_iso_time(); + break; + case 'p': + handler.on_am_pm(); + break; + case 'Q': + handler.on_duration_value(); + break; + case 'q': + handler.on_duration_unit(); + break; + case 'z': + handler.on_utc_offset(numeric_system::standard); + break; + case 'Z': + handler.on_tz_name(); + break; + // Alternative representation: + case 'E': { + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'Y': + handler.on_year(numeric_system::alternative); + break; + case 'y': + handler.on_offset_year(); + break; + case 'C': + handler.on_century(numeric_system::alternative); + break; + case 'c': + handler.on_datetime(numeric_system::alternative); + break; + case 'x': + handler.on_loc_date(numeric_system::alternative); + break; + case 'X': + handler.on_loc_time(numeric_system::alternative); + break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + } + case 'O': + if (ptr == end) FMT_THROW(format_error("invalid format")); + c = *ptr++; + switch (c) { + case 'y': + handler.on_short_year(numeric_system::alternative); + break; + case 'm': + handler.on_dec_month(numeric_system::alternative); + break; + case 'U': + handler.on_dec0_week_of_year(numeric_system::alternative, pad); + break; + case 'W': + handler.on_dec1_week_of_year(numeric_system::alternative, pad); + break; + case 'V': + handler.on_iso_week_of_year(numeric_system::alternative, pad); + break; + case 'd': + handler.on_day_of_month(numeric_system::alternative, pad); + break; + case 'e': + handler.on_day_of_month(numeric_system::alternative, pad_type::space); + break; + case 'w': + handler.on_dec0_weekday(numeric_system::alternative); + break; + case 'u': + handler.on_dec1_weekday(numeric_system::alternative); + break; + case 'H': + handler.on_24_hour(numeric_system::alternative, pad); + break; + case 'I': + handler.on_12_hour(numeric_system::alternative, pad); + break; + case 'M': + handler.on_minute(numeric_system::alternative, pad); + break; + case 'S': + handler.on_second(numeric_system::alternative, pad); + break; + case 'z': + handler.on_utc_offset(numeric_system::alternative); + break; + default: + FMT_THROW(format_error("invalid format")); + } + break; + default: + FMT_THROW(format_error("invalid format")); + } + begin = ptr; + } + if (begin != ptr) handler.on_text(begin, ptr); + return ptr; +} + +template struct null_chrono_spec_handler { + FMT_CONSTEXPR void unsupported() { + static_cast(this)->unsupported(); + } + FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_offset_year() { unsupported(); } + FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } + FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } + FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } + FMT_CONSTEXPR void on_full_weekday() { unsupported(); } + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_abbr_month() { unsupported(); } + FMT_CONSTEXPR void on_full_month() { unsupported(); } + FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_day_of_year() { unsupported(); } + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) { + unsupported(); + } + FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_us_date() { unsupported(); } + FMT_CONSTEXPR void on_iso_date() { unsupported(); } + FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } + FMT_CONSTEXPR void on_iso_time() { unsupported(); } + FMT_CONSTEXPR void on_am_pm() { unsupported(); } + FMT_CONSTEXPR void on_duration_value() { unsupported(); } + FMT_CONSTEXPR void on_duration_unit() { unsupported(); } + FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); } + FMT_CONSTEXPR void on_tz_name() { unsupported(); } +}; + +struct tm_format_checker : null_chrono_spec_handler { + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_year(numeric_system) {} + FMT_CONSTEXPR void on_short_year(numeric_system) {} + FMT_CONSTEXPR void on_offset_year() {} + FMT_CONSTEXPR void on_century(numeric_system) {} + FMT_CONSTEXPR void on_iso_week_based_year() {} + FMT_CONSTEXPR void on_iso_week_based_short_year() {} + FMT_CONSTEXPR void on_abbr_weekday() {} + FMT_CONSTEXPR void on_full_weekday() {} + FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} + FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} + FMT_CONSTEXPR void on_abbr_month() {} + FMT_CONSTEXPR void on_full_month() {} + FMT_CONSTEXPR void on_dec_month(numeric_system) {} + FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_iso_week_of_year(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_day_of_month(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_datetime(numeric_system) {} + FMT_CONSTEXPR void on_loc_date(numeric_system) {} + FMT_CONSTEXPR void on_loc_time(numeric_system) {} + FMT_CONSTEXPR void on_us_date() {} + FMT_CONSTEXPR void on_iso_date() {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_utc_offset(numeric_system) {} + FMT_CONSTEXPR void on_tz_name() {} +}; + +inline auto tm_wday_full_name(int wday) -> const char* { + static constexpr const char* full_name_list[] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday"}; + return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; +} +inline auto tm_wday_short_name(int wday) -> const char* { + static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat"}; + return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; +} + +inline auto tm_mon_full_name(int mon) -> const char* { + static constexpr const char* full_name_list[] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"}; + return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; +} +inline auto tm_mon_short_name(int mon) -> const char* { + static constexpr const char* short_name_list[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; +} + +template +struct has_member_data_tm_gmtoff : std::false_type {}; +template +struct has_member_data_tm_gmtoff> + : std::true_type {}; + +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + +#if FMT_USE_TZSET +inline void tzset_once() { + static bool init = []() -> bool { + _tzset(); + return true; + }(); + ignore_unused(init); +} +#endif + +// Converts value to Int and checks that it's in the range [0, upper). +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + if (!std::is_unsigned::value && + (value < 0 || to_unsigned(value) > to_unsigned(upper))) { + FMT_THROW(fmt::format_error("chrono value is out of range")); + } + return static_cast(value); +} +template ::value)> +inline auto to_nonnegative_int(T value, Int upper) -> Int { + auto int_value = static_cast(value); + if (int_value < 0 || value > static_cast(upper)) + FMT_THROW(format_error("invalid value")); + return int_value; +} + +constexpr auto pow10(std::uint32_t n) -> long long { + return n == 0 ? 1 : 10 * pow10(n - 1); +} + +// Counts the number of fractional digits in the range [0, 18] according to the +// C++20 spec. If more than 18 fractional digits are required then returns 6 for +// microseconds precision. +template () / 10)> +struct count_fractional_digits { + static constexpr int value = + Num % Den == 0 ? N : count_fractional_digits::value; +}; + +// Base case that doesn't instantiate any more templates +// in order to avoid overflow. +template +struct count_fractional_digits { + static constexpr int value = (Num % Den == 0) ? N : 6; +}; + +// Format subseconds which are given as an integer type with an appropriate +// number of digits. +template +void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { + constexpr auto num_fractional_digits = + count_fractional_digits::value; + + using subsecond_precision = std::chrono::duration< + typename std::common_type::type, + std::ratio<1, detail::pow10(num_fractional_digits)>>; + + const auto fractional = d - fmt_duration_cast(d); + const auto subseconds = + std::chrono::treat_as_floating_point< + typename subsecond_precision::rep>::value + ? fractional.count() + : fmt_duration_cast(fractional).count(); + auto n = static_cast>(subseconds); + const int num_digits = detail::count_digits(n); + + int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); + if (precision < 0) { + FMT_ASSERT(!std::is_floating_point::value, ""); + if (std::ratio_less::value) { + *out++ = '.'; + out = detail::fill_n(out, leading_zeroes, '0'); + out = format_decimal(out, n, num_digits).end; + } + } else if (precision > 0) { + *out++ = '.'; + leading_zeroes = (std::min)(leading_zeroes, precision); + int remaining = precision - leading_zeroes; + out = detail::fill_n(out, leading_zeroes, '0'); + if (remaining < num_digits) { + int num_truncated_digits = num_digits - remaining; + n /= to_unsigned(detail::pow10(to_unsigned(num_truncated_digits))); + if (n) { + out = format_decimal(out, n, remaining).end; + } + return; + } + if (n) { + out = format_decimal(out, n, num_digits).end; + remaining -= num_digits; + } + out = detail::fill_n(out, remaining, '0'); + } +} + +// Format subseconds which are given as a floating point type with an +// appropriate number of digits. We cannot pass the Duration here, as we +// explicitly need to pass the Rep value in the chrono_formatter. +template +void write_floating_seconds(memory_buffer& buf, Duration duration, + int num_fractional_digits = -1) { + using rep = typename Duration::rep; + FMT_ASSERT(std::is_floating_point::value, ""); + + auto val = duration.count(); + + if (num_fractional_digits < 0) { + // For `std::round` with fallback to `round`: + // On some toolchains `std::round` is not available (e.g. GCC 6). + using namespace std; + num_fractional_digits = + count_fractional_digits::value; + if (num_fractional_digits < 6 && static_cast(round(val)) != val) + num_fractional_digits = 6; + } + + fmt::format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), + std::fmod(val * static_cast(Duration::period::num) / + static_cast(Duration::period::den), + static_cast(60)), + num_fractional_digits); +} + +template +class tm_writer { + private: + static constexpr int days_per_week = 7; + + const std::locale& loc_; + const bool is_classic_; + OutputIt out_; + const Duration* subsecs_; + const std::tm& tm_; + + auto tm_sec() const noexcept -> int { + FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); + return tm_.tm_sec; + } + auto tm_min() const noexcept -> int { + FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); + return tm_.tm_min; + } + auto tm_hour() const noexcept -> int { + FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); + return tm_.tm_hour; + } + auto tm_mday() const noexcept -> int { + FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); + return tm_.tm_mday; + } + auto tm_mon() const noexcept -> int { + FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); + return tm_.tm_mon; + } + auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } + auto tm_wday() const noexcept -> int { + FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); + return tm_.tm_wday; + } + auto tm_yday() const noexcept -> int { + FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); + return tm_.tm_yday; + } + + auto tm_hour12() const noexcept -> int { + const auto h = tm_hour(); + const auto z = h < 12 ? h : h - 12; + return z == 0 ? 12 : z; + } + + // POSIX and the C Standard are unclear or inconsistent about what %C and %y + // do if the year is negative or exceeds 9999. Use the convention that %C + // concatenated with %y yields the same output as %Y, and that %Y contains at + // least 4 characters, with more only if necessary. + auto split_year_lower(long long year) const noexcept -> int { + auto l = year % 100; + if (l < 0) l = -l; // l in [0, 99] + return static_cast(l); + } + + // Algorithm: https://en.wikipedia.org/wiki/ISO_week_date. + auto iso_year_weeks(long long curr_year) const noexcept -> int { + const auto prev_year = curr_year - 1; + const auto curr_p = + (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % + days_per_week; + const auto prev_p = + (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % + days_per_week; + return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); + } + auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { + return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / + days_per_week; + } + auto tm_iso_week_year() const noexcept -> long long { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return year - 1; + if (w > iso_year_weeks(year)) return year + 1; + return year; + } + auto tm_iso_week_of_year() const noexcept -> int { + const auto year = tm_year(); + const auto w = iso_week_num(tm_yday(), tm_wday()); + if (w < 1) return iso_year_weeks(year - 1); + if (w > iso_year_weeks(year)) return 1; + return w; + } + + void write1(int value) { + *out_++ = static_cast('0' + to_unsigned(value) % 10); + } + void write2(int value) { + const char* d = digits2(to_unsigned(value) % 100); + *out_++ = *d++; + *out_++ = *d; + } + void write2(int value, pad_type pad) { + unsigned int v = to_unsigned(value) % 100; + if (v >= 10) { + const char* d = digits2(v); + *out_++ = *d++; + *out_++ = *d; + } else { + out_ = detail::write_padding(out_, pad); + *out_++ = static_cast('0' + v); + } + } + + void write_year_extended(long long year) { + // At least 4 characters. + int width = 4; + if (year < 0) { + *out_++ = '-'; + year = 0 - year; + --width; + } + uint32_or_64_or_128_t n = to_unsigned(year); + const int num_digits = count_digits(n); + if (width > num_digits) + out_ = detail::fill_n(out_, width - num_digits, '0'); + out_ = format_decimal(out_, n, num_digits).end; + } + void write_year(long long year) { + if (year >= 0 && year < 10000) { + write2(static_cast(year / 100)); + write2(static_cast(year % 100)); + } else { + write_year_extended(year); + } + } + + void write_utc_offset(long offset, numeric_system ns) { + if (offset < 0) { + *out_++ = '-'; + offset = -offset; + } else { + *out_++ = '+'; + } + offset /= 60; + write2(static_cast(offset / 60)); + if (ns != numeric_system::standard) *out_++ = ':'; + write2(static_cast(offset % 60)); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { + write_utc_offset(tm.tm_gmtoff, ns); + } + template ::value)> + void format_utc_offset_impl(const T& tm, numeric_system ns) { +#if defined(_WIN32) && defined(_UCRT) +# if FMT_USE_TZSET + tzset_once(); +# endif + long offset = 0; + _get_timezone(&offset); + if (tm.tm_isdst) { + long dstbias = 0; + _get_dstbias(&dstbias); + offset += dstbias; + } + write_utc_offset(-offset, ns); +#else + if (ns == numeric_system::standard) return format_localized('z'); + + // Extract timezone offset from timezone conversion functions. + std::tm gtm = tm; + std::time_t gt = std::mktime(>m); + std::tm ltm = gmtime(gt); + std::time_t lt = std::mktime(<m); + long offset = gt - lt; + write_utc_offset(offset, ns); +#endif + } + + template ::value)> + void format_tz_name_impl(const T& tm) { + if (is_classic_) + out_ = write_tm_str(out_, tm.tm_zone, loc_); + else + format_localized('Z'); + } + template ::value)> + void format_tz_name_impl(const T&) { + format_localized('Z'); + } + + void format_localized(char format, char modifier = 0) { + out_ = write(out_, tm_, loc_, format, modifier); + } + + public: + tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm, + const Duration* subsecs = nullptr) + : loc_(loc), + is_classic_(loc_ == get_classic_locale()), + out_(out), + subsecs_(subsecs), + tm_(tm) {} + + auto out() const -> OutputIt { return out_; } + + FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { + out_ = copy(begin, end, out_); + } + + void on_abbr_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_short_name(tm_wday())); + else + format_localized('a'); + } + void on_full_weekday() { + if (is_classic_) + out_ = write(out_, tm_wday_full_name(tm_wday())); + else + format_localized('A'); + } + void on_dec0_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); + format_localized('w', 'O'); + } + void on_dec1_weekday(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write1(wday == 0 ? days_per_week : wday); + } else { + format_localized('u', 'O'); + } + } + + void on_abbr_month() { + if (is_classic_) + out_ = write(out_, tm_mon_short_name(tm_mon())); + else + format_localized('b'); + } + void on_full_month() { + if (is_classic_) + out_ = write(out_, tm_mon_full_name(tm_mon())); + else + format_localized('B'); + } + + void on_datetime(numeric_system ns) { + if (is_classic_) { + on_abbr_weekday(); + *out_++ = ' '; + on_abbr_month(); + *out_++ = ' '; + on_day_of_month(numeric_system::standard, pad_type::space); + *out_++ = ' '; + on_iso_time(); + *out_++ = ' '; + on_year(numeric_system::standard); + } else { + format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); + } + } + void on_loc_date(numeric_system ns) { + if (is_classic_) + on_us_date(); + else + format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_loc_time(numeric_system ns) { + if (is_classic_) + on_iso_time(); + else + format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); + } + void on_us_date() { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_mon() + 1), + to_unsigned(tm_mday()), + to_unsigned(split_year_lower(tm_year())), '/'); + out_ = copy(std::begin(buf), std::end(buf), out_); + } + void on_iso_date() { + auto year = tm_year(); + char buf[10]; + size_t offset = 0; + if (year >= 0 && year < 10000) { + copy2(buf, digits2(static_cast(year / 100))); + } else { + offset = 4; + write_year_extended(year); + year = 0; + } + write_digit2_separated(buf + 2, static_cast(year % 100), + to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), + '-'); + out_ = copy(std::begin(buf) + offset, std::end(buf), out_); + } + + void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } + void on_tz_name() { format_tz_name_impl(tm_); } + + void on_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write_year(tm_year()); + format_localized('Y', 'E'); + } + void on_short_year(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(split_year_lower(tm_year())); + format_localized('y', 'O'); + } + void on_offset_year() { + if (is_classic_) return write2(split_year_lower(tm_year())); + format_localized('y', 'E'); + } + + void on_century(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) { + auto year = tm_year(); + auto upper = year / 100; + if (year >= -99 && year < 0) { + // Zero upper on negative year. + *out_++ = '-'; + *out_++ = '0'; + } else if (upper >= 0 && upper < 100) { + write2(static_cast(upper)); + } else { + out_ = write(out_, upper); + } + } else { + format_localized('C', 'E'); + } + } + + void on_dec_month(numeric_system ns) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mon() + 1); + format_localized('m', 'O'); + } + + void on_dec0_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week, + pad); + format_localized('U', 'O'); + } + void on_dec1_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + auto wday = tm_wday(); + write2((tm_yday() + days_per_week - + (wday == 0 ? (days_per_week - 1) : (wday - 1))) / + days_per_week, + pad); + } else { + format_localized('W', 'O'); + } + } + void on_iso_week_of_year(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_iso_week_of_year(), pad); + format_localized('V', 'O'); + } + + void on_iso_week_based_year() { write_year(tm_iso_week_year()); } + void on_iso_week_based_short_year() { + write2(split_year_lower(tm_iso_week_year())); + } + + void on_day_of_year() { + auto yday = tm_yday() + 1; + write1(yday / 100); + write2(yday % 100); + } + void on_day_of_month(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_mday(), pad); + format_localized('d', 'O'); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour(), pad); + format_localized('H', 'O'); + } + void on_12_hour(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_hour12(), pad); + format_localized('I', 'O'); + } + void on_minute(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) + return write2(tm_min(), pad); + format_localized('M', 'O'); + } + + void on_second(numeric_system ns, pad_type pad) { + if (is_classic_ || ns == numeric_system::standard) { + write2(tm_sec(), pad); + if (subsecs_) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, *subsecs_); + if (buf.size() > 1) { + // Remove the leading "0", write something like ".123". + out_ = std::copy(buf.begin() + 1, buf.end(), out_); + } + } else { + write_fractional_seconds(out_, *subsecs_); + } + } + } else { + // Currently no formatting of subseconds when a locale is set. + format_localized('S', 'O'); + } + } + + void on_12_hour_time() { + if (is_classic_) { + char buf[8]; + write_digit2_separated(buf, to_unsigned(tm_hour12()), + to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); + out_ = copy(std::begin(buf), std::end(buf), out_); + *out_++ = ' '; + on_am_pm(); + } else { + format_localized('r'); + } + } + void on_24_hour_time() { + write2(tm_hour()); + *out_++ = ':'; + write2(tm_min()); + } + void on_iso_time() { + on_24_hour_time(); + *out_++ = ':'; + on_second(numeric_system::standard, pad_type::zero); + } + + void on_am_pm() { + if (is_classic_) { + *out_++ = tm_hour() < 12 ? 'A' : 'P'; + *out_++ = 'M'; + } else { + format_localized('p'); + } + } + + // These apply to chrono durations but not tm. + void on_duration_value() {} + void on_duration_unit() {} +}; + +struct chrono_format_checker : null_chrono_spec_handler { + bool has_precision_integral = false; + + FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } + + template + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + FMT_CONSTEXPR void on_day_of_year() {} + FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} + FMT_CONSTEXPR void on_12_hour_time() {} + FMT_CONSTEXPR void on_24_hour_time() {} + FMT_CONSTEXPR void on_iso_time() {} + FMT_CONSTEXPR void on_am_pm() {} + FMT_CONSTEXPR void on_duration_value() const { + if (has_precision_integral) { + FMT_THROW(format_error("precision not allowed for this argument type")); + } + } + FMT_CONSTEXPR void on_duration_unit() {} +}; + +template ::value&& has_isfinite::value)> +inline auto isfinite(T) -> bool { + return true; +} + +template ::value)> +inline auto mod(T x, int y) -> T { + return x % static_cast(y); +} +template ::value)> +inline auto mod(T x, int y) -> T { + return std::fmod(x, static_cast(y)); +} + +// If T is an integral type, maps T to its unsigned counterpart, otherwise +// leaves it unchanged (unlike std::make_unsigned). +template ::value> +struct make_unsigned_or_unchanged { + using type = T; +}; + +template struct make_unsigned_or_unchanged { + using type = typename std::make_unsigned::type; +}; + +template ::value)> +inline auto get_milliseconds(std::chrono::duration d) + -> std::chrono::duration { + // this may overflow and/or the result may not fit in the + // target type. +#if FMT_SAFE_DURATION_CAST + using CommonSecondsType = + typename std::common_type::type; + const auto d_as_common = fmt_duration_cast(d); + const auto d_as_whole_seconds = + fmt_duration_cast(d_as_common); + // this conversion should be nonproblematic + const auto diff = d_as_common - d_as_whole_seconds; + const auto ms = + fmt_duration_cast>(diff); + return ms; +#else + auto s = fmt_duration_cast(d); + return fmt_duration_cast(d - s); +#endif +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int) -> OutputIt { + return write(out, val); +} + +template ::value)> +auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt { + auto specs = format_specs(); + specs.precision = precision; + specs.type = + precision >= 0 ? presentation_type::fixed : presentation_type::general; + return write(out, val, specs); +} + +template +auto copy_unit(string_view unit, OutputIt out, Char) -> OutputIt { + return std::copy(unit.begin(), unit.end(), out); +} + +template +auto copy_unit(string_view unit, OutputIt out, wchar_t) -> OutputIt { + // This works when wchar_t is UTF-32 because units only contain characters + // that have the same representation in UTF-16 and UTF-32. + utf8_to_utf16 u(unit); + return std::copy(u.c_str(), u.c_str() + u.size(), out); +} + +template +auto format_duration_unit(OutputIt out) -> OutputIt { + if (const char* unit = get_units()) + return copy_unit(string_view(unit), out, Char()); + *out++ = '['; + out = write(out, Period::num); + if (const_check(Period::den != 1)) { + *out++ = '/'; + out = write(out, Period::den); + } + *out++ = ']'; + *out++ = 's'; + return out; +} + +class get_locale { + private: + union { + std::locale locale_; + }; + bool has_locale_ = false; + + public: + get_locale(bool localized, locale_ref loc) : has_locale_(localized) { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR + if (localized) + ::new (&locale_) std::locale(loc.template get()); +#endif + } + ~get_locale() { + if (has_locale_) locale_.~locale(); + } + operator const std::locale&() const { + return has_locale_ ? locale_ : get_classic_locale(); + } +}; + +template +struct chrono_formatter { + FormatContext& context; + OutputIt out; + int precision; + bool localized = false; + // rep is unsigned to avoid overflow. + using rep = + conditional_t::value && sizeof(Rep) < sizeof(int), + unsigned, typename make_unsigned_or_unchanged::type>; + rep val; + using seconds = std::chrono::duration; + seconds s; + using milliseconds = std::chrono::duration; + bool negative; + + using char_type = typename FormatContext::char_type; + using tm_writer_type = tm_writer; + + chrono_formatter(FormatContext& ctx, OutputIt o, + std::chrono::duration d) + : context(ctx), + out(o), + val(static_cast(d.count())), + negative(false) { + if (d.count() < 0) { + val = 0 - val; + negative = true; + } + + // this may overflow and/or the result may not fit in the + // target type. + // might need checked conversion (rep!=Rep) + s = fmt_duration_cast(std::chrono::duration(val)); + } + + // returns true if nan or inf, writes to out. + auto handle_nan_inf() -> bool { + if (isfinite(val)) { + return false; + } + if (isnan(val)) { + write_nan(); + return true; + } + // must be +-inf + if (val > 0) { + write_pinf(); + } else { + write_ninf(); + } + return true; + } + + auto days() const -> Rep { return static_cast(s.count() / 86400); } + auto hour() const -> Rep { + return static_cast(mod((s.count() / 3600), 24)); + } + + auto hour12() const -> Rep { + Rep hour = static_cast(mod((s.count() / 3600), 12)); + return hour <= 0 ? 12 : hour; + } + + auto minute() const -> Rep { + return static_cast(mod((s.count() / 60), 60)); + } + auto second() const -> Rep { return static_cast(mod(s.count(), 60)); } + + auto time() const -> std::tm { + auto time = std::tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + time.tm_min = to_nonnegative_int(minute(), 60); + time.tm_sec = to_nonnegative_int(second(), 60); + return time; + } + + void write_sign() { + if (negative) { + *out++ = '-'; + negative = false; + } + } + + void write(Rep value, int width, pad_type pad = pad_type::zero) { + write_sign(); + if (isnan(value)) return write_nan(); + uint32_or_64_or_128_t n = + to_unsigned(to_nonnegative_int(value, max_value())); + int num_digits = detail::count_digits(n); + if (width > num_digits) { + out = detail::write_padding(out, pad, width - num_digits); + } + out = format_decimal(out, n, num_digits).end; + } + + void write_nan() { std::copy_n("nan", 3, out); } + void write_pinf() { std::copy_n("inf", 3, out); } + void write_ninf() { std::copy_n("-inf", 4, out); } + + template + void format_tm(const tm& time, Callback cb, Args... args) { + if (isnan(val)) return write_nan(); + get_locale loc(localized, context.locale()); + auto w = tm_writer_type(loc, out, time); + (w.*cb)(args...); + out = w.out(); + } + + void on_text(const char_type* begin, const char_type* end) { + std::copy(begin, end, out); + } + + // These are not implemented because durations don't have date information. + void on_abbr_weekday() {} + void on_full_weekday() {} + void on_dec0_weekday(numeric_system) {} + void on_dec1_weekday(numeric_system) {} + void on_abbr_month() {} + void on_full_month() {} + void on_datetime(numeric_system) {} + void on_loc_date(numeric_system) {} + void on_loc_time(numeric_system) {} + void on_us_date() {} + void on_iso_date() {} + void on_utc_offset(numeric_system) {} + void on_tz_name() {} + void on_year(numeric_system) {} + void on_short_year(numeric_system) {} + void on_offset_year() {} + void on_century(numeric_system) {} + void on_iso_week_based_year() {} + void on_iso_week_based_short_year() {} + void on_dec_month(numeric_system) {} + void on_dec0_week_of_year(numeric_system, pad_type) {} + void on_dec1_week_of_year(numeric_system, pad_type) {} + void on_iso_week_of_year(numeric_system, pad_type) {} + void on_day_of_month(numeric_system, pad_type) {} + + void on_day_of_year() { + if (handle_nan_inf()) return; + write(days(), 0); + } + + void on_24_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour(), 24); + format_tm(time, &tm_writer_type::on_24_hour, ns, pad); + } + + void on_12_hour(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(hour12(), 2, pad); + auto time = tm(); + time.tm_hour = to_nonnegative_int(hour12(), 12); + format_tm(time, &tm_writer_type::on_12_hour, ns, pad); + } + + void on_minute(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) return write(minute(), 2, pad); + auto time = tm(); + time.tm_min = to_nonnegative_int(minute(), 60); + format_tm(time, &tm_writer_type::on_minute, ns, pad); + } + + void on_second(numeric_system ns, pad_type pad) { + if (handle_nan_inf()) return; + + if (ns == numeric_system::standard) { + if (std::is_floating_point::value) { + auto buf = memory_buffer(); + write_floating_seconds(buf, std::chrono::duration(val), + precision); + if (negative) *out++ = '-'; + if (buf.size() < 2 || buf[1] == '.') { + out = detail::write_padding(out, pad); + } + out = std::copy(buf.begin(), buf.end(), out); + } else { + write(second(), 2, pad); + write_fractional_seconds( + out, std::chrono::duration(val), precision); + } + return; + } + auto time = tm(); + time.tm_sec = to_nonnegative_int(second(), 60); + format_tm(time, &tm_writer_type::on_second, ns, pad); + } + + void on_12_hour_time() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_12_hour_time); + } + + void on_24_hour_time() { + if (handle_nan_inf()) { + *out++ = ':'; + handle_nan_inf(); + return; + } + + write(hour(), 2); + *out++ = ':'; + write(minute(), 2); + } + + void on_iso_time() { + on_24_hour_time(); + *out++ = ':'; + if (handle_nan_inf()) return; + on_second(numeric_system::standard, pad_type::zero); + } + + void on_am_pm() { + if (handle_nan_inf()) return; + format_tm(time(), &tm_writer_type::on_am_pm); + } + + void on_duration_value() { + if (handle_nan_inf()) return; + write_sign(); + out = format_duration_value(out, val, precision); + } + + void on_duration_unit() { + out = format_duration_unit(out); + } +}; + +} // namespace detail + +#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 +using weekday = std::chrono::weekday; +using day = std::chrono::day; +using month = std::chrono::month; +using year = std::chrono::year; +using year_month_day = std::chrono::year_month_day; +#else +// A fallback version of weekday. +class weekday { + private: + unsigned char value_; + + public: + weekday() = default; + constexpr explicit weekday(unsigned wd) noexcept + : value_(static_cast(wd != 7 ? wd : 0)) {} + constexpr auto c_encoding() const noexcept -> unsigned { return value_; } +}; + +class day { + private: + unsigned char value_; + + public: + day() = default; + constexpr explicit day(unsigned d) noexcept + : value_(static_cast(d)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; + +class month { + private: + unsigned char value_; + + public: + month() = default; + constexpr explicit month(unsigned m) noexcept + : value_(static_cast(m)) {} + constexpr explicit operator unsigned() const noexcept { return value_; } +}; + +class year { + private: + int value_; + + public: + year() = default; + constexpr explicit year(int y) noexcept : value_(y) {} + constexpr explicit operator int() const noexcept { return value_; } +}; + +class year_month_day { + private: + fmt::year year_; + fmt::month month_; + fmt::day day_; + + public: + year_month_day() = default; + constexpr year_month_day(const year& y, const month& m, const day& d) noexcept + : year_(y), month_(m), day_(d) {} + constexpr auto year() const noexcept -> fmt::year { return year_; } + constexpr auto month() const noexcept -> fmt::month { return month_; } + constexpr auto day() const noexcept -> fmt::day { return day_; } +}; +#endif + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; + } + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(localized_, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_weekday(); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(day d, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mday = static_cast(static_cast(d)); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_day_of_month(detail::numeric_system::standard, detail::pad_type::zero); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool localized_ = false; + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it != end && *it == 'L') { + ++it; + localized_ = true; + return it; + } + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(month m, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_mon = static_cast(static_cast(m)) - 1; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(localized_, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_abbr_month(); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(year y, FormatContext& ctx) const -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(y) - 1900; + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(false, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_year(detail::numeric_system::standard); + return w.out(); + } +}; + +template +struct formatter : private formatter { + private: + bool use_tm_formatter_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + use_tm_formatter_ = it != end && *it != '}'; + return use_tm_formatter_ ? formatter::parse(ctx) : it; + } + + template + auto format(year_month_day val, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto time = std::tm(); + time.tm_year = static_cast(val.year()) - 1900; + time.tm_mon = static_cast(static_cast(val.month())) - 1; + time.tm_mday = static_cast(static_cast(val.day())); + if (use_tm_formatter_) return formatter::format(time, ctx); + detail::get_locale loc(true, ctx.locale()); + auto w = detail::tm_writer(loc, ctx.out(), time); + w.on_iso_date(); + return w.out(); + } +}; + +template +struct formatter, Char> { + private: + format_specs specs_; + detail::arg_ref width_ref_; + detail::arg_ref precision_ref_; + bool localized_ = false; + basic_string_view format_str_; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + auto checker = detail::chrono_format_checker(); + if (*it == '.') { + checker.has_precision_integral = !std::is_floating_point::value; + it = detail::parse_precision(it, end, specs_.precision, precision_ref_, + ctx); + } + if (it != end && *it == 'L') { + localized_ = true; + ++it; + } + end = detail::parse_chrono_format(it, end, checker); + format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(std::chrono::duration d, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + auto precision = specs.precision; + specs.precision = -1; + auto begin = format_str_.begin(), end = format_str_.end(); + // As a possible future optimization, we could avoid extra copying if width + // is not specified. + auto buf = basic_memory_buffer(); + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + detail::handle_dynamic_spec(precision, + precision_ref_, ctx); + if (begin == end || *begin == '}') { + out = detail::format_duration_value(out, d.count(), precision); + detail::format_duration_unit(out); + } else { + using chrono_formatter = + detail::chrono_formatter; + auto f = chrono_formatter(ctx, out, d); + f.precision = precision; + f.localized = localized_; + detail::parse_chrono_format(begin, end, f); + } + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } +}; + +template +struct formatter, + Char> : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + std::tm tm = gmtime(val); + using period = typename Duration::period; + if (detail::const_check( + period::num == 1 && period::den == 1 && + !std::is_floating_point::value)) { + return formatter::format(tm, ctx); + } + Duration epoch = val.time_since_epoch(); + Duration subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + if (subsecs.count() < 0) { + auto second = + detail::fmt_duration_cast(std::chrono::seconds(1)); + if (tm.tm_sec != 0) + --tm.tm_sec; + else + tm = gmtime(val - second); + subsecs += detail::fmt_duration_cast(std::chrono::seconds(1)); + } + return formatter::do_format(tm, ctx, &subsecs); + } +}; + +#if FMT_USE_LOCAL_TIME +template +struct formatter, Char> + : formatter { + FMT_CONSTEXPR formatter() { + this->format_str_ = detail::string_literal{}; + } + + template + auto format(std::chrono::local_time val, FormatContext& ctx) const + -> decltype(ctx.out()) { + using period = typename Duration::period; + if (period::num != 1 || period::den != 1 || + std::is_floating_point::value) { + const auto epoch = val.time_since_epoch(); + const auto subsecs = detail::fmt_duration_cast( + epoch - detail::fmt_duration_cast(epoch)); + + return formatter::do_format(localtime(val), ctx, &subsecs); + } + + return formatter::format(localtime(val), ctx); + } +}; +#endif + +#if FMT_USE_UTC_TIME +template +struct formatter, + Char> + : formatter, + Char> { + template + auto format(std::chrono::time_point val, + FormatContext& ctx) const -> decltype(ctx.out()) { + return formatter< + std::chrono::time_point, + Char>::format(std::chrono::utc_clock::to_sys(val), ctx); + } +}; +#endif + +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + + protected: + basic_string_view format_str_; + + template + auto do_format(const std::tm& tm, FormatContext& ctx, + const Duration* subsecs) const -> decltype(ctx.out()) { + auto specs = specs_; + auto buf = basic_memory_buffer(); + auto out = std::back_inserter(buf); + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + + auto loc_ref = ctx.locale(); + detail::get_locale loc(static_cast(loc_ref), loc_ref); + auto w = + detail::tm_writer(loc, out, tm, subsecs); + detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w); + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it == end) return it; + + end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); + // Replace the default format_str only if the new spec is not empty. + if (end != it) format_str_ = {it, detail::to_unsigned(end - it)}; + return end; + } + + template + auto format(const std::tm& tm, FormatContext& ctx) const + -> decltype(ctx.out()) { + return do_format(tm, ctx, nullptr); + } +}; + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_CHRONO_H_ diff --git a/cpp_src/vendor/fmt/color.h b/cpp_src/vendor/fmt/color.h new file mode 100644 index 000000000..f0e9dd94e --- /dev/null +++ b/cpp_src/vendor/fmt/color.h @@ -0,0 +1,612 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32 // rgb(154,205,50) +}; // enum class color + +enum class terminal_color : uint8_t { + black = 30, + red, + green, + yellow, + blue, + magenta, + cyan, + white, + bright_black = 90, + bright_red, + bright_green, + bright_yellow, + bright_blue, + bright_magenta, + bright_cyan, + bright_white +}; + +enum class emphasis : uint8_t { + bold = 1, + faint = 1 << 1, + italic = 1 << 2, + underline = 1 << 3, + blink = 1 << 4, + reverse = 1 << 5, + conceal = 1 << 6, + strikethrough = 1 << 7, +}; + +// rgb is a struct for red, green and blue colors. +// Using the name "rgb" makes some editors show the color in a tooltip. +struct rgb { + FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} + FMT_CONSTEXPR rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), + g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +namespace detail { + +// color is a struct of either a rgb color or a terminal color. +struct color_type { + FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} + FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { + value.rgb_color = static_cast(rgb_color); + } + FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { + value.rgb_color = (static_cast(rgb_color.r) << 16) | + (static_cast(rgb_color.g) << 8) | rgb_color.b; + } + FMT_CONSTEXPR color_type(terminal_color term_color) noexcept + : is_rgb(), value{} { + value.term_color = static_cast(term_color); + } + bool is_rgb; + union color_union { + uint8_t term_color; + uint32_t rgb_color; + } value; +}; +} // namespace detail + +/// A text style consisting of foreground and background colors and emphasis. +class text_style { + public: + FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept + : set_foreground_color(), set_background_color(), ems(em) {} + + FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { + if (!set_foreground_color) { + set_foreground_color = rhs.set_foreground_color; + foreground_color = rhs.foreground_color; + } else if (rhs.set_foreground_color) { + if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) + report_error("can't OR a terminal color"); + foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; + } + + if (!set_background_color) { + set_background_color = rhs.set_background_color; + background_color = rhs.background_color; + } else if (rhs.set_background_color) { + if (!background_color.is_rgb || !rhs.background_color.is_rgb) + report_error("can't OR a terminal color"); + background_color.value.rgb_color |= rhs.background_color.value.rgb_color; + } + + ems = static_cast(static_cast(ems) | + static_cast(rhs.ems)); + return *this; + } + + friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs) + -> text_style { + return lhs |= rhs; + } + + FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { + return set_foreground_color; + } + FMT_CONSTEXPR auto has_background() const noexcept -> bool { + return set_background_color; + } + FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { + return static_cast(ems) != 0; + } + FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { + FMT_ASSERT(has_foreground(), "no foreground specified for this style"); + return foreground_color; + } + FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { + FMT_ASSERT(has_background(), "no background specified for this style"); + return background_color; + } + FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { + FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); + return ems; + } + + private: + FMT_CONSTEXPR text_style(bool is_foreground, + detail::color_type text_color) noexcept + : set_foreground_color(), set_background_color(), ems() { + if (is_foreground) { + foreground_color = text_color; + set_foreground_color = true; + } else { + background_color = text_color; + set_background_color = true; + } + } + + friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept + -> text_style; + + friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept + -> text_style; + + detail::color_type foreground_color; + detail::color_type background_color; + bool set_foreground_color; + bool set_background_color; + emphasis ems; +}; + +/// Creates a text style from the foreground (text) color. +FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept + -> text_style { + return text_style(true, foreground); +} + +/// Creates a text style from the background color. +FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept + -> text_style { + return text_style(false, background); +} + +FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept + -> text_style { + return text_style(lhs) | rhs; +} + +namespace detail { + +template struct ansi_color_escape { + FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, + const char* esc) noexcept { + // If we have a terminal color, we need to output another escape code + // sequence. + if (!text_color.is_rgb) { + bool is_background = esc == string_view("\x1b[48;2;"); + uint32_t value = text_color.value.term_color; + // Background ASCII codes are the same as the foreground ones but with + // 10 more. + if (is_background) value += 10u; + + size_t index = 0; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + + if (value >= 100u) { + buffer[index++] = static_cast('1'); + value %= 100u; + } + buffer[index++] = static_cast('0' + value / 10u); + buffer[index++] = static_cast('0' + value % 10u); + + buffer[index++] = static_cast('m'); + buffer[index++] = static_cast('\0'); + return; + } + + for (int i = 0; i < 7; i++) { + buffer[i] = static_cast(esc[i]); + } + rgb color(text_color.value.rgb_color); + to_esc(color.r, buffer + 7, ';'); + to_esc(color.g, buffer + 11, ';'); + to_esc(color.b, buffer + 15, 'm'); + buffer[19] = static_cast(0); + } + FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { + uint8_t em_codes[num_emphases] = {}; + if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; + if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; + if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; + if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; + if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; + if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; + if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; + if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; + + size_t index = 0; + for (size_t i = 0; i < num_emphases; ++i) { + if (!em_codes[i]) continue; + buffer[index++] = static_cast('\x1b'); + buffer[index++] = static_cast('['); + buffer[index++] = static_cast('0' + em_codes[i]); + buffer[index++] = static_cast('m'); + } + buffer[index++] = static_cast(0); + } + FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } + + FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } + FMT_CONSTEXPR20 auto end() const noexcept -> const Char* { + return buffer + basic_string_view(buffer).size(); + } + + private: + static constexpr size_t num_emphases = 8; + Char buffer[7u + 3u * num_emphases + 1u]; + + static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, + char delimiter) noexcept { + out[0] = static_cast('0' + c / 100); + out[1] = static_cast('0' + c / 10 % 10); + out[2] = static_cast('0' + c % 10); + out[3] = static_cast(delimiter); + } + static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept + -> bool { + return static_cast(em) & static_cast(mask); + } +}; + +template +FMT_CONSTEXPR auto make_foreground_color(detail::color_type foreground) noexcept + -> ansi_color_escape { + return ansi_color_escape(foreground, "\x1b[38;2;"); +} + +template +FMT_CONSTEXPR auto make_background_color(detail::color_type background) noexcept + -> ansi_color_escape { + return ansi_color_escape(background, "\x1b[48;2;"); +} + +template +FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept + -> ansi_color_escape { + return ansi_color_escape(em); +} + +template inline void reset_color(buffer& buffer) { + auto reset_color = string_view("\x1b[0m"); + buffer.append(reset_color.begin(), reset_color.end()); +} + +template struct styled_arg : detail::view { + const T& value; + text_style style; + styled_arg(const T& v, text_style s) : value(v), style(s) {} +}; + +template +void vformat_to( + buffer& buf, const text_style& ts, basic_string_view format_str, + basic_format_args>> args) { + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + buf.append(emphasis.begin(), emphasis.end()); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = detail::make_foreground_color(ts.get_foreground()); + buf.append(foreground.begin(), foreground.end()); + } + if (ts.has_background()) { + has_style = true; + auto background = detail::make_background_color(ts.get_background()); + buf.append(background.begin(), background.end()); + } + detail::vformat_to(buf, format_str, args, {}); + if (has_style) detail::reset_color(buf); +} + +} // namespace detail + +inline void vprint(FILE* f, const text_style& ts, string_view fmt, + format_args args) { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size())); +} + +/** + * Formats a string and prints it to the specified file stream using ANSI + * escape sequences to specify text formatting. + * + * **Example**: + * + * fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + * "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +void print(FILE* f, const text_style& ts, format_string fmt, + T&&... args) { + vprint(f, ts, fmt, fmt::make_format_args(args...)); +} + +/** + * Formats a string and prints it to stdout using ANSI escape sequences to + * specify text formatting. + * + * **Example**: + * + * fmt::print(fmt::emphasis::bold | fg(fmt::color::red), + * "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +void print(const text_style& ts, format_string fmt, T&&... args) { + return print(stdout, ts, fmt, std::forward(args)...); +} + +inline auto vformat(const text_style& ts, string_view fmt, format_args args) + -> std::string { + auto buf = memory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + return fmt::to_string(buf); +} + +/** + * Formats arguments and returns the result as a string using ANSI escape + * sequences to specify text formatting. + * + * **Example**: + * + * ``` + * #include + * std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), + * "The answer is {}", 42); + * ``` + */ +template +inline auto format(const text_style& ts, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(ts, fmt, fmt::make_format_args(args...)); +} + +/// Formats a string with the given text_style and writes the output to `out`. +template ::value)> +auto vformat_to(OutputIt out, const text_style& ts, string_view fmt, + format_args args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, ts, fmt, args); + return detail::get_iterator(buf, out); +} + +/** + * Formats arguments with the given text style, writes the result to the output + * iterator `out` and returns the iterator past the end of the output range. + * + * **Example**: + * + * std::vector out; + * fmt::format_to(std::back_inserter(out), + * fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); + */ +template ::value)> +inline auto format_to(OutputIt out, const text_style& ts, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, ts, fmt, fmt::make_format_args(args...)); +} + +template +struct formatter, Char> : formatter { + template + auto format(const detail::styled_arg& arg, FormatContext& ctx) const + -> decltype(ctx.out()) { + const auto& ts = arg.style; + const auto& value = arg.value; + auto out = ctx.out(); + + bool has_style = false; + if (ts.has_emphasis()) { + has_style = true; + auto emphasis = detail::make_emphasis(ts.get_emphasis()); + out = std::copy(emphasis.begin(), emphasis.end(), out); + } + if (ts.has_foreground()) { + has_style = true; + auto foreground = + detail::make_foreground_color(ts.get_foreground()); + out = std::copy(foreground.begin(), foreground.end(), out); + } + if (ts.has_background()) { + has_style = true; + auto background = + detail::make_background_color(ts.get_background()); + out = std::copy(background.begin(), background.end(), out); + } + out = formatter::format(value, ctx); + if (has_style) { + auto reset_color = string_view("\x1b[0m"); + out = std::copy(reset_color.begin(), reset_color.end(), out); + } + return out; + } +}; + +/** + * Returns an argument that will be formatted using ANSI escape sequences, + * to be used in a formatting function. + * + * **Example**: + * + * fmt::print("Elapsed time: {0:.2f} seconds", + * fmt::styled(1.23, fmt::fg(fmt::color::green) | + * fmt::bg(fmt::color::blue))); + */ +template +FMT_CONSTEXPR auto styled(const T& value, text_style ts) + -> detail::styled_arg> { + return detail::styled_arg>{value, ts}; +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/cpp_src/vendor/fmt/compile.h b/cpp_src/vendor/fmt/compile.h new file mode 100644 index 000000000..b2afc2c30 --- /dev/null +++ b/cpp_src/vendor/fmt/compile.h @@ -0,0 +1,529 @@ +// Formatting library for C++ - experimental format string compilation +// +// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COMPILE_H_ +#define FMT_COMPILE_H_ + +#ifndef FMT_MODULE +# include // std::back_inserter +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +// A compile-time string which is compiled into fast formatting code. +FMT_EXPORT class compiled_string {}; + +namespace detail { + +template +FMT_CONSTEXPR inline auto copy(InputIt begin, InputIt end, counting_iterator it) + -> counting_iterator { + return it + (end - begin); +} + +template +struct is_compiled_string : std::is_base_of {}; + +/** + * Converts a string literal `s` into a format string that will be parsed at + * compile time and converted into efficient formatting code. Requires C++17 + * `constexpr if` compiler support. + * + * **Example**: + * + * // Converts 42 into std::string using the most efficient method and no + * // runtime format string processing. + * std::string s = fmt::format(FMT_COMPILE("{}"), 42); + */ +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string, explicit) +#else +# define FMT_COMPILE(s) FMT_STRING(s) +#endif + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct udl_compiled_string : compiled_string { + using char_type = Char; + explicit constexpr operator basic_string_view() const { + return {Str.data, N - 1}; + } +}; +#endif + +template +auto first(const T& value, const Tail&...) -> const T& { + return value; +} + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +template struct type_list {}; + +// Returns a reference to the argument at index N from [first, rest...]. +template +constexpr const auto& get([[maybe_unused]] const T& first, + [[maybe_unused]] const Args&... rest) { + static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); + if constexpr (N == 0) + return first; + else + return detail::get(rest...); +} + +template +constexpr int get_arg_index_by_name(basic_string_view name, + type_list) { + return get_arg_index_by_name(name); +} + +template struct get_type_impl; + +template struct get_type_impl> { + using type = + remove_cvref_t(std::declval()...))>; +}; + +template +using get_type = typename get_type_impl::type; + +template struct is_compiled_format : std::false_type {}; + +template struct text { + basic_string_view data; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + return write(out, data); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr text make_text(basic_string_view s, size_t pos, + size_t size) { + return {{&s[pos], size}}; +} + +template struct code_unit { + Char value; + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&...) const { + *out++ = value; + return out; + } +}; + +// This ensures that the argument type is convertible to `const T&`. +template +constexpr const T& get_arg_checked(const Args&... args) { + const auto& arg = detail::get(args...); + if constexpr (detail::is_named_arg>()) { + return arg.value; + } else { + return arg; + } +} + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N. +template struct field { + using char_type = Char; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + const T& arg = get_arg_checked(args...); + if constexpr (std::is_convertible>::value) { + auto s = basic_string_view(arg); + return copy(s.begin(), s.end(), out); + } + return write(out, arg); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument with name. +template struct runtime_named_field { + using char_type = Char; + basic_string_view name; + + template + constexpr static bool try_format_argument( + OutputIt& out, + // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 + [[maybe_unused]] basic_string_view arg_name, const T& arg) { + if constexpr (is_named_arg::type>::value) { + if (arg_name == arg.name) { + out = write(out, arg.value); + return true; + } + } + return false; + } + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + bool found = (try_format_argument(out, name, args) || ...); + if (!found) { + FMT_THROW(format_error("argument with specified name is not found")); + } + return out; + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +// A replacement field that refers to argument N and has format specifiers. +template struct spec_field { + using char_type = Char; + formatter fmt; + + template + constexpr FMT_INLINE OutputIt format(OutputIt out, + const Args&... args) const { + const auto& vargs = + fmt::make_format_args>(args...); + basic_format_context ctx(out, vargs); + return fmt.format(get_arg_checked(args...), ctx); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template struct concat { + L lhs; + R rhs; + using char_type = typename L::char_type; + + template + constexpr OutputIt format(OutputIt out, const Args&... args) const { + out = lhs.format(out, args...); + return rhs.format(out, args...); + } +}; + +template +struct is_compiled_format> : std::true_type {}; + +template +constexpr concat make_concat(L lhs, R rhs) { + return {lhs, rhs}; +} + +struct unknown_format {}; + +template +constexpr size_t parse_text(basic_string_view str, size_t pos) { + for (size_t size = str.size(); pos != size; ++pos) { + if (str[pos] == '{' || str[pos] == '}') break; + } + return pos; +} + +template +constexpr auto compile_format_string(S fmt); + +template +constexpr auto parse_tail(T head, S fmt) { + if constexpr (POS != basic_string_view(fmt).size()) { + constexpr auto tail = compile_format_string(fmt); + if constexpr (std::is_same, + unknown_format>()) + return tail; + else + return make_concat(head, tail); + } else { + return head; + } +} + +template struct parse_specs_result { + formatter fmt; + size_t end; + int next_arg_id; +}; + +enum { manual_indexing_id = -1 }; + +template +constexpr parse_specs_result parse_specs(basic_string_view str, + size_t pos, int next_arg_id) { + str.remove_prefix(pos); + auto ctx = + compile_parse_context(str, max_value(), nullptr, next_arg_id); + auto f = formatter(); + auto end = f.parse(ctx); + return {f, pos + fmt::detail::to_unsigned(end - str.data()), + next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; +} + +template struct arg_id_handler { + arg_ref arg_id; + + constexpr int on_auto() { + FMT_ASSERT(false, "handler cannot be used with automatic indexing"); + return 0; + } + constexpr int on_index(int id) { + arg_id = arg_ref(id); + return 0; + } + constexpr int on_name(basic_string_view id) { + arg_id = arg_ref(id); + return 0; + } +}; + +template struct parse_arg_id_result { + arg_ref arg_id; + const Char* arg_id_end; +}; + +template +constexpr auto parse_arg_id(const Char* begin, const Char* end) { + auto handler = arg_id_handler{arg_ref{}}; + auto arg_id_end = parse_arg_id(begin, end, handler); + return parse_arg_id_result{handler.arg_id, arg_id_end}; +} + +template struct field_type { + using type = remove_cvref_t; +}; + +template +struct field_type::value>> { + using type = remove_cvref_t; +}; + +template +constexpr auto parse_replacement_field_then_tail(S fmt) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(fmt); + constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); + if constexpr (c == '}') { + return parse_tail( + field::type, ARG_INDEX>(), fmt); + } else if constexpr (c != ':') { + FMT_THROW(format_error("expected ':'")); + } else { + constexpr auto result = parse_specs::type>( + str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); + if constexpr (result.end >= str.size() || str[result.end] != '}') { + FMT_THROW(format_error("expected '}'")); + return 0; + } else { + return parse_tail( + spec_field::type, ARG_INDEX>{ + result.fmt}, + fmt); + } + } +} + +// Compiles a non-empty format string and returns the compiled representation +// or unknown_format() on unrecognized input. +template +constexpr auto compile_format_string(S fmt) { + using char_type = typename S::char_type; + constexpr auto str = basic_string_view(fmt); + if constexpr (str[POS] == '{') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '{' in format string")); + if constexpr (str[POS + 1] == '{') { + return parse_tail(make_text(str, POS, 1), fmt); + } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { + static_assert(ID != manual_indexing_id, + "cannot switch from manual to automatic argument indexing"); + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail, Args, + POS + 1, ID, next_id>(fmt); + } else { + constexpr auto arg_id_result = + parse_arg_id(str.data() + POS + 1, str.data() + str.size()); + constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); + constexpr char_type c = + arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); + static_assert(c == '}' || c == ':', "missing '}' in format string"); + if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { + static_assert( + ID == manual_indexing_id || ID == 0, + "cannot switch from automatic to manual argument indexing"); + constexpr auto arg_index = arg_id_result.arg_id.val.index; + return parse_replacement_field_then_tail, + Args, arg_id_end_pos, + arg_index, manual_indexing_id>( + fmt); + } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { + constexpr auto arg_index = + get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); + if constexpr (arg_index >= 0) { + constexpr auto next_id = + ID != manual_indexing_id ? ID + 1 : manual_indexing_id; + return parse_replacement_field_then_tail< + decltype(get_type::value), Args, arg_id_end_pos, + arg_index, next_id>(fmt); + } else if constexpr (c == '}') { + return parse_tail( + runtime_named_field{arg_id_result.arg_id.val.name}, + fmt); + } else if constexpr (c == ':') { + return unknown_format(); // no type info for specs parsing + } + } + } + } else if constexpr (str[POS] == '}') { + if constexpr (POS + 1 == str.size()) + FMT_THROW(format_error("unmatched '}' in format string")); + return parse_tail(make_text(str, POS, 1), fmt); + } else { + constexpr auto end = parse_text(str, POS + 1); + if constexpr (end - POS > 1) { + return parse_tail(make_text(str, POS, end - POS), fmt); + } else { + return parse_tail(code_unit{str[POS]}, fmt); + } + } +} + +template ::value)> +constexpr auto compile(S fmt) { + constexpr auto str = basic_string_view(fmt); + if constexpr (str.size() == 0) { + return detail::make_text(str, 0, 0); + } else { + constexpr auto result = + detail::compile_format_string, 0, 0>(fmt); + return result; + } +} +#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +} // namespace detail + +FMT_BEGIN_EXPORT + +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) + +template ::value)> +FMT_INLINE std::basic_string format(const CompiledFormat& cf, + const Args&... args) { + auto s = std::basic_string(); + cf.format(std::back_inserter(s), args...); + return s; +} + +template ::value)> +constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, + const Args&... args) { + return cf.format(out, args...); +} + +template ::value)> +FMT_INLINE std::basic_string format(const S&, + Args&&... args) { + if constexpr (std::is_same::value) { + constexpr auto str = basic_string_view(S()); + if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { + const auto& first = detail::first(args...); + if constexpr (detail::is_named_arg< + remove_cvref_t>::value) { + return fmt::to_string(first.value); + } else { + return fmt::to_string(first); + } + } + } + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format( + static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format(compiled, std::forward(args)...); + } +} + +template ::value)> +FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { + constexpr auto compiled = detail::compile(S()); + if constexpr (std::is_same, + detail::unknown_format>()) { + return fmt::format_to( + out, static_cast>(S()), + std::forward(args)...); + } else { + return fmt::format_to(out, compiled, std::forward(args)...); + } +} +#endif + +template ::value)> +auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + fmt::format_to(std::back_inserter(buf), fmt, std::forward(args)...); + return {buf.out(), buf.count()}; +} + +template ::value)> +FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) + -> size_t { + return fmt::format_to(detail::counting_iterator(), fmt, args...).count(); +} + +template ::value)> +void print(std::FILE* f, const S& fmt, const Args&... args) { + memory_buffer buffer; + fmt::format_to(std::back_inserter(buffer), fmt, args...); + detail::print(f, {buffer.data(), buffer.size()}); +} + +template ::value)> +void print(const S& fmt, const Args&... args) { + print(stdout, fmt, args...); +} + +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +inline namespace literals { +template constexpr auto operator""_cf() { + using char_t = remove_cvref_t; + return detail::udl_compiled_string(); +} +} // namespace literals +#endif + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_COMPILE_H_ diff --git a/cpp_src/vendor/fmt/core.h b/cpp_src/vendor/fmt/core.h new file mode 100644 index 000000000..8ca735f0c --- /dev/null +++ b/cpp_src/vendor/fmt/core.h @@ -0,0 +1,5 @@ +// This file is only provided for compatibility and may be removed in future +// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h +// otherwise. + +#include "format.h" diff --git a/cpp_src/vendor/fmt/format-inl.h b/cpp_src/vendor/fmt/format-inl.h new file mode 100644 index 000000000..a887483b6 --- /dev/null +++ b/cpp_src/vendor/fmt/format-inl.h @@ -0,0 +1,1928 @@ +// Formatting library for C++ - implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#ifndef FMT_MODULE +# include +# include // errno +# include +# include +# include + +# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include +# endif +#endif + +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) +# include // _isatty +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +FMT_FUNC void assert_fail(const char* file, int line, const char* message) { + // Use unchecked std::fprintf to avoid triggering another assertion when + // writing to stderr fails + std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + // Chosen instead of std::abort to satisfy Clang in CUDA mode during device + // code pass. + std::terminate(); +} + +FMT_FUNC void format_error_code(detail::buffer& out, int error_code, + string_view message) noexcept { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.try_resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + auto abs_value = static_cast>(error_code); + if (detail::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); + auto it = appender(out); + if (message.size() <= inline_buffer_size - error_code_size) + fmt::format_to(it, FMT_STRING("{}{}"), message, SEP); + fmt::format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); + FMT_ASSERT(out.size() <= inline_buffer_size, ""); +} + +FMT_FUNC void report_error(format_func func, int error_code, + const char* message) noexcept { + memory_buffer full_message; + func(full_message, error_code, message); + // Don't use fwrite_fully because the latter may throw. + if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) + std::fputc('\n', stderr); +} + +// A wrapper around fwrite that throws on error. +inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) { + size_t written = std::fwrite(ptr, 1, count, stream); + if (written < count) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template +locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { + static_assert(std::is_same::value, ""); +} + +template auto locale_ref::get() const -> Locale { + static_assert(std::is_same::value, ""); + return locale_ ? *static_cast(locale_) : std::locale(); +} + +template +FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { + auto& facet = std::use_facet>(loc.get()); + auto grouping = facet.grouping(); + auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); + return {std::move(grouping), thousands_sep}; +} +template +FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char { + return std::use_facet>(loc.get()) + .decimal_point(); +} +#else +template +FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { + return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; +} +template FMT_FUNC Char decimal_point_impl(locale_ref) { + return '.'; +} +#endif + +FMT_FUNC auto write_loc(appender out, loc_value value, + const format_specs& specs, locale_ref loc) -> bool { +#ifdef FMT_STATIC_THOUSANDS_SEPARATOR + value.visit(loc_writer<>{ + out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."}); + return true; +#else + auto locale = loc.get(); + // We cannot use the num_put facet because it may produce output in + // a wrong encoding. + using facet = format_facet; + if (std::has_facet(locale)) + return std::use_facet(locale).put(out, value, specs); + return facet(locale).put(out, value, specs); +#endif +} +} // namespace detail + +FMT_FUNC void report_error(const char* message) { + FMT_THROW(format_error(message)); +} + +template typename Locale::id format_facet::id; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template format_facet::format_facet(Locale& loc) { + auto& numpunct = std::use_facet>(loc); + grouping_ = numpunct.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); +} + +template <> +FMT_API FMT_FUNC auto format_facet::do_put( + appender out, loc_value val, const format_specs& specs) const -> bool { + return val.visit( + detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); +} +#endif + +FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args) + -> std::system_error { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, vformat(fmt, args)); +} + +namespace detail { + +template +inline auto operator==(basic_fp x, basic_fp y) -> bool { + return x.f == y.f && x.e == y.e; +} + +// Compilers should be able to optimize this into the ror instruction. +FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t { + r &= 31; + return (n >> r) | (n << (32 - r)); +} +FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t { + r &= 63; + return (n >> r) | (n << (64 - r)); +} + +// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. +namespace dragonbox { +// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return umul128_upper64(static_cast(x) << 32, y); +} + +// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint64_t high = x * y.high(); + uint128_fallback high_low = umul128(x, y.low()); + return {high + high_low.high(), high_low.low()}; +} + +// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a +// 64-bit unsigned integer. +inline auto umul96_lower64(uint32_t x, uint64_t y) noexcept -> uint64_t { + return x * y; +} + +// Various fast log computations. +inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int { + FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); + return (e * 631305 - 261663) >> 21; +} + +FMT_INLINE_VARIABLE constexpr struct { + uint32_t divisor; + int shift_amount; +} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; + +// Replaces n by floor(n / pow(10, N)) returning true if and only if n is +// divisible by pow(10, N). +// Precondition: n <= pow(10, N + 1). +template +auto check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept -> bool { + // The numbers below are chosen such that: + // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, + // 2. nm mod 2^k < m if and only if n is divisible by d, + // where m is magic_number, k is shift_amount + // and d is divisor. + // + // Item 1 is a common technique of replacing division by a constant with + // multiplication, see e.g. "Division by Invariant Integers Using + // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set + // to ceil(2^k/d) for large enough k. + // The idea for item 2 originates from Schubfach. + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + n *= magic_number; + const uint32_t comparison_mask = (1u << info.shift_amount) - 1; + bool result = (n & comparison_mask) < magic_number; + n >>= info.shift_amount; + return result; +} + +// Computes floor(n / pow(10, N)) for small n and N. +// Precondition: n <= pow(10, N + 1). +template auto small_division_by_pow10(uint32_t n) noexcept -> uint32_t { + constexpr auto info = div_small_pow10_infos[N - 1]; + FMT_ASSERT(n <= info.divisor * 10, "n is too large"); + constexpr uint32_t magic_number = + (1u << info.shift_amount) / info.divisor + 1; + return (n * magic_number) >> info.shift_amount; +} + +// Computes floor(n / 10^(kappa + 1)) (float) +inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t { + // 1374389535 = ceil(2^37/100) + return static_cast((static_cast(n) * 1374389535) >> 37); +} +// Computes floor(n / 10^(kappa + 1)) (double) +inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t { + // 2361183241434822607 = ceil(2^(64+7)/1000) + return umul128_upper64(n, 2361183241434822607ull) >> 7; +} + +// Various subroutines using pow10 cache +template struct cache_accessor; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint64_t; + + static auto get_cached_power(int k) noexcept -> uint64_t { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + static constexpr const uint64_t pow10_significands[] = { + 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, + 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, + 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, + 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, + 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, + 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, + 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, + 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, + 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, + 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, + 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, + 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, + 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, + 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, + 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, + 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, + 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, + 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, + 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, + 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, + 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, + 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, + 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, + 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, + 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, + 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; + return pow10_significands[k - float_info::min_k]; + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul96_upper64(u, cache); + return {static_cast(r >> 32), + static_cast(r) == 0}; + } + + static auto compute_delta(const cache_entry_type& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul96_lower64(two_f, cache); + return {((r >> (64 - beta)) & 1) != 0, + static_cast(r >> (32 - beta)) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return static_cast( + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (static_cast( + cache >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +template <> struct cache_accessor { + using carrier_uint = float_info::carrier_uint; + using cache_entry_type = uint128_fallback; + + static auto get_cached_power(int k) noexcept -> uint128_fallback { + FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, + "k is out of range"); + + static constexpr const uint128_fallback pow10_significands[] = { +#if FMT_USE_FULL_CACHE_DRAGONBOX + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0x9faacf3df73609b1, 0x77b191618c54e9ad}, + {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, + {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, + {0x9becce62836ac577, 0x4ee367f9430aec33}, + {0xc2e801fb244576d5, 0x229c41f793cda740}, + {0xf3a20279ed56d48a, 0x6b43527578c11110}, + {0x9845418c345644d6, 0x830a13896b78aaaa}, + {0xbe5691ef416bd60c, 0x23cc986bc656d554}, + {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, + {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, + {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, + {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, + {0x91376c36d99995be, 0x23100809b9c21fa2}, + {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, + {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, + {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, + {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, + {0xdd95317f31c7fa1d, 0x40405643d711d584}, + {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, + {0xad1c8eab5ee43b66, 0xda3243650005eed0}, + {0xd863b256369d4a40, 0x90bed43e40076a83}, + {0x873e4f75e2224e68, 0x5a7744a6e804a292}, + {0xa90de3535aaae202, 0x711515d0a205cb37}, + {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, + {0x8412d9991ed58091, 0xe858790afe9486c3}, + {0xa5178fff668ae0b6, 0x626e974dbe39a873}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, + {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, + {0xc987434744ac874e, 0xa327ffb266b56221}, + {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, + {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, + {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, + {0xf6019da07f549b2b, 0x7e2a53a146606a49}, + {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, + {0xc0314325637a1939, 0xfa911155fefb5309}, + {0xf03d93eebc589f88, 0x793555ab7eba27cb}, + {0x96267c7535b763b5, 0x4bc1558b2f3458df}, + {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, + {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, + {0x92a1958a7675175f, 0x0bfacd89ec191eca}, + {0xb749faed14125d36, 0xcef980ec671f667c}, + {0xe51c79a85916f484, 0x82b7e12780e7401b}, + {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, + {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, + {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, + {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, + {0xaecc49914078536d, 0x58fae9f773886e19}, + {0xda7f5bf590966848, 0xaf39a475506a899f}, + {0x888f99797a5e012d, 0x6d8406c952429604}, + {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, + {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, + {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0xd0601d8efc57b08b, 0xf13b94daf124da27}, + {0x823c12795db6ce57, 0x76c53d08d6b70859}, + {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, + {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, + {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, + {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, + {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, + {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, + {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, + {0xc21094364dfb5636, 0x985915fc12f542e5}, + {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, + {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, + {0xbd8430bd08277231, 0x50c6ff782a838354}, + {0xece53cec4a314ebd, 0xa4f8bf5635246429}, + {0x940f4613ae5ed136, 0x871b7795e136be9a}, + {0xb913179899f68584, 0x28e2557b59846e40}, + {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, + {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, + {0xb4bca50b065abe63, 0x0fed077a756b53aa}, + {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, + {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, + {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, + {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, + {0x89e42caaf9491b60, 0xf41686c49db57245}, + {0xac5d37d5b79b6239, 0x311c2875c522ced6}, + {0xd77485cb25823ac7, 0x7d633293366b828c}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, + {0xd267caa862a12d66, 0xd072df63c324fd7c}, + {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, + {0xa46116538d0deb78, 0x52d9be85f074e609}, + {0xcd795be870516656, 0x67902e276c921f8c}, + {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, + {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, + {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, + {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, + {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, + {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, + {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, + {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, + {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, + {0xef340a98172aace4, 0x86fb897116c87c35}, + {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, + {0xbae0a846d2195712, 0x8974836059cca10a}, + {0xe998d258869facd7, 0x2bd1a438703fc94c}, + {0x91ff83775423cc06, 0x7b6306a34627ddd0}, + {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, + {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, + {0x8e938662882af53e, 0x547eb47b7282ee9d}, + {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, + {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, + {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, + {0xae0b158b4738705e, 0x9624ab50b148d446}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, + {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, + {0xd47487cc8470652b, 0x7647c32000696720}, + {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, + {0xa5fb0a17c777cf09, 0xf468107100525891}, + {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, + {0x81ac1fe293d599bf, 0xc6f14cd848405531}, + {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, + {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, + {0xfd442e4688bd304a, 0x908f4a166d1da664}, + {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, + {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, + {0xf7549530e188c128, 0xd12bee59e68ef47d}, + {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, + {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, + {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, + {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, + {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, + {0xebdf661791d60f56, 0x111b495b3464ad22}, + {0x936b9fcebb25c995, 0xcab10dd900beec35}, + {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, + {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, + {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, + {0xb3f4e093db73a093, 0x59ed216765690f57}, + {0xe0f218b8d25088b8, 0x306869c13ec3532d}, + {0x8c974f7383725573, 0x1e414218c73a13fc}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, + {0x894bc396ce5da772, 0x6b8bba8c328eb784}, + {0xab9eb47c81f5114f, 0x066ea92f3f326565}, + {0xd686619ba27255a2, 0xc80a537b0efefebe}, + {0x8613fd0145877585, 0xbd06742ce95f5f37}, + {0xa798fc4196e952e7, 0x2c48113823b73705}, + {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, + {0x82ef85133de648c4, 0x9a984d73dbe722fc}, + {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, + {0xcc963fee10b7d1b3, 0x318df905079926a9}, + {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, + {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, + {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, + {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, + {0x9c1661a651213e2d, 0x06bea10ca65c084f}, + {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, + {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, + {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, + {0xbe89523386091465, 0xf6bbb397f1135824}, + {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, + {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, + {0xba121a4650e4ddeb, 0x92f34d62616ce414}, + {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, + {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, + {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, + {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, + {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, + {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, + {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, + {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, + {0x87625f056c7c4a8b, 0x11471cd764ad4973}, + {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, + {0xd389b47879823479, 0x4aff1d108d4ec2c4}, + {0x843610cb4bf160cb, 0xcedf722a585139bb}, + {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, + {0xce947a3da6a9273e, 0x733d226229feea33}, + {0x811ccc668829b887, 0x0806357d5a3f5260}, + {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, + {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, + {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, + {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, + {0xc5029163f384a931, 0x0a9e795e65d4df12}, + {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, + {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, + {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, + {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, + {0x964e858c91ba2655, 0x3a6a07f8d510f870}, + {0xbbe226efb628afea, 0x890489f70a55368c}, + {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, + {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, + {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, + {0xb32df8e9f3546564, 0x47939822dc96abfa}, + {0xdff9772470297ebd, 0x59787e2b93bc56f8}, + {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, + {0xaefae51477a06b03, 0xede622920b6b23f2}, + {0xdab99e59958885c4, 0xe95fab368e45ecee}, + {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, + {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, + {0xd59944a37c0752a2, 0x4be76d3346f04960}, + {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, + {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, + {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, + {0x825ecc24c873782f, 0x8ed400668c0c28c9}, + {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, + {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, + {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, + {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, + {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, + {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, + {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, + {0xc24452da229b021b, 0xfbe85badce996169}, + {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, + {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, + {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, + {0xed246723473e3813, 0x290123e9aab23b69}, + {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, + {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, + {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, + {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, + {0x8d590723948a535f, 0x579c487e5a38ad0f}, + {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, + {0xdcdb1b2798182244, 0xf8e431456cf88e66}, + {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, + {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, + {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, + {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, + {0xa87fea27a539e9a5, 0x3f2398d747b36225}, + {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, + {0x83a3eeeef9153e89, 0x1953cf68300424ad}, + {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, + {0xcdb02555653131b6, 0x3792f412cb06794e}, + {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, + {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, + {0xc8de047564d20a8b, 0xf245825a5a445276}, + {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, + {0x9ced737bb6c4183d, 0x55464dd69685606c}, + {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, + {0xf53304714d9265df, 0xd53dd99f4b3066a9}, + {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, + {0xbf8fdb78849a5f96, 0xde98520472bdd034}, + {0xef73d256a5c0f77c, 0x963e66858f6d4441}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xbb127c53b17ec159, 0x5560c018580d5d53}, + {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, + {0x9226712162ab070d, 0xcab3961304ca70e9}, + {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, + {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, + {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, + {0xb267ed1940f1c61c, 0x55f038b237591ed4}, + {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, + {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, + {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, + {0xd9c7dced53c72255, 0x96e7bd358c904a22}, + {0x881cea14545c7575, 0x7e50d64177da2e55}, + {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, + {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, + {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, + {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, + {0xcfb11ead453994ba, 0x67de18eda5814af3}, + {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, + {0xa2425ff75e14fc31, 0xa1258379a94d028e}, + {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, + {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, + {0x9e74d1b791e07e48, 0x775ea264cf55347e}, + {0xc612062576589dda, 0x95364afe032a819e}, + {0xf79687aed3eec551, 0x3a83ddbd83f52205}, + {0x9abe14cd44753b52, 0xc4926a9672793543}, + {0xc16d9a0095928a27, 0x75b7053c0f178294}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, + {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, + {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, + {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, + {0xb877aa3236a4b449, 0x09befeb9fad487c3}, + {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, + {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, + {0xb424dc35095cd80f, 0x538484c19ef38c95}, + {0xe12e13424bb40e13, 0x2865a5f206b06fba}, + {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, + {0xafebff0bcb24aafe, 0xf78f69a51539d749}, + {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, + {0x89705f4136b4a597, 0x31680a88f8953031}, + {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, + {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, + {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, + {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, + {0xd1b71758e219652b, 0xd3c36113404ea4a9}, + {0x83126e978d4fdf3b, 0x645a1cac083126ea}, + {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, + {0xcccccccccccccccc, 0xcccccccccccccccd}, + {0x8000000000000000, 0x0000000000000000}, + {0xa000000000000000, 0x0000000000000000}, + {0xc800000000000000, 0x0000000000000000}, + {0xfa00000000000000, 0x0000000000000000}, + {0x9c40000000000000, 0x0000000000000000}, + {0xc350000000000000, 0x0000000000000000}, + {0xf424000000000000, 0x0000000000000000}, + {0x9896800000000000, 0x0000000000000000}, + {0xbebc200000000000, 0x0000000000000000}, + {0xee6b280000000000, 0x0000000000000000}, + {0x9502f90000000000, 0x0000000000000000}, + {0xba43b74000000000, 0x0000000000000000}, + {0xe8d4a51000000000, 0x0000000000000000}, + {0x9184e72a00000000, 0x0000000000000000}, + {0xb5e620f480000000, 0x0000000000000000}, + {0xe35fa931a0000000, 0x0000000000000000}, + {0x8e1bc9bf04000000, 0x0000000000000000}, + {0xb1a2bc2ec5000000, 0x0000000000000000}, + {0xde0b6b3a76400000, 0x0000000000000000}, + {0x8ac7230489e80000, 0x0000000000000000}, + {0xad78ebc5ac620000, 0x0000000000000000}, + {0xd8d726b7177a8000, 0x0000000000000000}, + {0x878678326eac9000, 0x0000000000000000}, + {0xa968163f0a57b400, 0x0000000000000000}, + {0xd3c21bcecceda100, 0x0000000000000000}, + {0x84595161401484a0, 0x0000000000000000}, + {0xa56fa5b99019a5c8, 0x0000000000000000}, + {0xcecb8f27f4200f3a, 0x0000000000000000}, + {0x813f3978f8940984, 0x4000000000000000}, + {0xa18f07d736b90be5, 0x5000000000000000}, + {0xc9f2c9cd04674ede, 0xa400000000000000}, + {0xfc6f7c4045812296, 0x4d00000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xc5371912364ce305, 0x6c28000000000000}, + {0xf684df56c3e01bc6, 0xc732000000000000}, + {0x9a130b963a6c115c, 0x3c7f400000000000}, + {0xc097ce7bc90715b3, 0x4b9f100000000000}, + {0xf0bdc21abb48db20, 0x1e86d40000000000}, + {0x96769950b50d88f4, 0x1314448000000000}, + {0xbc143fa4e250eb31, 0x17d955a000000000}, + {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, + {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, + {0xb7abc627050305ad, 0xf14a3d9e40000000}, + {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, + {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, + {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, + {0xe0352f62a19e306e, 0xd50b2037ad200000}, + {0x8c213d9da502de45, 0x4526f422cc340000}, + {0xaf298d050e4395d6, 0x9670b12b7f410000}, + {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, + {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, + {0xab0e93b6efee0053, 0x8eea0d047a457a00}, + {0xd5d238a4abe98068, 0x72a4904598d6d880}, + {0x85a36366eb71f041, 0x47a6da2b7f864750}, + {0xa70c3c40a64e6c51, 0x999090b65f67d924}, + {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, + {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, + {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, + {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0x9f4f2726179a2245, 0x01d762422c946591}, + {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, + {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, + {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, + {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, + {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, + {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, + {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, + {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, + {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, + {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, + {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, + {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, + {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, + {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, + {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, + {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, + {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, + {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, + {0xacb92ed9397bf996, 0x49c2c37f07965405}, + {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, + {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, + {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, + {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, + {0x83c7088e1aab65db, 0x792667c6da79e0fb}, + {0xa4b8cab1a1563f52, 0x577001b891185939}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0x80b05e5ac60b6178, 0x544f8158315b05b5}, + {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, + {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, + {0xfb5878494ace3a5f, 0x04ab48a04065c724}, + {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, + {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, + {0xf5746577930d6500, 0xca8f44ec7ee3647a}, + {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, + {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, + {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, + {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, + {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, + {0xea1575143cf97226, 0xf52d09d71a3293be}, + {0x924d692ca61be758, 0x593c2626705f9c57}, + {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, + {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, + {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, + {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, + {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, + {0x8b865b215899f46c, 0xbd79e0d20082ee75}, + {0xae67f1e9aec07187, 0xecd8590680a3aa12}, + {0xda01ee641a708de9, 0xe80e6f4820cc9496}, + {0x884134fe908658b2, 0x3109058d147fdcde}, + {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, + {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, + {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0xcfe87f7cef46ff16, 0xe612641865679a64}, + {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, + {0xa26da3999aef7749, 0xe3be5e330f38f09e}, + {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, + {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, + {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, + {0xc646d63501a1511d, 0xb281e1fd541501b9}, + {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, + {0x9ae757596946075f, 0x3375788de9b06959}, + {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, + {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, + {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, + {0xbd176620a501fbff, 0xb650e5a93bc3d899}, + {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, + {0x93ba47c980e98cdf, 0xc66f336c36b10138}, + {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, + {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, + {0x9043ea1ac7e41392, 0x87c89837ad68db30}, + {0xb454e4a179dd1877, 0x29babe4598c311fc}, + {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, + {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, + {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, + {0xdc21a1171d42645d, 0x76707543f4fa1f74}, + {0x899504ae72497eba, 0x6a06494a791c53a9}, + {0xabfa45da0edbde69, 0x0487db9d17636893}, + {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xa7f26836f282b732, 0x8e6cac7768d7141f}, + {0xd1ef0244af2364ff, 0x3207d795430cd927}, + {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, + {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, + {0xcd036837130890a1, 0x36dba887c37a8c10}, + {0x802221226be55a64, 0xc2494954da2c978a}, + {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, + {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, + {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, + {0x9c69a97284b578d7, 0xff2a760414536efc}, + {0xc38413cf25e2d70d, 0xfef5138519684abb}, + {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, + {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, + {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, + {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, + {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, + {0xba756174393d88df, 0x94f971119aeef9e5}, + {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, + {0x91abb422ccb812ee, 0xac62e055c10ab33b}, + {0xb616a12b7fe617aa, 0x577b986b314d600a}, + {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, + {0x8e41ade9fbebc27d, 0x14588f13be847308}, + {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, + {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, + {0x8aec23d680043bee, 0x25de7bb9480d5855}, + {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0x87aa9aff79042286, 0x90fb44d2f05d0843}, + {0xa99541bf57452b28, 0x353a1607ac744a54}, + {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, + {0x847c9b5d7c2e09b7, 0x69956135febada12}, + {0xa59bc234db398c25, 0x43fab9837e699096}, + {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, + {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, + {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, + {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, + {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, + {0x9defbf01b061adab, 0x3a0888136afa64a8}, + {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, + {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, + {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, + {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, + {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, + {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, + {0xbc4665b596706114, 0x873d5d9f0dde1fef}, + {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, + {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, + {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, + {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, + {0x8fa475791a569d10, 0xf96e017d694487bd}, + {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, + {0xe070f78d3927556a, 0x85bbe253f47b1418}, + {0x8c469ab843b89562, 0x93956d7478ccec8f}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, + {0x88fcf317f22241e2, 0x441fece3bdf81f04}, + {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, + {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, + {0x85c7056562757456, 0xf6872d5667844e4a}, + {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, + {0xd106f86e69d785c7, 0xe13336d701beba53}, + {0x82a45b450226b39c, 0xecc0024661173474}, + {0xa34d721642b06084, 0x27f002d7f95d0191}, + {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, + {0xff290242c83396ce, 0x7e67047175a15272}, + {0x9f79a169bd203e41, 0x0f0062c6e984d387}, + {0xc75809c42c684dd1, 0x52c07b78a3e60869}, + {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, + {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, + {0xc2abf989935ddbfe, 0x6acff893d00ea436}, + {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, + {0x98165af37b2153de, 0xc3727a337a8b704b}, + {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, + {0xeda2ee1c7064130c, 0x1162def06f79df74}, + {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, + {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, + {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, + {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, + {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, + {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xb10d8e1456105dad, 0x7425a83e872c5f48}, + {0xdd50f1996b947518, 0xd12f124e28f7771a}, + {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, + {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, + {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, + {0x8714a775e3e95c78, 0x65acfaec34810a72}, + {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, + {0xd31045a8341ca07c, 0x1ede48111209a051}, + {0x83ea2b892091e44d, 0x934aed0aab460433}, + {0xa4e4b66b68b65d60, 0xf81da84d56178540}, + {0xce1de40642e3f4b9, 0x36251260ab9d668f}, + {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, + {0xa1075a24e4421730, 0xb24cf65b8612f820}, + {0xc94930ae1d529cfc, 0xdee033f26797b628}, + {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, + {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, + {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, + {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, + {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, + {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, + {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, + {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, + {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, + {0xea53df5fd18d5513, 0x84c86189216dc5ee}, + {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, + {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, + {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, + {0xdf78e4b2bd342cf6, 0x914da9246b255417}, + {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, + {0xae9672aba3d0c320, 0xa184ac2473b529b2}, + {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, + {0x8865899617fb1871, 0x7e2fa67c7a658893}, + {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, + {0xd51ea6fa85785631, 0x552a74227f3ea566}, + {0x8533285c936b35de, 0xd53a88958f872760}, + {0xa67ff273b8460356, 0x8a892abaf368f138}, + {0xd01fef10a657842c, 0x2d2b7569b0432d86}, + {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, + {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, + {0xcb3f2f7642717713, 0x241c70a936219a74}, + {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, + {0x9ec95d1463e8a506, 0xf4363804324a40ab}, + {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, + {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, + {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, + {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, + {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, + {0x976e41088617ca01, 0xd5be0503e085d814}, + {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, + {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, + {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, + {0x906a617d450187e2, 0x27fb2b80668b24c6}, + {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, + {0xe1a63853bbd26451, 0x5e7873f8a0396974}, + {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, + {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, + {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, + {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, + {0xac2820d9623bf429, 0x546345fa9fbdcd45}, + {0xd732290fbacaf133, 0xa97c177947ad4096}, + {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, + {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, + {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, + {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, + {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, + {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, + {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, + {0xa0555e361951c366, 0xd7e105bcc3326220}, + {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, + {0xfa856334878fc150, 0xb14f98f6f0feb952}, + {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, + {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, + {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, + {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, + {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, + {0xeeea5d5004981478, 0x1858ccfce06cac75}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xbaa718e68396cffd, 0xd30560258f54e6bb}, + {0xe950df20247c83fd, 0x47c6b82ef32a206a}, + {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, + {0xb6472e511c81471d, 0xe0133fe4adf8e953}, + {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, + {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, + {0xb201833b35d63f73, 0x2cd2cc6551e513db}, + {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, + {0x8b112e86420f6191, 0xfb04afaf27faf783}, + {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, + {0xd94ad8b1c7380874, 0x18375281ae7822bd}, + {0x87cec76f1c830548, 0x8f2293910d0b15b6}, + {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, + {0xd433179d9c8cb841, 0x5fa60692a46151ec}, + {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, + {0xa5c7ea73224deff3, 0x12b9b522906c0801}, + {0xcf39e50feae16bef, 0xd768226b34870a01}, + {0x81842f29f2cce375, 0xe6a1158300d46641}, + {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, + {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, + {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, + {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, + {0xc5a05277621be293, 0xc7098b7305241886}, + {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}, + {0x9a65406d44a5c903, 0x737f74f1dc043329}, + {0xc0fe908895cf3b44, 0x505f522e53053ff3}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0}, + {0x96c6e0eab509e64d, 0x5eca783430dc19f6}, + {0xbc789925624c5fe0, 0xb67d16413d132073}, + {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890}, + {0x933e37a534cbaae7, 0x8e91b962f7b6f15a}, + {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1}, + {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d}, + {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2}, + {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e}, + {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, + {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, + {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, + {0xdb68c2ca82ed2a05, 0xa67398db9f6820e2}, +#else + {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, + {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, + {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, + {0x86a8d39ef77164bc, 0xae5dff9c02033198}, + {0xd98ddaee19068c76, 0x3badd624dd9b0958}, + {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, + {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, + {0xe55990879ddcaabd, 0xcc420a6a101d0516}, + {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, + {0x95a8637627989aad, 0xdde7001379a44aa9}, + {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, + {0xc350000000000000, 0x0000000000000000}, + {0x9dc5ada82b70b59d, 0xf020000000000000}, + {0xfee50b7025c36a08, 0x02f236d04753d5b5}, + {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, + {0xa6539930bf6bff45, 0x84db8346b786151d}, + {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, + {0xd910f7ff28069da4, 0x1b2ba1518094da05}, + {0xaf58416654a6babb, 0x387ac8d1970027b3}, + {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, + {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, + {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, + {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, + {0xf13e34aabb430a15, 0x647726b9e7c68ff0} +#endif + }; + +#if FMT_USE_FULL_CACHE_DRAGONBOX + return pow10_significands[k - float_info::min_k]; +#else + static constexpr const uint64_t powers_of_5_64[] = { + 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, + 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, + 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, + 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, + 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, + 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, + 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, + 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, + 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; + + static const int compression_ratio = 27; + + // Compute base index. + int cache_index = (k - float_info::min_k) / compression_ratio; + int kb = cache_index * compression_ratio + float_info::min_k; + int offset = k - kb; + + // Get base cache. + uint128_fallback base_cache = pow10_significands[cache_index]; + if (offset == 0) return base_cache; + + // Compute the required amount of bit-shift. + int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; + FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); + + // Try to recover the real cache. + uint64_t pow5 = powers_of_5_64[offset]; + uint128_fallback recovered_cache = umul128(base_cache.high(), pow5); + uint128_fallback middle_low = umul128(base_cache.low(), pow5); + + recovered_cache += middle_low.high(); + + uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); + uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); + + recovered_cache = + uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle, + ((middle_low.low() >> alpha) | middle_to_low)}; + FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); + return {recovered_cache.high(), recovered_cache.low() + 1}; +#endif + } + + struct compute_mul_result { + carrier_uint result; + bool is_integer; + }; + struct compute_mul_parity_result { + bool parity; + bool is_integer; + }; + + static auto compute_mul(carrier_uint u, + const cache_entry_type& cache) noexcept + -> compute_mul_result { + auto r = umul192_upper128(u, cache); + return {r.high(), r.low() == 0}; + } + + static auto compute_delta(cache_entry_type const& cache, int beta) noexcept + -> uint32_t { + return static_cast(cache.high() >> (64 - 1 - beta)); + } + + static auto compute_mul_parity(carrier_uint two_f, + const cache_entry_type& cache, + int beta) noexcept + -> compute_mul_parity_result { + FMT_ASSERT(beta >= 1, ""); + FMT_ASSERT(beta < 64, ""); + + auto r = umul192_lower128(two_f, cache); + return {((r.high() >> (64 - beta)) & 1) != 0, + ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; + } + + static auto compute_left_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() - + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_right_endpoint_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return (cache.high() + + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); + } + + static auto compute_round_up_for_shorter_interval_case( + const cache_entry_type& cache, int beta) noexcept -> carrier_uint { + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + + 1) / + 2; + } +}; + +FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback { + return cache_accessor::get_cached_power(k); +} + +// Various integer checks +template +auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool { + const int case_shorter_interval_left_endpoint_lower_threshold = 2; + const int case_shorter_interval_left_endpoint_upper_threshold = 3; + return exponent >= case_shorter_interval_left_endpoint_lower_threshold && + exponent <= case_shorter_interval_left_endpoint_upper_threshold; +} + +// Remove trailing zeros from n and return the number of zeros removed (float) +FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { + FMT_ASSERT(n != 0, ""); + // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1. + constexpr uint32_t mod_inv_5 = 0xcccccccd; + constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5 + + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + return s; +} + +// Removes trailing zeros and returns the number of zeros removed (double) +FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { + FMT_ASSERT(n != 0, ""); + + // This magic number is ceil(2^90 / 10^8). + constexpr uint64_t magic_number = 12379400392853802749ull; + auto nm = umul128(n, magic_number); + + // Is n is divisible by 10^8? + if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { + // If yes, work with the quotient... + auto n32 = static_cast(nm.high() >> (90 - 64)); + // ... and use the 32 bit variant of the function + int s = remove_trailing_zeros(n32, 8); + n = n32; + return s; + } + + // If n is not divisible by 10^8, work with n itself. + constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; + constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // mod_inv_5 * mod_inv_5 + + int s = 0; + while (true) { + auto q = rotr(n * mod_inv_25, 2); + if (q > max_value() / 100) break; + n = q; + s += 2; + } + auto q = rotr(n * mod_inv_5, 1); + if (q <= max_value() / 10) { + n = q; + s |= 1; + } + + return s; +} + +// The main algorithm for shorter interval case +template +FMT_INLINE decimal_fp shorter_interval_case(int exponent) noexcept { + decimal_fp ret_value; + // Compute k and beta + const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute xi and zi + using cache_entry_type = typename cache_accessor::cache_entry_type; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + + auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( + cache, beta); + auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( + cache, beta); + + // If the left endpoint is not an integer, increase it + if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; + + // Try bigger divisor + ret_value.significand = zi / 10; + + // If succeed, remove trailing zeros if necessary and return + if (ret_value.significand * 10 >= xi) { + ret_value.exponent = minus_k + 1; + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + } + + // Otherwise, compute the round-up of y + ret_value.significand = + cache_accessor::compute_round_up_for_shorter_interval_case(cache, + beta); + ret_value.exponent = minus_k; + + // When tie occurs, choose one of them according to the rule + if (exponent >= float_info::shorter_interval_tie_lower_threshold && + exponent <= float_info::shorter_interval_tie_upper_threshold) { + ret_value.significand = ret_value.significand % 2 == 0 + ? ret_value.significand + : ret_value.significand - 1; + } else if (ret_value.significand < xi) { + ++ret_value.significand; + } + return ret_value; +} + +template auto to_decimal(T x) noexcept -> decimal_fp { + // Step 1: integer promotion & Schubfach multiplier calculation. + + using carrier_uint = typename float_info::carrier_uint; + using cache_entry_type = typename cache_accessor::cache_entry_type; + auto br = bit_cast(x); + + // Extract significand bits and exponent bits. + const carrier_uint significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + carrier_uint significand = (br & significand_mask); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + + // Shorter interval case; proceed like Schubfach. + // In fact, when exponent == 1 and significand == 0, the interval is + // regular. However, it can be shown that the end-results are anyway same. + if (significand == 0) return shorter_interval_case(exponent); + + significand |= (static_cast(1) << num_significand_bits()); + } else { + // Subnormal case; the interval is always regular. + if (significand == 0) return {0, 0}; + exponent = + std::numeric_limits::min_exponent - num_significand_bits() - 1; + } + + const bool include_left_endpoint = (significand % 2 == 0); + const bool include_right_endpoint = include_left_endpoint; + + // Compute k and beta. + const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; + const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); + const int beta = exponent + floor_log2_pow10(-minus_k); + + // Compute zi and deltai. + // 10^kappa <= deltai < 10^(kappa + 1) + const uint32_t deltai = cache_accessor::compute_delta(cache, beta); + const carrier_uint two_fc = significand << 1; + + // For the case of binary32, the result of integer check is not correct for + // 29711844 * 2^-82 + // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 + // and 29711844 * 2^-81 + // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, + // and they are the unique counterexamples. However, since 29711844 is even, + // this does not cause any problem for the endpoints calculations; it can only + // cause a problem when we need to perform integer check for the center. + // Fortunately, with these inputs, that branch is never executed, so we are + // fine. + const typename cache_accessor::compute_mul_result z_mul = + cache_accessor::compute_mul((two_fc | 1) << beta, cache); + + // Step 2: Try larger divisor; remove trailing zeros if necessary. + + // Using an upper bound on zi, we might be able to optimize the division + // better than the compiler; we are computing zi / big_divisor here. + decimal_fp ret_value; + ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result); + uint32_t r = static_cast(z_mul.result - float_info::big_divisor * + ret_value.significand); + + if (r < deltai) { + // Exclude the right endpoint if necessary. + if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { + --ret_value.significand; + r = float_info::big_divisor; + goto small_divisor_case_label; + } + } else if (r > deltai) { + goto small_divisor_case_label; + } else { + // r == deltai; compare fractional parts. + const typename cache_accessor::compute_mul_parity_result x_mul = + cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); + + if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) + goto small_divisor_case_label; + } + ret_value.exponent = minus_k + float_info::kappa + 1; + + // We may need to remove trailing zeros. + ret_value.exponent += remove_trailing_zeros(ret_value.significand); + return ret_value; + + // Step 3: Find the significand with the smaller divisor. + +small_divisor_case_label: + ret_value.significand *= 10; + ret_value.exponent = minus_k + float_info::kappa; + + uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); + const bool approx_y_parity = + ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; + + // Is dist divisible by 10^kappa? + const bool divisible_by_small_divisor = + check_divisibility_and_divide_by_pow10::kappa>(dist); + + // Add dist / 10^kappa to the significand. + ret_value.significand += dist; + + if (!divisible_by_small_divisor) return ret_value; + + // Check z^(f) >= epsilon^(f). + // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, + // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). + // Since there are only 2 possibilities, we only need to care about the + // parity. Also, zi and r should have the same parity since the divisor + // is an even number. + const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); + + // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), + // or equivalently, when y is an integer. + if (y_mul.parity != approx_y_parity) + --ret_value.significand; + else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) + --ret_value.significand; + return ret_value; +} +} // namespace dragonbox +} // namespace detail + +template <> struct formatter { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) + -> format_parse_context::iterator { + return ctx.begin(); + } + + auto format(const detail::bigint& n, format_context& ctx) const + -> format_context::iterator { + auto out = ctx.out(); + bool first = true; + for (auto i = n.bigits_.size(); i > 0; --i) { + auto value = n.bigits_[i - 1u]; + if (first) { + out = fmt::format_to(out, FMT_STRING("{:x}"), value); + first = false; + continue; + } + out = fmt::format_to(out, FMT_STRING("{:08x}"), value); + } + if (n.exp_ > 0) + out = fmt::format_to(out, FMT_STRING("p{}"), + n.exp_ * detail::bigint::bigit_bits); + return out; + } +}; + +FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { + for_each_codepoint(s, [this](uint32_t cp, string_view) { + if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); + if (cp <= 0xFFFF) { + buffer_.push_back(static_cast(cp)); + } else { + cp -= 0x10000; + buffer_.push_back(static_cast(0xD800 + (cp >> 10))); + buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); + } + return true; + }); + buffer_.push_back(0); +} + +FMT_FUNC void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept { + FMT_TRY { + auto ec = std::error_code(error_code, std::generic_category()); + detail::write(appender(out), std::system_error(ec, message).what()); + return; + } + FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +FMT_FUNC void report_system_error(int error_code, + const char* message) noexcept { + report_error(format_system_error, error_code, message); +} + +FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { + // Don't optimize the "{}" case to keep the binary size small and because it + // can be better optimized in fmt::format anyway. + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + return to_string(buffer); +} + +namespace detail { + +template struct span { + T* data; + size_t size; +}; + +template auto flockfile(F* f) -> decltype(_lock_file(f)) { + _lock_file(f); +} +template auto funlockfile(F* f) -> decltype(_unlock_file(f)) { + _unlock_file(f); +} + +#ifndef getc_unlocked +template auto getc_unlocked(F* f) -> decltype(_fgetc_nolock(f)) { + return _fgetc_nolock(f); +} +#endif + +template +struct has_flockfile : std::false_type {}; + +template +struct has_flockfile()))>> + : std::true_type {}; + +// A FILE wrapper. F is FILE defined as a template parameter to make system API +// detection work. +template class file_base { + public: + F* file_; + + public: + file_base(F* file) : file_(file) {} + operator F*() const { return file_; } + + // Reads a code unit from the stream. + auto get() -> int { + int result = getc_unlocked(file_); + if (result == EOF && ferror(file_) != 0) + FMT_THROW(system_error(errno, FMT_STRING("getc failed"))); + return result; + } + + // Puts the code unit back into the stream buffer. + void unget(char c) { + if (ungetc(c, file_) == EOF) + FMT_THROW(system_error(errno, FMT_STRING("ungetc failed"))); + } + + void flush() { fflush(this->file_); } +}; + +// A FILE wrapper for glibc. +template class glibc_file : public file_base { + private: + enum { + line_buffered = 0x200, // _IO_LINE_BUF + unbuffered = 2 // _IO_UNBUFFERED + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; + } + + void init_buffer() { + if (this->file_->_IO_write_ptr) return; + // Force buffer initialization by placing and removing a char in a buffer. + putc_unlocked(0, this->file_); + --this->file_->_IO_write_ptr; + } + + // Returns the file's read buffer. + auto get_read_buffer() const -> span { + auto ptr = this->file_->_IO_read_ptr; + return {ptr, to_unsigned(this->file_->_IO_read_end - ptr)}; + } + + // Returns the file's write buffer. + auto get_write_buffer() const -> span { + auto ptr = this->file_->_IO_write_ptr; + return {ptr, to_unsigned(this->file_->_IO_buf_end - ptr)}; + } + + void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += size; } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + char* end = this->file_->_IO_write_end; + return memchr(end, '\n', to_unsigned(this->file_->_IO_write_ptr - end)); + } + + void flush() { fflush_unlocked(this->file_); } +}; + +// A FILE wrapper for Apple's libc. +template class apple_file : public file_base { + private: + enum { + line_buffered = 1, // __SNBF + unbuffered = 2 // __SLBF + }; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { + return (this->file_->_flags & unbuffered) == 0; + } + + void init_buffer() { + if (this->file_->_p) return; + // Force buffer initialization by placing and removing a char in a buffer. + putc_unlocked(0, this->file_); + --this->file_->_p; + ++this->file_->_w; + } + + auto get_read_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_r)}; + } + + auto get_write_buffer() const -> span { + return {reinterpret_cast(this->file_->_p), + to_unsigned(this->file_->_bf._base + this->file_->_bf._size - + this->file_->_p)}; + } + + void advance_write_buffer(size_t size) { + this->file_->_p += size; + this->file_->_w -= size; + } + + bool needs_flush() const { + if ((this->file_->_flags & line_buffered) == 0) return false; + return memchr(this->file_->_p + this->file_->_w, '\n', + to_unsigned(-this->file_->_w)); + } +}; + +// A fallback FILE wrapper. +template class fallback_file : public file_base { + private: + char next_; // The next unconsumed character in the buffer. + bool has_next_ = false; + + public: + using file_base::file_base; + + auto is_buffered() const -> bool { return false; } + auto needs_flush() const -> bool { return false; } + void init_buffer() {} + + auto get_read_buffer() const -> span { + return {&next_, has_next_ ? 1u : 0u}; + } + + auto get_write_buffer() const -> span { return {nullptr, 0}; } + + void advance_write_buffer(size_t) {} + + auto get() -> int { + has_next_ = false; + return file_base::get(); + } + + void unget(char c) { + file_base::unget(c); + next_ = c; + has_next_ = true; + } +}; + +#ifndef FMT_USE_FALLBACK_FILE +# define FMT_USE_FALLBACK_FILE 1 +#endif + +template +auto get_file(F* f, int) -> apple_file { + return f; +} +template +inline auto get_file(F* f, int) -> glibc_file { + return f; +} + +inline auto get_file(FILE* f, ...) -> fallback_file { return f; } + +using file_ref = decltype(get_file(static_cast(nullptr), 0)); + +template +class file_print_buffer : public buffer { + public: + explicit file_print_buffer(F*) : buffer(nullptr, size_t()) {} +}; + +template +class file_print_buffer::value>> + : public buffer { + private: + file_ref file_; + + static void grow(buffer& base, size_t) { + auto& self = static_cast(base); + self.file_.advance_write_buffer(self.size()); + if (self.file_.get_write_buffer().size == 0) self.file_.flush(); + auto buf = self.file_.get_write_buffer(); + FMT_ASSERT(buf.size > 0, ""); + self.set(buf.data, buf.size); + self.clear(); + } + + public: + explicit file_print_buffer(F* f) : buffer(grow, size_t()), file_(f) { + flockfile(f); + file_.init_buffer(); + auto buf = file_.get_write_buffer(); + set(buf.data, buf.size); + } + ~file_print_buffer() { + file_.advance_write_buffer(size()); + bool flush = file_.needs_flush(); + F* f = file_; // Make funlockfile depend on the template parameter F + funlockfile(f); // for the system API detection to work. + if (flush) fflush(file_); + } +}; + +#if !defined(_WIN32) || defined(FMT_USE_WRITE_CONSOLE) +FMT_FUNC auto write_console(int, string_view) -> bool { return false; } +#else +using dword = conditional_t; +extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // + void*, const void*, dword, dword*, void*); + +FMT_FUNC bool write_console(int fd, string_view text) { + auto u16 = utf8_to_utf16(text); + return WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), + static_cast(u16.size()), nullptr, nullptr) != 0; +} +#endif + +#ifdef _WIN32 +// Print assuming legacy (non-Unicode) encoding. +FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args, + bool newline) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + if (newline) buffer.push_back('\n'); + fwrite_fully(buffer.data(), buffer.size(), f); +} +#endif + +FMT_FUNC void print(std::FILE* f, string_view text) { +#if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) + int fd = _fileno(f); + if (_isatty(fd)) { + std::fflush(f); + if (write_console(fd, text)) return; + } +#endif + fwrite_fully(text.data(), text.size(), f); +} +} // namespace detail + +FMT_FUNC void vprint_buffered(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { + if (!detail::file_ref(f).is_buffered() || !detail::has_flockfile<>()) + return vprint_buffered(f, fmt, args); + auto&& buffer = detail::file_print_buffer<>(f); + return detail::vformat_to(buffer, fmt, args); +} + +FMT_FUNC void vprintln(std::FILE* f, string_view fmt, format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, fmt, args); + buffer.push_back('\n'); + detail::print(f, {buffer.data(), buffer.size()}); +} + +FMT_FUNC void vprint(string_view fmt, format_args args) { + vprint(stdout, fmt, args); +} + +namespace detail { + +struct singleton { + unsigned char upper; + unsigned char lower_count; +}; + +inline auto is_printable(uint16_t x, const singleton* singletons, + size_t singletons_size, + const unsigned char* singleton_lowers, + const unsigned char* normal, size_t normal_size) + -> bool { + auto upper = x >> 8; + auto lower_start = 0; + for (size_t i = 0; i < singletons_size; ++i) { + auto s = singletons[i]; + auto lower_end = lower_start + s.lower_count; + if (upper < s.upper) break; + if (upper == s.upper) { + for (auto j = lower_start; j < lower_end; ++j) { + if (singleton_lowers[j] == (x & 0xff)) return false; + } + } + lower_start = lower_end; + } + + auto xsigned = static_cast(x); + auto current = true; + for (size_t i = 0; i < normal_size; ++i) { + auto v = static_cast(normal[i]); + auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; + xsigned -= len; + if (xsigned < 0) break; + current = !current; + } + return current; +} + +// This code is generated by support/printable.py. +FMT_FUNC auto is_printable(uint32_t cp) -> bool { + static constexpr singleton singletons0[] = { + {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, + {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, + {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, + {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, + {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, + {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, + {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, + }; + static constexpr unsigned char singletons0_lower[] = { + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, + 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, + 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, + 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, + 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, + 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, + 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, + 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, + 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, + 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, + 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, + 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, + 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, + 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, + 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, + 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, + 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, + 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, + 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, + 0xfe, 0xff, + }; + static constexpr singleton singletons1[] = { + {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, + {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, + {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, + {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, + {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, + {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, + {0xfa, 2}, {0xfb, 1}, + }; + static constexpr unsigned char singletons1_lower[] = { + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, + 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, + 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, + 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, + 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, + 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, + 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, + 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, + 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, + 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, + }; + static constexpr unsigned char normal0[] = { + 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, + 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, + 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, + 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, + 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, + 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, + 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, + 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, + 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, + 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, + 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, + 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, + 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, + 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, + 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, + 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, + 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, + 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, + 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, + 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, + 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, + 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, + 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, + 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, + 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, + }; + static constexpr unsigned char normal1[] = { + 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, + 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, + 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, + 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, + 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, + 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, + 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, + 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, + 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, + 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, + 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, + 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, + 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, + 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, + 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, + 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, + 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, + 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, + 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, + 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, + 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, + 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, + 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, + 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, + 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, + 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, + 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, + 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, + 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, + 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, + 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, + 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, + 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, + 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, + }; + auto lower = static_cast(cp); + if (cp < 0x10000) { + return is_printable(lower, singletons0, + sizeof(singletons0) / sizeof(*singletons0), + singletons0_lower, normal0, sizeof(normal0)); + } + if (cp < 0x20000) { + return is_printable(lower, singletons1, + sizeof(singletons1) / sizeof(*singletons1), + singletons1_lower, normal1, sizeof(normal1)); + } + if (0x2a6de <= cp && cp < 0x2a700) return false; + if (0x2b735 <= cp && cp < 0x2b740) return false; + if (0x2b81e <= cp && cp < 0x2b820) return false; + if (0x2cea2 <= cp && cp < 0x2ceb0) return false; + if (0x2ebe1 <= cp && cp < 0x2f800) return false; + if (0x2fa1e <= cp && cp < 0x30000) return false; + if (0x3134b <= cp && cp < 0xe0100) return false; + if (0xe01f0 <= cp && cp < 0x110000) return false; + return cp < 0x110000; +} + +} // namespace detail + +FMT_END_NAMESPACE + +#endif // FMT_FORMAT_INL_H_ diff --git a/cpp_src/vendor/fmt/format.cc b/cpp_src/vendor/fmt/format.cc new file mode 100644 index 000000000..391d3a248 --- /dev/null +++ b/cpp_src/vendor/fmt/format.cc @@ -0,0 +1,43 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/format-inl.h" + +FMT_BEGIN_NAMESPACE +namespace detail { + +template FMT_API auto dragonbox::to_decimal(float x) noexcept + -> dragonbox::decimal_fp; +template FMT_API auto dragonbox::to_decimal(double x) noexcept + -> dragonbox::decimal_fp; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template FMT_API locale_ref::locale_ref(const std::locale& loc); +template FMT_API auto locale_ref::get() const -> std::locale; +#endif + +// Explicit instantiations for char. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> char; + +template FMT_API void buffer::append(const char*, const char*); + +template FMT_API void vformat_to(buffer&, string_view, + typename vformat_args<>::type, locale_ref); + +// Explicit instantiations for wchar_t. + +template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; + +template FMT_API void buffer::append(const wchar_t*, const wchar_t*); + +} // namespace detail +FMT_END_NAMESPACE diff --git a/cpp_src/vendor/fmt/format.h b/cpp_src/vendor/fmt/format.h new file mode 100644 index 000000000..46eda2ccf --- /dev/null +++ b/cpp_src/vendor/fmt/format.h @@ -0,0 +1,4449 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#ifndef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +# define FMT_REMOVE_TRANSITIVE_INCLUDES +#endif + +#include "base.h" + +#ifndef FMT_MODULE +# include // std::signbit +# include // uint32_t +# include // std::memcpy +# include // std::initializer_list +# include // std::numeric_limits +# if defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI) +// Workaround for pre gcc 5 libstdc++. +# include // std::allocator_traits +# endif +# include // std::runtime_error +# include // std::string +# include // std::system_error + +// Checking FMT_CPLUSPLUS for warning suppression in MSVC. +# if FMT_HAS_INCLUDE() && FMT_CPLUSPLUS > 201703L +# include // std::bit_cast +# endif + +// libc++ supports string_view in pre-c++17. +# if FMT_HAS_INCLUDE() && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# include +# define FMT_USE_STRING_VIEW +# endif +#endif // FMT_MODULE + +#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L +# define FMT_INLINE_VARIABLE inline +#else +# define FMT_INLINE_VARIABLE +#endif + +#ifndef FMT_NO_UNIQUE_ADDRESS +# if FMT_CPLUSPLUS >= 202002L +# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address) +# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] +// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485). +# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION +# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +# endif +# endif +#endif +#ifndef FMT_NO_UNIQUE_ADDRESS +# define FMT_NO_UNIQUE_ADDRESS +#endif + +// Visibility when compiled as a shared library/object. +#if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) +# define FMT_SO_VISIBILITY(value) FMT_VISIBILITY(value) +#else +# define FMT_SO_VISIBILITY(value) +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_NOINLINE __attribute__((noinline)) +#else +# define FMT_NOINLINE +#endif + +namespace std { +template <> struct iterator_traits { + using iterator_category = output_iterator_tag; + using value_type = char; +}; +} // namespace std + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VERSION || defined(__NVCC__) +FMT_BEGIN_NAMESPACE +namespace detail { +template inline void do_throw(const Exception& x) { + // Silence unreachable code warnings in MSVC and NVCC because these + // are nearly impossible to fix in a generic code. + volatile bool b = true; + if (b) throw x; +} +} // namespace detail +FMT_END_NAMESPACE +# define FMT_THROW(x) detail::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) \ + ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) +# endif +#endif + +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. +// +// GCC before 4.9 requires a space in `operator"" _a` which is invalid in later +// compiler versions. +# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 409 || \ + FMT_MSC_VERSION >= 1900) && \ + (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of +// integer formatter template instantiations to just one by only using the +// largest integer type. This results in a reduction in binary size but will +// cause a decrease in integer formatting performance. +#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) +# define FMT_REDUCE_INT_INSTANTIATIONS 0 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519. +#if !FMT_MSC_VERSION +# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// __builtin_ctz is broken in Intel Compiler Classic on Windows: +// https://github.com/fmtlib/fmt/issues/2510. +#ifndef __ICL +# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ + defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) +# endif +# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ + FMT_ICC_VERSION || defined(__NVCOMPILER) +# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) +# endif +#endif + +#if FMT_MSC_VERSION +# include // _BitScanReverse[64], _BitScanForward[64], _umul128 +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ + !defined(FMT_BUILTIN_CTZLL) +FMT_BEGIN_NAMESPACE +namespace detail { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# if !defined(__clang__) +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +# if defined(_WIN64) +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +# endif + +inline auto clz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanReverse(&r, x); + FMT_ASSERT(x != 0, ""); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. + FMT_MSC_WARNING(suppress : 6102) + return 31 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZ(n) detail::clz(n) + +inline auto clzll(uint64_t x) -> int { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 ^ static_cast(r + 32); + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return 63 ^ static_cast(r); +} +# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) + +inline auto ctz(uint32_t x) -> int { + unsigned long r = 0; + _BitScanForward(&r, x); + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. + return static_cast(r); +} +# define FMT_BUILTIN_CTZ(n) detail::ctz(n) + +inline auto ctzll(uint64_t x) -> int { + unsigned long r = 0; + FMT_ASSERT(x != 0, ""); + FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. +# ifdef _WIN64 + _BitScanForward64(&r, x); +# else + // Scan the low 32 bits. + if (_BitScanForward(&r, static_cast(x))) return static_cast(r); + // Scan the high 32 bits. + _BitScanForward(&r, static_cast(x >> 32)); + r += 32; +# endif + return static_cast(r); +} +# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) +} // namespace detail +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE + +template +struct is_contiguous> + : std::true_type {}; + +namespace detail { + +FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { + ignore_unused(condition); +#ifdef FMT_FUZZ + if (condition) throw std::runtime_error("fuzzing limit reached"); +#endif +} + +#if defined(FMT_USE_STRING_VIEW) +template using std_string_view = std::basic_string_view; +#else +template struct std_string_view {}; +#endif + +// Implementation of std::bit_cast for pre-C++20. +template +FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { +#ifdef __cpp_lib_bit_cast + if (is_constant_evaluated()) return std::bit_cast(from); +#endif + auto to = To(); + // The cast suppresses a bogus -Wclass-memaccess on GCC. + std::memcpy(static_cast(&to), &from, sizeof(to)); + return to; +} + +inline auto is_big_endian() -> bool { +#ifdef _WIN32 + return false; +#elif defined(__BIG_ENDIAN__) + return true; +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) + return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; +#else + struct bytes { + char data[sizeof(int)]; + }; + return bit_cast(1).data[0] == 0; +#endif +} + +class uint128_fallback { + private: + uint64_t lo_, hi_; + + public: + constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} + constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} + + constexpr auto high() const noexcept -> uint64_t { return hi_; } + constexpr auto low() const noexcept -> uint64_t { return lo_; } + + template ::value)> + constexpr explicit operator T() const { + return static_cast(lo_); + } + + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; + } + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return !(lhs == rhs); + } + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { + return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; + } + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; + } + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { + return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; + } + friend constexpr auto operator~(const uint128_fallback& n) + -> uint128_fallback { + return {~n.hi_, ~n.lo_}; + } + friend auto operator+(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> uint128_fallback { + auto result = uint128_fallback(lhs); + result += rhs; + return result; + } + friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) + -> uint128_fallback { + FMT_ASSERT(lhs.hi_ == 0, ""); + uint64_t hi = (lhs.lo_ >> 32) * rhs; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; + } + friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) + -> uint128_fallback { + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; + } + FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { + if (shift == 64) return {0, hi_}; + if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); + return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; + } + FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { + if (shift == 64) return {lo_, 0}; + if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); + return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; + } + FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { + return *this = *this >> shift; + } + FMT_CONSTEXPR void operator+=(uint128_fallback n) { + uint64_t new_lo = lo_ + n.lo_; + uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); + FMT_ASSERT(new_hi >= hi_, ""); + lo_ = new_lo; + hi_ = new_hi; + } + FMT_CONSTEXPR void operator&=(uint128_fallback n) { + lo_ &= n.lo_; + hi_ &= n.hi_; + } + + FMT_CONSTEXPR20 auto operator+=(uint64_t n) noexcept -> uint128_fallback& { + if (is_constant_evaluated()) { + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); + return *this; + } +#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) + unsigned long long carry; + lo_ = __builtin_addcll(lo_, n, 0, &carry); + hi_ += carry; +#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) + unsigned long long result; + auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); + lo_ = result; + hi_ += carry; +#elif defined(_MSC_VER) && defined(_M_X64) + auto carry = _addcarry_u64(0, lo_, n, &lo_); + _addcarry_u64(carry, hi_, 0, &hi_); +#else + lo_ += n; + hi_ += (lo_ < n ? 1 : 0); +#endif + return *this; + } +}; + +using uint128_t = conditional_t; + +#ifdef UINTPTR_MAX +using uintptr_t = ::uintptr_t; +#else +using uintptr_t = uint128_t; +#endif + +// Returns the largest possible value for type T. Same as +// std::numeric_limits::max() but shorter and not affected by the max macro. +template constexpr auto max_value() -> T { + return (std::numeric_limits::max)(); +} +template constexpr auto num_bits() -> int { + return std::numeric_limits::digits; +} +// std::numeric_limits::digits may return 0 for 128-bit ints. +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } +template <> constexpr auto num_bits() -> int { return 128; } + +// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t +// and 128-bit pointers to uint128_fallback. +template sizeof(From))> +inline auto bit_cast(const From& from) -> To { + constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); + struct data_t { + unsigned value[static_cast(size)]; + } data = bit_cast(from); + auto result = To(); + if (const_check(is_big_endian())) { + for (int i = 0; i < size; ++i) + result = (result << num_bits()) | data.value[i]; + } else { + for (int i = size - 1; i >= 0; --i) + result = (result << num_bits()) | data.value[i]; + } + return result; +} + +template +FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int { + int lz = 0; + constexpr UInt msb_mask = static_cast(1) << (num_bits() - 1); + for (; (n & msb_mask) == 0; n <<= 1) lz++; + return lz; +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); +#endif + return countl_zero_fallback(n); +} + +FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); +#endif + return countl_zero_fallback(n); +} + +FMT_INLINE void assume(bool condition) { + (void)condition; +#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION + __builtin_assume(condition); +#elif FMT_GCC_VERSION + if (!condition) __builtin_unreachable(); +#endif +} + +// An approximation of iterator_t for pre-C++20 systems. +template +using iterator_t = decltype(std::begin(std::declval())); +template using sentinel_t = decltype(std::end(std::declval())); + +// A workaround for std::string not having mutable data() until C++17. +template +inline auto get_data(std::basic_string& s) -> Char* { + return &s[0]; +} +template +inline auto get_data(Container& c) -> typename Container::value_type* { + return c.data(); +} + +// Attempts to reserve space for n extra characters in the output range. +// Returns a pointer to the reserved range or a reference to it. +template ::value&& + is_contiguous::value)> +#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION +__attribute__((no_sanitize("undefined"))) +#endif +inline auto +reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { + auto& c = get_container(it); + size_t size = c.size(); + c.resize(size + n); + return get_data(c) + size; +} + +template +inline auto reserve(basic_appender it, size_t n) -> basic_appender { + buffer& buf = get_container(it); + buf.try_reserve(buf.size() + n); + return it; +} + +template +constexpr auto reserve(Iterator& it, size_t) -> Iterator& { + return it; +} + +template +using reserve_iterator = + remove_reference_t(), 0))>; + +template +constexpr auto to_pointer(OutputIt, size_t) -> T* { + return nullptr; +} +template auto to_pointer(basic_appender it, size_t n) -> T* { + buffer& buf = get_container(it); + auto size = buf.size(); + buf.try_reserve(size + n); + if (buf.capacity() < size + n) return nullptr; + buf.try_resize(size + n); + return buf.data() + size; +} + +template ::value&& + is_contiguous::value)> +inline auto base_iterator(OutputIt it, + typename OutputIt::container_type::value_type*) + -> OutputIt { + return it; +} + +template +constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { + return it; +} + +// is spectacularly slow to compile in C++20 so use a simple fill_n +// instead (#1998). +template +FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) + -> OutputIt { + for (Size i = 0; i < count; ++i) *out++ = value; + return out; +} +template +FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { + if (is_constant_evaluated()) { + return fill_n(out, count, value); + } + std::memset(out, value, to_unsigned(count)); + return out + count; +} + +template +FMT_CONSTEXPR FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end, + OutputIt out) -> OutputIt { + return copy(begin, end, out); +} + +// A public domain branchless UTF-8 decoder by Christopher Wellons: +// https://github.com/skeeto/branchless-utf8 +/* Decode the next character, c, from s, reporting errors in e. + * + * Since this is a branchless decoder, four bytes will be read from the + * buffer regardless of the actual length of the next character. This + * means the buffer _must_ have at least three bytes of zero padding + * following the end of the data stream. + * + * Errors are reported in e, which will be non-zero if the parsed + * character was somehow invalid: invalid byte sequence, non-canonical + * encoding, or a surrogate half. + * + * The function returns a pointer to the next character. When an error + * occurs, this pointer will be a guess that depends on the particular + * error, but it will always advance at least one byte. + */ +FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) + -> const char* { + constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; + constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; + constexpr const int shiftc[] = {0, 18, 12, 6, 0}; + constexpr const int shifte[] = {0, 6, 4, 2, 0}; + + int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" + [static_cast(*s) >> 3]; + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + const char* next = s + len + !len; + + using uchar = unsigned char; + + // Assume a four-byte character and load four bytes. Unused bits are + // shifted out. + *c = uint32_t(uchar(s[0]) & masks[len]) << 18; + *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; + *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; + *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; + *c >>= shiftc[len]; + + // Accumulate the various error conditions. + *e = (*c < mins[len]) << 6; // non-canonical encoding + *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? + *e |= (*c > 0x10FFFF) << 8; // out of range? + *e |= (uchar(s[1]) & 0xc0) >> 2; + *e |= (uchar(s[2]) & 0xc0) >> 4; + *e |= uchar(s[3]) >> 6; + *e ^= 0x2a; // top two bits of each tail byte correct? + *e >>= shifte[len]; + + return next; +} + +constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t(); + +// Invokes f(cp, sv) for every code point cp in s with sv being the string view +// corresponding to the code point. cp is invalid_code_point on error. +template +FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { + auto decode = [f](const char* buf_ptr, const char* ptr) { + auto cp = uint32_t(); + auto error = 0; + auto end = utf8_decode(buf_ptr, &cp, &error); + bool result = f(error ? invalid_code_point : cp, + string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); + return result ? (error ? buf_ptr + 1 : end) : nullptr; + }; + auto p = s.data(); + const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. + if (s.size() >= block_size) { + for (auto end = p + s.size() - block_size + 1; p < end;) { + p = decode(p, p); + if (!p) return; + } + } + if (auto num_chars_left = s.data() + s.size() - p) { + char buf[2 * block_size - 1] = {}; + copy(p, p + num_chars_left, buf); + const char* buf_ptr = buf; + do { + auto end = decode(buf_ptr, p); + if (!end) return; + p += end - buf_ptr; + buf_ptr = end; + } while (buf_ptr - buf < num_chars_left); + } +} + +template +inline auto compute_width(basic_string_view s) -> size_t { + return s.size(); +} + +// Computes approximate display width of a UTF-8 string. +FMT_CONSTEXPR inline auto compute_width(string_view s) -> size_t { + size_t num_code_points = 0; + // It is not a lambda for compatibility with C++14. + struct count_code_points { + size_t* count; + FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { + *count += detail::to_unsigned( + 1 + + (cp >= 0x1100 && + (cp <= 0x115f || // Hangul Jamo init. consonants + cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET + cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET + // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: + (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || + (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables + (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs + (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms + (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms + (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms + (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms + (cp >= 0x20000 && cp <= 0x2fffd) || // CJK + (cp >= 0x30000 && cp <= 0x3fffd) || + // Miscellaneous Symbols and Pictographs + Emoticons: + (cp >= 0x1f300 && cp <= 0x1f64f) || + // Supplemental Symbols and Pictographs: + (cp >= 0x1f900 && cp <= 0x1f9ff)))); + return true; + } + }; + // We could avoid branches by using utf8_decode directly. + for_each_codepoint(s, count_code_points{&num_code_points}); + return num_code_points; +} + +template +inline auto code_point_index(basic_string_view s, size_t n) -> size_t { + size_t size = s.size(); + return n < size ? n : size; +} + +// Calculates the index of the nth code point in a UTF-8 string. +inline auto code_point_index(string_view s, size_t n) -> size_t { + size_t result = s.size(); + const char* begin = s.begin(); + for_each_codepoint(s, [begin, &n, &result](uint32_t, string_view sv) { + if (n != 0) { + --n; + return true; + } + result = to_unsigned(sv.begin() - begin); + return false; + }); + return result; +} + +template struct is_integral : std::is_integral {}; +template <> struct is_integral : std::true_type {}; +template <> struct is_integral : std::true_type {}; + +template +using is_signed = + std::integral_constant::is_signed || + std::is_same::value>; + +template +using is_integer = + bool_constant::value && !std::is_same::value && + !std::is_same::value && + !std::is_same::value>; + +#ifndef FMT_USE_FLOAT +# define FMT_USE_FLOAT 1 +#endif +#ifndef FMT_USE_DOUBLE +# define FMT_USE_DOUBLE 1 +#endif +#ifndef FMT_USE_LONG_DOUBLE +# define FMT_USE_LONG_DOUBLE 1 +#endif + +#if defined(FMT_USE_FLOAT128) +// Use the provided definition. +#elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE() +# define FMT_USE_FLOAT128 1 +#elif FMT_GCC_VERSION && defined(_GLIBCXX_USE_FLOAT128) && \ + !defined(__STRICT_ANSI__) +# define FMT_USE_FLOAT128 1 +#else +# define FMT_USE_FLOAT128 0 +#endif +#if FMT_USE_FLOAT128 +using float128 = __float128; +#else +using float128 = void; +#endif + +template using is_float128 = std::is_same; + +template +using is_floating_point = + bool_constant::value || is_float128::value>; + +template ::value> +struct is_fast_float : bool_constant::is_iec559 && + sizeof(T) <= sizeof(double)> {}; +template struct is_fast_float : std::false_type {}; + +template +using is_double_double = bool_constant::digits == 106>; + +#ifndef FMT_USE_FULL_CACHE_DRAGONBOX +# define FMT_USE_FULL_CACHE_DRAGONBOX 0 +#endif + +template +struct is_locale : std::false_type {}; +template +struct is_locale> : std::true_type {}; +} // namespace detail + +FMT_BEGIN_EXPORT + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + * A dynamically growing memory buffer for trivially copyable/constructible + * types with the first `SIZE` elements stored in the object itself. Most + * commonly used via the `memory_buffer` alias for `char`. + * + * **Example**: + * + * auto out = fmt::memory_buffer(); + * fmt::format_to(std::back_inserter(out), "The answer is {}.", 42); + * + * This will append "The answer is 42." to `out`. The buffer content can be + * converted to `std::string` with `to_string(out)`. + */ +template > +class basic_memory_buffer : public detail::buffer { + private: + T store_[SIZE]; + + // Don't inherit from Allocator to avoid generating type_info for it. + FMT_NO_UNIQUE_ADDRESS Allocator alloc_; + + // Deallocate memory allocated by the buffer. + FMT_CONSTEXPR20 void deallocate() { + T* data = this->data(); + if (data != store_) alloc_.deallocate(data, this->capacity()); + } + + static FMT_CONSTEXPR20 void grow(detail::buffer& buf, size_t size) { + detail::abort_fuzzing_if(size > 5000); + auto& self = static_cast(buf); + const size_t max_size = + std::allocator_traits::max_size(self.alloc_); + size_t old_capacity = buf.capacity(); + size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + else if (new_capacity > max_size) + new_capacity = size > max_size ? size : max_size; + T* old_data = buf.data(); + T* new_data = self.alloc_.allocate(new_capacity); + // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481). + detail::assume(buf.size() <= new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + memcpy(new_data, old_data, buf.size() * sizeof(T)); + self.set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != self.store_) self.alloc_.deallocate(old_data, old_capacity); + } + + public: + using value_type = T; + using const_reference = const T&; + + FMT_CONSTEXPR20 explicit basic_memory_buffer( + const Allocator& alloc = Allocator()) + : detail::buffer(grow), alloc_(alloc) { + this->set(store_, SIZE); + if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); + } + FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { + alloc_ = std::move(other.alloc_); + T* data = other.data(); + size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + detail::copy(other.store_, other.store_ + size, store_); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + other.clear(); + } + this->resize(size); + } + + public: + /// Constructs a `basic_memory_buffer` object moving the content of the other + /// object to it. + FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept + : detail::buffer(grow) { + move(other); + } + + /// Moves the content of the other `basic_memory_buffer` object to this one. + auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { + FMT_ASSERT(this != &other, ""); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + auto get_allocator() const -> Allocator { return alloc_; } + + /// Resizes the buffer to contain `count` elements. If T is a POD type new + /// elements may not be initialized. + FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } + + /// Increases the buffer capacity to `new_capacity`. + void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } + + using detail::buffer::append; + template + void append(const ContiguousRange& range) { + append(range.data(), range.data() + range.size()); + } +}; + +using memory_buffer = basic_memory_buffer; + +template +struct is_contiguous> : std::true_type { +}; + +FMT_END_EXPORT +namespace detail { +FMT_API auto write_console(int fd, string_view text) -> bool; +FMT_API void print(std::FILE*, string_view); +} // namespace detail + +FMT_BEGIN_EXPORT + +// Suppress a misleading warning in older versions of clang. +#if FMT_CLANG_VERSION +# pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +/// An error reported from a formatting function. +class FMT_SO_VISIBILITY("default") format_error : public std::runtime_error { + public: + using std::runtime_error::runtime_error; +}; + +namespace detail_exported { +#if FMT_USE_NONTYPE_TEMPLATE_ARGS +template struct fixed_string { + constexpr fixed_string(const Char (&str)[N]) { + detail::copy(static_cast(str), + str + N, data); + } + Char data[N] = {}; +}; +#endif + +// Converts a compile-time string to basic_string_view. +template +constexpr auto compile_string_to_view(const Char (&s)[N]) + -> basic_string_view { + // Remove trailing NUL character if needed. Won't be present if this is used + // with a raw character array (i.e. not defined as a string). + return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; +} +template +constexpr auto compile_string_to_view(basic_string_view s) + -> basic_string_view { + return s; +} +} // namespace detail_exported + +// A generic formatting context with custom output iterator and character +// (code unit) support. Char is the format string code unit type which can be +// different from OutputIt::value_type. +template class generic_context { + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using char_type = Char; + using iterator = OutputIt; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + constexpr generic_context(OutputIt out, + basic_format_args ctx_args, + detail::locale_ref loc = {}) + : out_(out), args_(ctx_args), loc_(loc) {} + generic_context(generic_context&&) = default; + generic_context(const generic_context&) = delete; + void operator=(const generic_context&) = delete; + + constexpr auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } + auto arg(basic_string_view name) -> basic_format_arg { + return args_.get(name); + } + FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { + return args_.get_id(name); + } + auto args() const -> const basic_format_args& { + return args_; + } + + FMT_CONSTEXPR auto out() -> iterator { return out_; } + + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } +}; + +class loc_value { + private: + basic_format_arg value_; + + public: + template ::value)> + loc_value(T value) : value_(detail::make_arg(value)) {} + + template ::value)> + loc_value(T) {} + + template auto visit(Visitor&& vis) -> decltype(vis(0)) { + return value_.visit(vis); + } +}; + +// A locale facet that formats values in UTF-8. +// It is parameterized on the locale to avoid the heavy include. +template class format_facet : public Locale::facet { + private: + std::string separator_; + std::string grouping_; + std::string decimal_point_; + + protected: + virtual auto do_put(appender out, loc_value val, + const format_specs& specs) const -> bool; + + public: + static FMT_API typename Locale::id id; + + explicit format_facet(Locale& loc); + explicit format_facet(string_view sep = "", + std::initializer_list g = {3}, + std::string decimal_point = ".") + : separator_(sep.data(), sep.size()), + grouping_(g.begin(), g.end()), + decimal_point_(decimal_point) {} + + auto put(appender out, loc_value val, const format_specs& specs) const + -> bool { + return do_put(out, val, specs); + } +}; + +FMT_END_EXPORT + +namespace detail { + +// Returns true if value is negative, false otherwise. +// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. +template ::value)> +constexpr auto is_negative(T value) -> bool { + return value < 0; +} +template ::value)> +constexpr auto is_negative(T) -> bool { + return false; +} + +template +FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { + if (std::is_same()) return FMT_USE_FLOAT; + if (std::is_same()) return FMT_USE_DOUBLE; + if (std::is_same()) return FMT_USE_LONG_DOUBLE; + return true; +} + +// Smallest of uint32_t, uint64_t, uint128_t that is large enough to +// represent all values of an integral type T. +template +using uint32_or_64_or_128_t = + conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, + uint32_t, + conditional_t() <= 64, uint64_t, uint128_t>>; +template +using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, (factor) * 100, (factor) * 1000, (factor) * 10000, \ + (factor) * 100000, (factor) * 1000000, (factor) * 10000000, \ + (factor) * 100000000, (factor) * 1000000000 + +// Converts value in the range [0, 100) to a string. +constexpr auto digits2(size_t value) -> const char* { + // GCC generates slightly better code when value is pointer-size. + return &"0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"[value * 2]; +} + +// Sign is a template parameter to workaround a bug in gcc 4.8. +template constexpr auto sign(Sign s) -> Char { +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 + static_assert(std::is_same::value, ""); +#endif + return static_cast(((' ' << 24) | ('+' << 16) | ('-' << 8)) >> (s * 8)); +} + +template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { + int count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#if FMT_USE_INT128 +FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { + return count_digits_fallback(n); +} +#endif + +#ifdef FMT_BUILTIN_CLZLL +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +inline auto do_count_digits(uint64_t n) -> int { + // This has comparable performance to the version by Kendall Willets + // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) + // but uses smaller tables. + // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). + static constexpr uint8_t bsr2log10[] = { + 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; + auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; + static constexpr const uint64_t zero_or_powers_of_10[] = { + 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), + 10000000000000000000ULL}; + return t - (n < zero_or_powers_of_10[t]); +} +#endif + +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { +#ifdef FMT_BUILTIN_CLZLL + if (!is_constant_evaluated()) return do_count_digits(n); +#endif + return count_digits_fallback(n); +} + +// Counts the number of digits in n. BITS = log2(radix). +template +FMT_CONSTEXPR auto count_digits(UInt n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated() && num_bits() == 32) + return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; +#endif + // Lambda avoids unreachable code warnings from NVHPC. + return [](UInt m) { + int num_digits = 0; + do { + ++num_digits; + } while ((m >>= BITS) != 0); + return num_digits; + }(n); +} + +#ifdef FMT_BUILTIN_CLZ +// It is a separate function rather than a part of count_digits to workaround +// the lack of static constexpr in constexpr functions. +FMT_INLINE auto do_count_digits(uint32_t n) -> int { +// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. +// This increments the upper 32 bits (log10(T) - 1) when >= T is added. +# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) + static constexpr uint64_t table[] = { + FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 + FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 + FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 + FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 + FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k + FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k + FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k + FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M + FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M + FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M + FMT_INC(1000000000), FMT_INC(1000000000) // 4B + }; + auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; + return static_cast((n + inc) >> 32); +} +#endif + +// Optional version of count_digits for better performance on 32-bit platforms. +FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { +#ifdef FMT_BUILTIN_CLZ + if (!is_constant_evaluated()) { + return do_count_digits(n); + } +#endif + return count_digits_fallback(n); +} + +template constexpr auto digits10() noexcept -> int { + return std::numeric_limits::digits10; +} +template <> constexpr auto digits10() noexcept -> int { return 38; } +template <> constexpr auto digits10() noexcept -> int { return 38; } + +template struct thousands_sep_result { + std::string grouping; + Char thousands_sep; +}; + +template +FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; +template +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + auto result = thousands_sep_impl(loc); + return {result.grouping, Char(result.thousands_sep)}; +} +template <> +inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { + return thousands_sep_impl(loc); +} + +template +FMT_API auto decimal_point_impl(locale_ref loc) -> Char; +template inline auto decimal_point(locale_ref loc) -> Char { + return Char(decimal_point_impl(loc)); +} +template <> inline auto decimal_point(locale_ref loc) -> wchar_t { + return decimal_point_impl(loc); +} + +// Compares two characters for equality. +template auto equal2(const Char* lhs, const char* rhs) -> bool { + return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); +} +inline auto equal2(const char* lhs, const char* rhs) -> bool { + return memcmp(lhs, rhs, 2) == 0; +} + +// Copies two characters from src to dst. +template +FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { + if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { + memcpy(dst, src, 2); + return; + } + *dst++ = static_cast(*src++); + *dst = static_cast(*src); +} + +template struct format_decimal_result { + Iterator begin; + Iterator end; +}; + +// Formats a decimal unsigned integer value writing into out pointing to a +// buffer of specified size. The caller must ensure that the buffer is large +// enough. +template +FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) + -> format_decimal_result { + FMT_ASSERT(size >= count_digits(value), "invalid digit count"); + out += size; + Char* end = out; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + out -= 2; + copy2(out, digits2(static_cast(value % 100))); + value /= 100; + } + if (value < 10) { + *--out = static_cast('0' + value); + return {out, end}; + } + out -= 2; + copy2(out, digits2(static_cast(value))); + return {out, end}; +} + +template >::value)> +FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) + -> format_decimal_result { + // Buffer is large enough to hold all digits (digits10 + 1). + Char buffer[digits10() + 1] = {}; + auto end = format_decimal(buffer, value, size).end; + return {out, detail::copy_noinline(buffer, end, out)}; +} + +template +FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, + bool upper = false) -> Char* { + buffer += num_digits; + Char* end = buffer; + do { + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); + *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) + : digits[digit]); + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits, + bool upper = false) -> It { + if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { + format_uint(ptr, value, num_digits, upper); + return out; + } + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). + char buffer[num_bits() / BASE_BITS + 1] = {}; + format_uint(buffer, value, num_digits, upper); + return detail::copy_noinline(buffer, buffer + num_digits, out); +} + +// A converter from UTF-8 to UTF-16. +class utf8_to_utf16 { + private: + basic_memory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator basic_string_view() const { return {&buffer_[0], size()}; } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const wchar_t* { return &buffer_[0]; } + auto str() const -> std::wstring { return {&buffer_[0], size()}; } +}; + +enum class to_utf8_error_policy { abort, replace }; + +// A converter from UTF-16/UTF-32 (host endian) to UTF-8. +template class to_utf8 { + private: + Buffer buffer_; + + public: + to_utf8() {} + explicit to_utf8(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) { + static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4, + "Expect utf16 or utf32"); + if (!convert(s, policy)) + FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16" + : "invalid utf32")); + } + operator string_view() const { return string_view(&buffer_[0], size()); } + auto size() const -> size_t { return buffer_.size() - 1; } + auto c_str() const -> const char* { return &buffer_[0]; } + auto str() const -> std::string { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a bool instead of throwing exception on + // conversion error. This method may still throw in case of memory allocation + // error. + auto convert(basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + if (!convert(buffer_, s, policy)) return false; + buffer_.push_back(0); + return true; + } + static auto convert(Buffer& buf, basic_string_view s, + to_utf8_error_policy policy = to_utf8_error_policy::abort) + -> bool { + for (auto p = s.begin(); p != s.end(); ++p) { + uint32_t c = static_cast(*p); + if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { + // Handle a surrogate pair. + ++p; + if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { + if (policy == to_utf8_error_policy::abort) return false; + buf.append(string_view("\xEF\xBF\xBD")); + --p; + } else { + c = (c << 10) + static_cast(*p) - 0x35fdc00; + } + } else if (c < 0x80) { + buf.push_back(static_cast(c)); + } else if (c < 0x800) { + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else if (c >= 0x10000 && c <= 0x10ffff) { + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); + } else { + return false; + } + } + return true; + } +}; + +// Computes 128-bit result of multiplication of two 64-bit unsigned integers. +inline auto umul128(uint64_t x, uint64_t y) noexcept -> uint128_fallback { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return {static_cast(p >> 64), static_cast(p)}; +#elif defined(_MSC_VER) && defined(_M_X64) + auto hi = uint64_t(); + auto lo = _umul128(x, y, &hi); + return {hi, lo}; +#else + const uint64_t mask = static_cast(max_value()); + + uint64_t a = x >> 32; + uint64_t b = x & mask; + uint64_t c = y >> 32; + uint64_t d = y & mask; + + uint64_t ac = a * c; + uint64_t bc = b * c; + uint64_t ad = a * d; + uint64_t bd = b * d; + + uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); + + return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), + (intermediate << 32) + (bd & mask)}; +#endif +} + +namespace dragonbox { +// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from +// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. +inline auto floor_log10_pow2(int e) noexcept -> int { + FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); + static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); + return (e * 315653) >> 20; +} + +inline auto floor_log2_pow10(int e) noexcept -> int { + FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); + return (e * 1741647) >> 19; +} + +// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. +inline auto umul128_upper64(uint64_t x, uint64_t y) noexcept -> uint64_t { +#if FMT_USE_INT128 + auto p = static_cast(x) * static_cast(y); + return static_cast(p >> 64); +#elif defined(_MSC_VER) && defined(_M_X64) + return __umulh(x, y); +#else + return umul128(x, y).high(); +#endif +} + +// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a +// 128-bit unsigned integer. +inline auto umul192_upper128(uint64_t x, uint128_fallback y) noexcept + -> uint128_fallback { + uint128_fallback r = umul128(x, y.high()); + r += umul128_upper64(x, y.low()); + return r; +} + +FMT_API auto get_cached_power(int k) noexcept -> uint128_fallback; + +// Type-specific information that Dragonbox uses. +template struct float_info; + +template <> struct float_info { + using carrier_uint = uint32_t; + static const int exponent_bits = 8; + static const int kappa = 1; + static const int big_divisor = 100; + static const int small_divisor = 10; + static const int min_k = -31; + static const int max_k = 46; + static const int shorter_interval_tie_lower_threshold = -35; + static const int shorter_interval_tie_upper_threshold = -35; +}; + +template <> struct float_info { + using carrier_uint = uint64_t; + static const int exponent_bits = 11; + static const int kappa = 2; + static const int big_divisor = 1000; + static const int small_divisor = 100; + static const int min_k = -292; + static const int max_k = 341; + static const int shorter_interval_tie_lower_threshold = -77; + static const int shorter_interval_tie_upper_threshold = -77; +}; + +// An 80- or 128-bit floating point number. +template +struct float_info::digits == 64 || + std::numeric_limits::digits == 113 || + is_float128::value>> { + using carrier_uint = detail::uint128_t; + static const int exponent_bits = 15; +}; + +// A double-double floating point number. +template +struct float_info::value>> { + using carrier_uint = detail::uint128_t; +}; + +template struct decimal_fp { + using significand_type = typename float_info::carrier_uint; + significand_type significand; + int exponent; +}; + +template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; +} // namespace dragonbox + +// Returns true iff Float has the implicit bit which is not stored. +template constexpr auto has_implicit_bit() -> bool { + // An 80-bit FP number has a 64-bit significand an no implicit bit. + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits stored in Float. The implicit bit is +// not counted since it is not stored. +template constexpr auto num_significand_bits() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 112 + : (std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0)); +} + +template +constexpr auto exponent_mask() -> + typename dragonbox::float_info::carrier_uint { + using float_uint = typename dragonbox::float_info::carrier_uint; + return ((float_uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); +} +template constexpr auto exponent_bias() -> int { + // std::numeric_limits may not support __float128. + return is_float128() ? 16383 + : std::numeric_limits::max_exponent - 1; +} + +// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. +template +FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { + FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); + if (exp < 0) { + *it++ = static_cast('-'); + exp = -exp; + } else { + *it++ = static_cast('+'); + } + if (exp >= 100) { + const char* top = digits2(to_unsigned(exp / 100)); + if (exp >= 1000) *it++ = static_cast(top[0]); + *it++ = static_cast(top[1]); + exp %= 100; + } + const char* d = digits2(to_unsigned(exp)); + *it++ = static_cast(d[0]); + *it++ = static_cast(d[1]); + return it; +} + +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> + num_float_significand_bits); + // The predecessor is closer if n is a normalized power of 2 (f == 0) + // other than the smallest normalized number (biased_e > 1). + auto is_predecessor_closer = f == 0 && biased_e > 1; + if (biased_e == 0) + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); + e = biased_e - exponent_bias() - num_float_significand_bits; + if (!has_implicit_bit()) ++e; + return is_predecessor_closer; + } + + template ::value)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } +}; + +using fp = basic_fp; + +// Normalizes the value converted from double and multiplied by (1 << SHIFT). +template +FMT_CONSTEXPR auto normalize(basic_fp value) -> basic_fp { + // Handle subnormals. + const auto implicit_bit = F(1) << num_significand_bits(); + const auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((value.f & shifted_implicit_bit) == 0) { + value.f <<= 1; + --value.e; + } + // Subtract 1 to account for hidden bit. + const auto offset = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; + value.f <<= offset; + value.e -= offset; + return value; +} + +// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. +FMT_CONSTEXPR inline auto multiply(uint64_t lhs, uint64_t rhs) -> uint64_t { +#if FMT_USE_INT128 + auto product = static_cast<__uint128_t>(lhs) * rhs; + auto f = static_cast(product >> 64); + return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; +#else + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = lhs >> 32, b = lhs & mask; + uint64_t c = rhs >> 32, d = rhs & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); +#endif +} + +FMT_CONSTEXPR inline auto operator*(fp x, fp y) -> fp { + return {multiply(x.f, y.f), x.e + y.e + 64}; +} + +template () == num_bits()> +using convert_float_result = + conditional_t::value || doublish, double, T>; + +template +constexpr auto convert_float(T value) -> convert_float_result { + return static_cast>(value); +} + +template +FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t& fill) + -> OutputIt { + auto fill_size = fill.size(); + if (fill_size == 1) return detail::fill_n(it, n, fill.template get()); + if (const Char* data = fill.template data()) { + for (size_t i = 0; i < n; ++i) it = copy(data, data + fill_size, it); + } + return it; +} + +// Writes the output of f, padded according to format specifications in specs. +// size: output size in code units. +// width: output display width in (terminal) column positions. +template +FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs, + size_t size, size_t width, F&& f) -> OutputIt { + static_assert(align == align::left || align == align::right, ""); + unsigned spec_width = to_unsigned(specs.width); + size_t padding = spec_width > width ? spec_width - width : 0; + // Shifts are encoded as string literals because static constexpr is not + // supported in constexpr functions. + auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; + size_t left_padding = padding >> shifts[specs.align]; + size_t right_padding = padding - left_padding; + auto it = reserve(out, size + padding * specs.fill.size()); + if (left_padding != 0) it = fill(it, left_padding, specs.fill); + it = f(it); + if (right_padding != 0) it = fill(it, right_padding, specs.fill); + return base_iterator(out, it); +} + +template +constexpr auto write_padded(OutputIt out, const format_specs& specs, + size_t size, F&& f) -> OutputIt { + return write_padded(out, specs, size, size, f); +} + +template +FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, + const format_specs& specs = {}) -> OutputIt { + return write_padded( + out, specs, bytes.size(), [bytes](reserve_iterator it) { + const char* data = bytes.data(); + return copy(data, data + bytes.size(), it); + }); +} + +template +auto write_ptr(OutputIt out, UIntPtr value, const format_specs* specs) + -> OutputIt { + int num_digits = count_digits<4>(value); + auto size = to_unsigned(num_digits) + size_t(2); + auto write = [=](reserve_iterator it) { + *it++ = static_cast('0'); + *it++ = static_cast('x'); + return format_uint<4, Char>(it, value, num_digits); + }; + return specs ? write_padded(out, *specs, size, write) + : base_iterator(out, write(reserve(out, size))); +} + +// Returns true iff the code point cp is printable. +FMT_API auto is_printable(uint32_t cp) -> bool; + +inline auto needs_escape(uint32_t cp) -> bool { + return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || + !is_printable(cp); +} + +template struct find_escape_result { + const Char* begin; + const Char* end; + uint32_t cp; +}; + +template +auto find_escape(const Char* begin, const Char* end) + -> find_escape_result { + for (; begin != end; ++begin) { + uint32_t cp = static_cast>(*begin); + if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; + if (needs_escape(cp)) return {begin, begin + 1, cp}; + } + return {begin, nullptr, 0}; +} + +inline auto find_escape(const char* begin, const char* end) + -> find_escape_result { + if (!use_utf8()) return find_escape(begin, end); + auto result = find_escape_result{end, nullptr, 0}; + for_each_codepoint(string_view(begin, to_unsigned(end - begin)), + [&](uint32_t cp, string_view sv) { + if (needs_escape(cp)) { + result = {sv.begin(), sv.end(), cp}; + return false; + } + return true; + }); + return result; +} + +#define FMT_STRING_IMPL(s, base, explicit) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ + using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ + operator fmt::basic_string_view() const { \ + return fmt::detail_exported::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + * Constructs a compile-time format string from a string literal `s`. + * + * **Example**: + * + * // A compile-time error because 'd' is an invalid specifier for strings. + * std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) + +template +auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { + *out++ = static_cast('\\'); + *out++ = static_cast(prefix); + Char buf[width]; + fill_n(buf, width, static_cast('0')); + format_uint<4>(buf, cp, width); + return copy(buf, buf + width, out); +} + +template +auto write_escaped_cp(OutputIt out, const find_escape_result& escape) + -> OutputIt { + auto c = static_cast(escape.cp); + switch (escape.cp) { + case '\n': + *out++ = static_cast('\\'); + c = static_cast('n'); + break; + case '\r': + *out++ = static_cast('\\'); + c = static_cast('r'); + break; + case '\t': + *out++ = static_cast('\\'); + c = static_cast('t'); + break; + case '"': + FMT_FALLTHROUGH; + case '\'': + FMT_FALLTHROUGH; + case '\\': + *out++ = static_cast('\\'); + break; + default: + if (escape.cp < 0x100) return write_codepoint<2, Char>(out, 'x', escape.cp); + if (escape.cp < 0x10000) + return write_codepoint<4, Char>(out, 'u', escape.cp); + if (escape.cp < 0x110000) + return write_codepoint<8, Char>(out, 'U', escape.cp); + for (Char escape_char : basic_string_view( + escape.begin, to_unsigned(escape.end - escape.begin))) { + out = write_codepoint<2, Char>(out, 'x', + static_cast(escape_char) & 0xFF); + } + return out; + } + *out++ = c; + return out; +} + +template +auto write_escaped_string(OutputIt out, basic_string_view str) + -> OutputIt { + *out++ = static_cast('"'); + auto begin = str.begin(), end = str.end(); + do { + auto escape = find_escape(begin, end); + out = copy(begin, escape.begin, out); + begin = escape.end; + if (!begin) break; + out = write_escaped_cp(out, escape); + } while (begin != end); + *out++ = static_cast('"'); + return out; +} + +template +auto write_escaped_char(OutputIt out, Char v) -> OutputIt { + Char v_array[1] = {v}; + *out++ = static_cast('\''); + if ((needs_escape(static_cast(v)) && v != static_cast('"')) || + v == static_cast('\'')) { + out = write_escaped_cp(out, + find_escape_result{v_array, v_array + 1, + static_cast(v)}); + } else { + *out++ = v; + } + *out++ = static_cast('\''); + return out; +} + +template +FMT_CONSTEXPR auto write_char(OutputIt out, Char value, + const format_specs& specs) -> OutputIt { + bool is_debug = specs.type == presentation_type::debug; + return write_padded(out, specs, 1, [=](reserve_iterator it) { + if (is_debug) return write_escaped_char(it, value); + *it++ = value; + return it; + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, Char value, const format_specs& specs, + locale_ref loc = {}) -> OutputIt { + // char is formatted as unsigned char for consistency across platforms. + using unsigned_type = + conditional_t::value, unsigned char, unsigned>; + return check_char_specs(specs) + ? write_char(out, value, specs) + : write(out, static_cast(value), specs, loc); +} + +// Data for write_int that doesn't depend on output iterator type. It is used to +// avoid template code bloat. +template struct write_int_data { + size_t size; + size_t padding; + + FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, + const format_specs& specs) + : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { + if (specs.align == align::numeric) { + auto width = to_unsigned(specs.width); + if (width > size) { + padding = width - size; + size = width; + } + } else if (specs.precision > num_digits) { + size = (prefix >> 24) + to_unsigned(specs.precision); + padding = to_unsigned(specs.precision - num_digits); + } + } +}; + +// Writes an integer in the format +// +// where are written by write_digits(it). +// prefix contains chars in three lower bytes and the size in the fourth byte. +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, + unsigned prefix, + const format_specs& specs, + W write_digits) -> OutputIt { + // Slightly faster check for specs.width == 0 && specs.precision == -1. + if ((specs.width | (specs.precision + 1)) == 0) { + auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); + if (prefix != 0) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + } + return base_iterator(out, write_digits(it)); + } + auto data = write_int_data(num_digits, prefix, specs); + return write_padded( + out, specs, data.size, [=](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + it = detail::fill_n(it, data.padding, static_cast('0')); + return write_digits(it); + }); +} + +template class digit_grouping { + private: + std::string grouping_; + std::basic_string thousands_sep_; + + struct next_state { + std::string::const_iterator group; + int pos; + }; + auto initial_state() const -> next_state { return {grouping_.begin(), 0}; } + + // Returns the next digit group separator position. + auto next(next_state& state) const -> int { + if (thousands_sep_.empty()) return max_value(); + if (state.group == grouping_.end()) return state.pos += grouping_.back(); + if (*state.group <= 0 || *state.group == max_value()) + return max_value(); + state.pos += *state.group++; + return state.pos; + } + + public: + explicit digit_grouping(locale_ref loc, bool localized = true) { + if (!localized) return; + auto sep = thousands_sep(loc); + grouping_ = sep.grouping; + if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); + } + digit_grouping(std::string grouping, std::basic_string sep) + : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} + + auto has_separator() const -> bool { return !thousands_sep_.empty(); } + + auto count_separators(int num_digits) const -> int { + int count = 0; + auto state = initial_state(); + while (num_digits > next(state)) ++count; + return count; + } + + // Applies grouping to digits and write the output to out. + template + auto apply(Out out, basic_string_view digits) const -> Out { + auto num_digits = static_cast(digits.size()); + auto separators = basic_memory_buffer(); + separators.push_back(0); + auto state = initial_state(); + while (int i = next(state)) { + if (i >= num_digits) break; + separators.push_back(i); + } + for (int i = 0, sep_index = static_cast(separators.size() - 1); + i < num_digits; ++i) { + if (num_digits - i == separators[sep_index]) { + out = copy(thousands_sep_.data(), + thousands_sep_.data() + thousands_sep_.size(), out); + --sep_index; + } + *out++ = static_cast(digits[to_unsigned(i)]); + } + return out; + } +}; + +FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { + prefix |= prefix != 0 ? value << 8 : value; + prefix += (1u + (value > 0xff ? 1 : 0)) << 24; +} + +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif +// Writes a decimal integer with digit grouping. +template +auto write_int(OutputIt out, UInt value, unsigned prefix, + const format_specs& specs, const digit_grouping& grouping) + -> OutputIt { + static_assert(std::is_same, UInt>::value, ""); + int num_digits = 0; + auto buffer = memory_buffer(); + switch (specs.type) { + default: + FMT_ASSERT(false, ""); + FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: + num_digits = count_digits(value); + format_decimal(appender(buffer), value, num_digits); + break; + case presentation_type::hex: + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0'); + num_digits = count_digits<4>(value); + format_uint<4, char>(appender(buffer), value, num_digits, specs.upper); + break; + case presentation_type::oct: + num_digits = count_digits<3>(value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && value != 0) + prefix_append(prefix, '0'); + format_uint<3, char>(appender(buffer), value, num_digits); + break; + case presentation_type::bin: + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0'); + num_digits = count_digits<1>(value); + format_uint<1, char>(appender(buffer), value, num_digits); + break; + case presentation_type::chr: + return write_char(out, static_cast(value), specs); + } + + unsigned size = (prefix != 0 ? prefix >> 24 : 0) + to_unsigned(num_digits) + + to_unsigned(grouping.count_separators(num_digits)); + return write_padded( + out, specs, size, size, [&](reserve_iterator it) { + for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) + *it++ = static_cast(p & 0xff); + return grouping.apply(it, string_view(buffer.data(), buffer.size())); + }); +} +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + +// Writes a localized value. +FMT_API auto write_loc(appender out, loc_value value, const format_specs& specs, + locale_ref loc) -> bool; +template +inline auto write_loc(OutputIt, loc_value, const format_specs&, locale_ref) + -> bool { + return false; +} + +template struct write_int_arg { + UInt abs_value; + unsigned prefix; +}; + +template +FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) + -> write_int_arg> { + auto prefix = 0u; + auto abs_value = static_cast>(value); + if (is_negative(value)) { + prefix = 0x01000000 | '-'; + abs_value = 0 - abs_value; + } else { + constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', + 0x1000000u | ' '}; + prefix = prefixes[sign]; + } + return {abs_value, prefix}; +} + +template struct loc_writer { + basic_appender out; + const format_specs& specs; + std::basic_string sep; + std::string grouping; + std::basic_string decimal_point; + + template ::value)> + auto operator()(T value) -> bool { + auto arg = make_write_int_arg(value, specs.sign); + write_int(out, static_cast>(arg.abs_value), arg.prefix, + specs, digit_grouping(grouping, sep)); + return true; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif +template +FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, + const format_specs& specs, locale_ref) + -> OutputIt { + static_assert(std::is_same>::value, ""); + auto abs_value = arg.abs_value; + auto prefix = arg.prefix; + switch (specs.type) { + default: + FMT_ASSERT(false, ""); + FMT_FALLTHROUGH; + case presentation_type::none: + case presentation_type::dec: { + int num_digits = count_digits(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_decimal(it, abs_value, num_digits).end; + }); + } + case presentation_type::hex: { + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0'); + int num_digits = count_digits<4>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<4, Char>(it, abs_value, num_digits, specs.upper); + }); + } + case presentation_type::oct: { + int num_digits = count_digits<3>(abs_value); + // Octal prefix '0' is counted as a digit, so only add it if precision + // is not greater than the number of digits. + if (specs.alt && specs.precision <= num_digits && abs_value != 0) + prefix_append(prefix, '0'); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<3, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::bin: { + if (specs.alt) + prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0'); + int num_digits = count_digits<1>(abs_value); + return write_int( + out, num_digits, prefix, specs, [=](reserve_iterator it) { + return format_uint<1, Char>(it, abs_value, num_digits); + }); + } + case presentation_type::chr: + return write_char(out, static_cast(abs_value), specs); + } +} +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + +template +FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline(OutputIt out, + write_int_arg arg, + const format_specs& specs, + locale_ref loc) -> OutputIt { + return write_int(out, arg, specs, loc); +} +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR FMT_INLINE auto write(basic_appender out, T value, + const format_specs& specs, locale_ref loc) + -> basic_appender { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int_noinline(out, make_write_int_arg(value, specs.sign), + specs, loc); +} +// An inlined version of write used in format string compilation. +template ::value && + !std::is_same::value && + !std::is_same::value && + !std::is_same>::value)> +FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, + const format_specs& specs, locale_ref loc) + -> OutputIt { + if (specs.localized && write_loc(out, value, specs, loc)) return out; + return write_int(out, make_write_int_arg(value, specs.sign), specs, + loc); +} + +// An output iterator that counts the number of objects written to it and +// discards them. +class counting_iterator { + private: + size_t count_; + + public: + using iterator_category = std::output_iterator_tag; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = void; + FMT_UNCHECKED_ITERATOR(counting_iterator); + + struct value_type { + template FMT_CONSTEXPR void operator=(const T&) {} + }; + + FMT_CONSTEXPR counting_iterator() : count_(0) {} + + FMT_CONSTEXPR auto count() const -> size_t { return count_; } + + FMT_CONSTEXPR auto operator++() -> counting_iterator& { + ++count_; + return *this; + } + FMT_CONSTEXPR auto operator++(int) -> counting_iterator { + auto it = *this; + ++*this; + return it; + } + + FMT_CONSTEXPR friend auto operator+(counting_iterator it, difference_type n) + -> counting_iterator { + it.count_ += static_cast(n); + return it; + } + + FMT_CONSTEXPR auto operator*() const -> value_type { return {}; } +}; + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, + const format_specs& specs) -> OutputIt { + auto data = s.data(); + auto size = s.size(); + if (specs.precision >= 0 && to_unsigned(specs.precision) < size) + size = code_point_index(s, to_unsigned(specs.precision)); + bool is_debug = specs.type == presentation_type::debug; + size_t width = 0; + + if (is_debug) size = write_escaped_string(counting_iterator{}, s).count(); + + if (specs.width != 0) { + if (is_debug) + width = size; + else + width = compute_width(basic_string_view(data, size)); + } + return write_padded(out, specs, size, width, + [=](reserve_iterator it) { + if (is_debug) return write_escaped_string(it, s); + return copy(data, data + size, it); + }); +} +template +FMT_CONSTEXPR auto write(OutputIt out, + basic_string_view> s, + const format_specs& specs, locale_ref) -> OutputIt { + return write(out, s, specs); +} +template +FMT_CONSTEXPR auto write(OutputIt out, const Char* s, const format_specs& specs, + locale_ref) -> OutputIt { + if (specs.type == presentation_type::pointer) + return write_ptr(out, bit_cast(s), &specs); + if (!s) report_error("string pointer is null"); + return write(out, basic_string_view(s), specs, {}); +} + +template ::value && + !std::is_same::value && + !std::is_same::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + auto abs_value = static_cast>(value); + bool negative = is_negative(value); + // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. + if (negative) abs_value = ~abs_value + 1; + int num_digits = count_digits(abs_value); + auto size = (negative ? 1 : 0) + static_cast(num_digits); + if (auto ptr = to_pointer(out, size)) { + if (negative) *ptr++ = static_cast('-'); + format_decimal(ptr, abs_value, num_digits); + return out; + } + if (negative) *out++ = static_cast('-'); + return format_decimal(out, abs_value, num_digits).end; +} + +// DEPRECATED! +template +FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, + format_specs& specs) -> const Char* { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (end - p <= 0) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; + break; + } + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '}') return begin; + if (c == '{') { + report_error("invalid fill character '{'"); + return begin; + } + specs.fill = basic_string_view(begin, to_unsigned(p - begin)); + begin = p + 1; + } else { + ++begin; + } + break; + } else if (p == begin) { + break; + } + p = begin; + } + specs.align = align; + return begin; +} + +// A floating-point presentation format. +enum class float_format : unsigned char { + general, // General: exponent notation or fixed point based on magnitude. + exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. + fixed // Fixed point with the default precision of 6, e.g. 0.0012. +}; + +struct float_specs { + int precision; + float_format format : 8; + sign_t sign : 8; + bool locale : 1; + bool binary32 : 1; + bool showpoint : 1; +}; + +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif +// DEPRECATED! +FMT_CONSTEXPR inline auto parse_float_type_spec(const format_specs& specs) + -> float_specs { + auto result = float_specs(); + result.showpoint = specs.alt; + result.locale = specs.localized; + switch (specs.type) { + default: + FMT_FALLTHROUGH; + case presentation_type::none: + result.format = float_format::general; + break; + case presentation_type::exp: + result.format = float_format::exp; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::fixed: + result.format = float_format::fixed; + result.showpoint |= specs.precision != 0; + break; + case presentation_type::general: + result.format = float_format::general; + break; + } + return result; +} +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + +template +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, + format_specs specs, sign_t sign) + -> OutputIt { + auto str = + isnan ? (specs.upper ? "NAN" : "nan") : (specs.upper ? "INF" : "inf"); + constexpr size_t str_size = 3; + auto size = str_size + (sign ? 1 : 0); + // Replace '0'-padding with space for non-finite values. + const bool is_zero_fill = + specs.fill.size() == 1 && specs.fill.template get() == '0'; + if (is_zero_fill) specs.fill = ' '; + return write_padded(out, specs, size, + [=](reserve_iterator it) { + if (sign) *it++ = detail::sign(sign); + return copy(str, str + str_size, it); + }); +} + +// A decimal floating-point number significand * pow(10, exp). +struct big_decimal_fp { + const char* significand; + int significand_size; + int exponent; +}; + +constexpr auto get_significand_size(const big_decimal_fp& f) -> int { + return f.significand_size; +} +template +inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { + return count_digits(f.significand); +} + +template +constexpr auto write_significand(OutputIt out, const char* significand, + int significand_size) -> OutputIt { + return copy(significand, significand + significand_size, out); +} +template +inline auto write_significand(OutputIt out, UInt significand, + int significand_size) -> OutputIt { + return format_decimal(out, significand, significand_size).end; +} +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int exponent, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + out = write_significand(out, significand, significand_size); + return detail::fill_n(out, exponent, static_cast('0')); + } + auto buffer = memory_buffer(); + write_significand(appender(buffer), significand, significand_size); + detail::fill_n(appender(buffer), exponent, '0'); + return grouping.apply(out, string_view(buffer.data(), buffer.size())); +} + +template ::value)> +inline auto write_significand(Char* out, UInt significand, int significand_size, + int integral_size, Char decimal_point) -> Char* { + if (!decimal_point) + return format_decimal(out, significand, significand_size).end; + out += significand_size + 1; + Char* end = out; + int floating_size = significand_size - integral_size; + for (int i = floating_size / 2; i > 0; --i) { + out -= 2; + copy2(out, digits2(static_cast(significand % 100))); + significand /= 100; + } + if (floating_size % 2 != 0) { + *--out = static_cast('0' + significand % 10); + significand /= 10; + } + *--out = decimal_point; + format_decimal(out - integral_size, significand, integral_size); + return end; +} + +template >::value)> +inline auto write_significand(OutputIt out, UInt significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. + Char buffer[digits10() + 2]; + auto end = write_significand(buffer, significand, significand_size, + integral_size, decimal_point); + return detail::copy_noinline(buffer, end, out); +} + +template +FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, + int significand_size, int integral_size, + Char decimal_point) -> OutputIt { + out = detail::copy_noinline(significand, significand + integral_size, + out); + if (!decimal_point) return out; + *out++ = decimal_point; + return detail::copy_noinline(significand + integral_size, + significand + significand_size, out); +} + +template +FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, + int significand_size, int integral_size, + Char decimal_point, + const Grouping& grouping) -> OutputIt { + if (!grouping.has_separator()) { + return write_significand(out, significand, significand_size, integral_size, + decimal_point); + } + auto buffer = basic_memory_buffer(); + write_significand(basic_appender(buffer), significand, significand_size, + integral_size, decimal_point); + grouping.apply( + out, basic_string_view(buffer.data(), to_unsigned(integral_size))); + return detail::copy_noinline(buffer.data() + integral_size, + buffer.end(), out); +} + +template > +FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, + float_specs fspecs, locale_ref loc) + -> OutputIt { + auto significand = f.significand; + int significand_size = get_significand_size(f); + const Char zero = static_cast('0'); + auto sign = fspecs.sign; + size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); + using iterator = reserve_iterator; + + Char decimal_point = + fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); + + int output_exp = f.exponent + significand_size - 1; + auto use_exp_format = [=]() { + if (fspecs.format == float_format::exp) return true; + if (fspecs.format != float_format::general) return false; + // Use the fixed notation if the exponent is in [exp_lower, exp_upper), + // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. + const int exp_lower = -4, exp_upper = 16; + return output_exp < exp_lower || + output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); + }; + if (use_exp_format()) { + int num_zeros = 0; + if (fspecs.showpoint) { + num_zeros = fspecs.precision - significand_size; + if (num_zeros < 0) num_zeros = 0; + size += to_unsigned(num_zeros); + } else if (significand_size == 1) { + decimal_point = Char(); + } + auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; + int exp_digits = 2; + if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; + + size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); + char exp_char = specs.upper ? 'E' : 'e'; + auto write = [=](iterator it) { + if (sign) *it++ = detail::sign(sign); + // Insert a decimal point after the first digit and add an exponent. + it = write_significand(it, significand, significand_size, 1, + decimal_point); + if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); + *it++ = static_cast(exp_char); + return write_exponent(output_exp, it); + }; + return specs.width > 0 + ? write_padded(out, specs, size, write) + : base_iterator(out, write(reserve(out, size))); + } + + int exp = f.exponent + significand_size; + if (f.exponent >= 0) { + // 1234e5 -> 123400000[.0+] + size += to_unsigned(f.exponent); + int num_zeros = fspecs.precision - exp; + abort_fuzzing_if(num_zeros > 5000); + if (fspecs.showpoint) { + ++size; + if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0; + if (num_zeros > 0) size += to_unsigned(num_zeros); + } + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, + f.exponent, grouping); + if (!fspecs.showpoint) return it; + *it++ = decimal_point; + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } else if (exp > 0) { + // 1234e-2 -> 12.34[0+] + int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; + size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); + auto grouping = Grouping(loc, fspecs.locale); + size += to_unsigned(grouping.count_separators(exp)); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + it = write_significand(it, significand, significand_size, exp, + decimal_point, grouping); + return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; + }); + } + // 1234e-6 -> 0.001234 + int num_zeros = -exp; + if (significand_size == 0 && fspecs.precision >= 0 && + fspecs.precision < num_zeros) { + num_zeros = fspecs.precision; + } + bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; + size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); + return write_padded(out, specs, size, [&](iterator it) { + if (sign) *it++ = detail::sign(sign); + *it++ = zero; + if (!pointy) return it; + *it++ = decimal_point; + it = detail::fill_n(it, num_zeros, zero); + return write_significand(it, significand, significand_size); + }); +} + +template class fallback_digit_grouping { + public: + constexpr fallback_digit_grouping(locale_ref, bool) {} + + constexpr auto has_separator() const -> bool { return false; } + + constexpr auto count_separators(int) const -> int { return 0; } + + template + constexpr auto apply(Out out, basic_string_view) const -> Out { + return out; + } +}; + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, + const format_specs& specs, float_specs fspecs, + locale_ref loc) -> OutputIt { + if (is_constant_evaluated()) { + return do_write_float>(out, f, specs, fspecs, + loc); + } else { + return do_write_float(out, f, specs, fspecs, loc); + } +} + +template constexpr auto isnan(T value) -> bool { + return value != value; // std::isnan doesn't support __float128. +} + +template +struct has_isfinite : std::false_type {}; + +template +struct has_isfinite> + : std::true_type {}; + +template ::value&& + has_isfinite::value)> +FMT_CONSTEXPR20 auto isfinite(T value) -> bool { + constexpr T inf = T(std::numeric_limits::infinity()); + if (is_constant_evaluated()) + return !detail::isnan(value) && value < inf && value > -inf; + return std::isfinite(value); +} +template ::value)> +FMT_CONSTEXPR auto isfinite(T value) -> bool { + T inf = T(std::numeric_limits::infinity()); + // std::isfinite doesn't support __float128. + return !detail::isnan(value) && value < inf && value > -inf; +} + +template ::value)> +FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { + if (is_constant_evaluated()) { +#ifdef __cpp_if_constexpr + if constexpr (std::numeric_limits::is_iec559) { + auto bits = detail::bit_cast(static_cast(value)); + return (bits >> (num_bits() - 1)) != 0; + } +#endif + } + return std::signbit(static_cast(value)); +} + +inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { + // Adjust fixed precision by exponent because it is relative to decimal + // point. + if (exp10 > 0 && precision > max_value() - exp10) + FMT_THROW(format_error("number is too big")); + precision += exp10; +} + +class bigint { + private: + // A bigint is stored as an array of bigits (big digits), with bigit at index + // 0 being the least significant one. + using bigit = uint32_t; + using double_bigit = uint64_t; + enum { bigits_capacity = 32 }; + basic_memory_buffer bigits_; + int exp_; + + FMT_CONSTEXPR20 auto operator[](int index) const -> bigit { + return bigits_[to_unsigned(index)]; + } + FMT_CONSTEXPR20 auto operator[](int index) -> bigit& { + return bigits_[to_unsigned(index)]; + } + + static constexpr const int bigit_bits = num_bits(); + + friend struct formatter; + + FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { + auto result = static_cast((*this)[index]) - other - borrow; + (*this)[index] = static_cast(result); + borrow = static_cast(result >> (bigit_bits * 2 - 1)); + } + + FMT_CONSTEXPR20 void remove_leading_zeros() { + int num_bigits = static_cast(bigits_.size()) - 1; + while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; + bigits_.resize(to_unsigned(num_bigits + 1)); + } + + // Computes *this -= other assuming aligned bigints and *this >= other. + FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { + FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); + FMT_ASSERT(compare(*this, other) >= 0, ""); + bigit borrow = 0; + int i = other.exp_ - exp_; + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) + subtract_bigits(i, other.bigits_[j], borrow); + while (borrow > 0) subtract_bigits(i, 0, borrow); + remove_leading_zeros(); + } + + FMT_CONSTEXPR20 void multiply(uint32_t value) { + const double_bigit wide_value = value; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + double_bigit result = bigits_[i] * wide_value + carry; + bigits_[i] = static_cast(result); + carry = static_cast(result >> bigit_bits); + } + if (carry != 0) bigits_.push_back(carry); + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void multiply(UInt value) { + using half_uint = + conditional_t::value, uint64_t, uint32_t>; + const int shift = num_bits() - bigit_bits; + const UInt lower = static_cast(value); + const UInt upper = value >> num_bits(); + UInt carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + UInt result = lower * bigits_[i] + static_cast(carry); + carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + + (carry >> bigit_bits); + bigits_[i] = static_cast(result); + } + while (carry != 0) { + bigits_.push_back(static_cast(carry)); + carry >>= bigit_bits; + } + } + + template ::value || + std::is_same::value)> + FMT_CONSTEXPR20 void assign(UInt n) { + size_t num_bigits = 0; + do { + bigits_[num_bigits++] = static_cast(n); + n >>= bigit_bits; + } while (n != 0); + bigits_.resize(num_bigits); + exp_ = 0; + } + + public: + FMT_CONSTEXPR20 bigint() : exp_(0) {} + explicit bigint(uint64_t n) { assign(n); } + + bigint(const bigint&) = delete; + void operator=(const bigint&) = delete; + + FMT_CONSTEXPR20 void assign(const bigint& other) { + auto size = other.bigits_.size(); + bigits_.resize(size); + auto data = other.bigits_.data(); + copy(data, data + size, bigits_.data()); + exp_ = other.exp_; + } + + template FMT_CONSTEXPR20 void operator=(Int n) { + FMT_ASSERT(n > 0, ""); + assign(uint64_or_128_t(n)); + } + + FMT_CONSTEXPR20 auto num_bigits() const -> int { + return static_cast(bigits_.size()) + exp_; + } + + FMT_NOINLINE FMT_CONSTEXPR20 auto operator<<=(int shift) -> bigint& { + FMT_ASSERT(shift >= 0, ""); + exp_ += shift / bigit_bits; + shift %= bigit_bits; + if (shift == 0) return *this; + bigit carry = 0; + for (size_t i = 0, n = bigits_.size(); i < n; ++i) { + bigit c = bigits_[i] >> (bigit_bits - shift); + bigits_[i] = (bigits_[i] << shift) + carry; + carry = c; + } + if (carry != 0) bigits_.push_back(carry); + return *this; + } + + template + FMT_CONSTEXPR20 auto operator*=(Int value) -> bigint& { + FMT_ASSERT(value > 0, ""); + multiply(uint32_or_64_or_128_t(value)); + return *this; + } + + friend FMT_CONSTEXPR20 auto compare(const bigint& lhs, const bigint& rhs) + -> int { + int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); + if (num_lhs_bigits != num_rhs_bigits) + return num_lhs_bigits > num_rhs_bigits ? 1 : -1; + int i = static_cast(lhs.bigits_.size()) - 1; + int j = static_cast(rhs.bigits_.size()) - 1; + int end = i - j; + if (end < 0) end = 0; + for (; i >= end; --i, --j) { + bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; + if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; + } + if (i != j) return i > j ? 1 : -1; + return 0; + } + + // Returns compare(lhs1 + lhs2, rhs). + friend FMT_CONSTEXPR20 auto add_compare(const bigint& lhs1, + const bigint& lhs2, const bigint& rhs) + -> int { + auto minimum = [](int a, int b) { return a < b ? a : b; }; + auto maximum = [](int a, int b) { return a > b ? a : b; }; + int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); + int num_rhs_bigits = rhs.num_bigits(); + if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; + if (max_lhs_bigits > num_rhs_bigits) return 1; + auto get_bigit = [](const bigint& n, int i) -> bigit { + return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; + }; + double_bigit borrow = 0; + int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); + for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { + double_bigit sum = + static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); + bigit rhs_bigit = get_bigit(rhs, i); + if (sum > rhs_bigit + borrow) return 1; + borrow = rhs_bigit + borrow - sum; + if (borrow > 1) return -1; + borrow <<= bigit_bits; + } + return borrow != 0 ? -1 : 0; + } + + // Assigns pow(10, exp) to this bigint. + FMT_CONSTEXPR20 void assign_pow10(int exp) { + FMT_ASSERT(exp >= 0, ""); + if (exp == 0) return *this = 1; + // Find the top bit. + int bitmask = 1; + while (exp >= bitmask) bitmask <<= 1; + bitmask >>= 1; + // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by + // repeated squaring and multiplication. + *this = 5; + bitmask >>= 1; + while (bitmask != 0) { + square(); + if ((exp & bitmask) != 0) *this *= 5; + bitmask >>= 1; + } + *this <<= exp; // Multiply by pow(2, exp) by shifting. + } + + FMT_CONSTEXPR20 void square() { + int num_bigits = static_cast(bigits_.size()); + int num_result_bigits = 2 * num_bigits; + basic_memory_buffer n(std::move(bigits_)); + bigits_.resize(to_unsigned(num_result_bigits)); + auto sum = uint128_t(); + for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { + // Compute bigit at position bigit_index of the result by adding + // cross-product terms n[i] * n[j] such that i + j == bigit_index. + for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { + // Most terms are multiplied twice which can be optimized in the future. + sum += static_cast(n[i]) * n[j]; + } + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); // Compute the carry. + } + // Do the same for the top half. + for (int bigit_index = num_bigits; bigit_index < num_result_bigits; + ++bigit_index) { + for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) + sum += static_cast(n[i++]) * n[j--]; + (*this)[bigit_index] = static_cast(sum); + sum >>= num_bits(); + } + remove_leading_zeros(); + exp_ *= 2; + } + + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + FMT_CONSTEXPR20 void align(const bigint& other) { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + memset(bigits_.data(), 0, to_unsigned(exp_difference) * sizeof(bigit)); + exp_ -= exp_difference; + } + + // Divides this bignum by divisor, assigning the remainder to this and + // returning the quotient. + FMT_CONSTEXPR20 auto divmod_assign(const bigint& divisor) -> int { + FMT_ASSERT(this != &divisor, ""); + if (compare(*this, divisor) < 0) return 0; + FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); + align(divisor); + int quotient = 0; + do { + subtract_aligned(divisor); + ++quotient; + } while (compare(*this, divisor) >= 0); + return quotient; + } +}; + +// format_dragon flags. +enum dragon { + predecessor_closer = 1, + fixup = 2, // Run fixup to correct exp10 which can be off by one. + fixed = 4, +}; + +// Formats a floating-point number using a variation of the Fixed-Precision +// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: +// https://fmt.dev/papers/p372-steele.pdf. +FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, + unsigned flags, int num_digits, + buffer& buf, int& exp10) { + bigint numerator; // 2 * R in (FPP)^2. + bigint denominator; // 2 * S in (FPP)^2. + // lower and upper are differences between value and corresponding boundaries. + bigint lower; // (M^- in (FPP)^2). + bigint upper_store; // upper's value if different from lower. + bigint* upper = nullptr; // (M^+ in (FPP)^2). + // Shift numerator and denominator by an extra bit or two (if lower boundary + // is closer) to make lower and upper integers. This eliminates multiplication + // by 2 during later computations. + bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; + int shift = is_predecessor_closer ? 2 : 1; + if (value.e >= 0) { + numerator = value.f; + numerator <<= value.e + shift; + lower = 1; + lower <<= value.e; + if (is_predecessor_closer) { + upper_store = 1; + upper_store <<= value.e + 1; + upper = &upper_store; + } + denominator.assign_pow10(exp10); + denominator <<= shift; + } else if (exp10 < 0) { + numerator.assign_pow10(-exp10); + lower.assign(numerator); + if (is_predecessor_closer) { + upper_store.assign(numerator); + upper_store <<= 1; + upper = &upper_store; + } + numerator *= value.f; + numerator <<= shift; + denominator = 1; + denominator <<= shift - value.e; + } else { + numerator = value.f; + numerator <<= shift; + denominator.assign_pow10(exp10); + denominator <<= shift - value.e; + lower = 1; + if (is_predecessor_closer) { + upper_store = 1ULL << 1; + upper = &upper_store; + } + } + int even = static_cast((value.f & 1) == 0); + if (!upper) upper = &lower; + bool shortest = num_digits < 0; + if ((flags & dragon::fixup) != 0) { + if (add_compare(numerator, *upper, denominator) + even <= 0) { + --exp10; + numerator *= 10; + if (num_digits < 0) { + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); + } + // Invariant: value == (numerator / denominator) * pow(10, exp10). + if (shortest) { + // Generate the shortest representation. + num_digits = 0; + char* data = buf.data(); + for (;;) { + int digit = numerator.divmod_assign(denominator); + bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. + // numerator + upper >[=] pow10: + bool high = add_compare(numerator, *upper, denominator) + even > 0; + data[num_digits++] = static_cast('0' + digit); + if (low || high) { + if (!low) { + ++data[num_digits - 1]; + } else if (high) { + int result = add_compare(numerator, numerator, denominator); + // Round half to even. + if (result > 0 || (result == 0 && (digit % 2) != 0)) + ++data[num_digits - 1]; + } + buf.try_resize(to_unsigned(num_digits)); + exp10 -= num_digits - 1; + return; + } + numerator *= 10; + lower *= 10; + if (upper != &lower) *upper *= 10; + } + } + // Generate the given number of digits. + exp10 -= num_digits - 1; + if (num_digits <= 0) { + auto digit = '0'; + if (num_digits == 0) { + denominator *= 10; + digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; + } + buf.push_back(digit); + return; + } + buf.try_resize(to_unsigned(num_digits)); + for (int i = 0; i < num_digits - 1; ++i) { + int digit = numerator.divmod_assign(denominator); + buf[i] = static_cast('0' + digit); + numerator *= 10; + } + int digit = numerator.divmod_assign(denominator); + auto result = add_compare(numerator, numerator, denominator); + if (result > 0 || (result == 0 && (digit % 2) != 0)) { + if (digit == 9) { + const auto overflow = '0' + 10; + buf[num_digits - 1] = overflow; + // Propagate the carry. + for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] == overflow) { + buf[0] = '1'; + if ((flags & dragon::fixed) != 0) + buf.push_back('0'); + else + ++exp10; + } + return; + } + ++digit; + } + buf[num_digits - 1] = static_cast('0' + digit); +} + +// Formats a floating-point number using the hexfloat format. +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, + buffer& buf) { + // float is passed as double to reduce the number of instantiations and to + // simplify implementation. + static_assert(!std::is_same::value, ""); + + using info = dragonbox::float_info; + + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename info::carrier_uint; + + constexpr auto num_float_significand_bits = + detail::num_significand_bits(); + + basic_fp f(value); + f.e += num_float_significand_bits; + if (!has_implicit_bit()) --f.e; + + constexpr auto num_fraction_bits = + num_float_significand_bits + (has_implicit_bit() ? 1 : 0); + constexpr auto num_xdigits = (num_fraction_bits + 3) / 4; + + constexpr auto leading_shift = ((num_xdigits - 1) * 4); + const auto leading_mask = carrier_uint(0xF) << leading_shift; + const auto leading_xdigit = + static_cast((f.f & leading_mask) >> leading_shift); + if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1); + + int print_xdigits = num_xdigits - 1; + if (specs.precision >= 0 && print_xdigits > specs.precision) { + const int shift = ((print_xdigits - specs.precision - 1) * 4); + const auto mask = carrier_uint(0xF) << shift; + const auto v = static_cast((f.f & mask) >> shift); + + if (v >= 8) { + const auto inc = carrier_uint(1) << (shift + 4); + f.f += inc; + f.f &= ~(inc - 1); + } + + // Check long double overflow + if (!has_implicit_bit()) { + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + if ((f.f & implicit_bit) == implicit_bit) { + f.f >>= 4; + f.e += 4; + } + } + + print_xdigits = specs.precision; + } + + char xdigits[num_bits() / 4]; + detail::fill_n(xdigits, sizeof(xdigits), '0'); + format_uint<4>(xdigits, f.f, num_xdigits, specs.upper); + + // Remove zero tail + while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits; + + buf.push_back('0'); + buf.push_back(specs.upper ? 'X' : 'x'); + buf.push_back(xdigits[0]); + if (specs.alt || print_xdigits > 0 || print_xdigits < specs.precision) + buf.push_back('.'); + buf.append(xdigits + 1, xdigits + 1 + print_xdigits); + for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back('0'); + + buf.push_back(specs.upper ? 'P' : 'p'); + + uint32_t abs_e; + if (f.e < 0) { + buf.push_back('-'); + abs_e = static_cast(-f.e); + } else { + buf.push_back('+'); + abs_e = static_cast(f.e); + } + format_decimal(appender(buf), abs_e, detail::count_digits(abs_e)); +} + +template ::value)> +FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, + buffer& buf) { + format_hexfloat(static_cast(value), specs, buf); +} + +constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t { + // For checking rounding thresholds. + // The kth entry is chosen to be the smallest integer such that the + // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k. + // It is equal to ceil(2^31 + 2^32/10^(k + 1)). + // These are stored in a string literal because we cannot have static arrays + // in constexpr functions and non-static ones are poorly optimized. + return U"\x9999999a\x828f5c29\x80418938\x80068db9\x8000a7c6\x800010c7" + U"\x800001ae\x8000002b"[index]; +} + +template +FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, + buffer& buf) -> int { + // float is passed as double to reduce the number of instantiations. + static_assert(!std::is_same::value, ""); + FMT_ASSERT(value >= 0, "value is negative"); + auto converted_value = convert_float(value); + + const bool fixed = specs.format == float_format::fixed; + if (value <= 0) { // <= instead of == to silence a warning. + if (precision <= 0 || !fixed) { + buf.push_back('0'); + return 0; + } + buf.try_resize(to_unsigned(precision)); + fill_n(buf.data(), precision, '0'); + return -precision; + } + + int exp = 0; + bool use_dragon = true; + unsigned dragon_flags = 0; + if (!is_fast_float() || is_constant_evaluated()) { + const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); + // Compute exp, an approximate power of 10, such that + // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). + // This is based on log10(value) == log2(value) / log2(10) and approximation + // of log2(value) by e + num_fraction_bits idea from double-conversion. + auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; + exp = static_cast(e); + if (e > exp) ++exp; // Compute ceil. + dragon_flags = dragon::fixup; + } else if (precision < 0) { + // Use Dragonbox for the shortest format. + if (specs.binary32) { + auto dec = dragonbox::to_decimal(static_cast(value)); + write(appender(buf), dec.significand); + return dec.exponent; + } + auto dec = dragonbox::to_decimal(static_cast(value)); + write(appender(buf), dec.significand); + return dec.exponent; + } else { + // Extract significand bits and exponent bits. + using info = dragonbox::float_info; + auto br = bit_cast(static_cast(value)); + + const uint64_t significand_mask = + (static_cast(1) << num_significand_bits()) - 1; + uint64_t significand = (br & significand_mask); + int exponent = static_cast((br & exponent_mask()) >> + num_significand_bits()); + + if (exponent != 0) { // Check if normal. + exponent -= exponent_bias() + num_significand_bits(); + significand |= + (static_cast(1) << num_significand_bits()); + significand <<= 1; + } else { + // Normalize subnormal inputs. + FMT_ASSERT(significand != 0, "zeros should not appear here"); + int shift = countl_zero(significand); + FMT_ASSERT(shift >= num_bits() - num_significand_bits(), + ""); + shift -= (num_bits() - num_significand_bits() - 2); + exponent = (std::numeric_limits::min_exponent - + num_significand_bits()) - + shift; + significand <<= shift; + } + + // Compute the first several nonzero decimal significand digits. + // We call the number we get the first segment. + const int k = info::kappa - dragonbox::floor_log10_pow2(exponent); + exp = -k; + const int beta = exponent + dragonbox::floor_log2_pow10(k); + uint64_t first_segment; + bool has_more_segments; + int digits_in_the_first_segment; + { + const auto r = dragonbox::umul192_upper128( + significand << beta, dragonbox::get_cached_power(k)); + first_segment = r.high(); + has_more_segments = r.low() != 0; + + // The first segment can have 18 ~ 19 digits. + if (first_segment >= 1000000000000000000ULL) { + digits_in_the_first_segment = 19; + } else { + // When it is of 18-digits, we align it to 19-digits by adding a bogus + // zero at the end. + digits_in_the_first_segment = 18; + first_segment *= 10; + } + } + + // Compute the actual number of decimal digits to print. + if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment); + + // Use Dragon4 only when there might be not enough digits in the first + // segment. + if (digits_in_the_first_segment > precision) { + use_dragon = false; + + if (precision <= 0) { + exp += digits_in_the_first_segment; + + if (precision < 0) { + // Nothing to do, since all we have are just leading zeros. + buf.try_resize(0); + } else { + // We may need to round-up. + buf.try_resize(1); + if ((first_segment | static_cast(has_more_segments)) > + 5000000000000000000ULL) { + buf[0] = '1'; + } else { + buf[0] = '0'; + } + } + } // precision <= 0 + else { + exp += digits_in_the_first_segment - precision; + + // When precision > 0, we divide the first segment into three + // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits + // in 32-bits which usually allows faster calculation than in + // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize + // division-by-constant for large 64-bit divisors, we do it here + // manually. The magic number 7922816251426433760 below is equal to + // ceil(2^(64+32) / 10^10). + const uint32_t first_subsegment = static_cast( + dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >> + 32); + const uint64_t second_third_subsegments = + first_segment - first_subsegment * 10000000000ULL; + + uint64_t prod; + uint32_t digits; + bool should_round_up; + int number_of_digits_to_print = precision > 9 ? 9 : precision; + + // Print a 9-digits subsegment, either the first or the second. + auto print_subsegment = [&](uint32_t subsegment, char* buffer) { + int number_of_digits_printed = 0; + + // If we want to print an odd number of digits from the subsegment, + if ((number_of_digits_to_print & 1) != 0) { + // Convert to 64-bit fixed-point fractional form with 1-digit + // integer part. The magic number 720575941 is a good enough + // approximation of 2^(32 + 24) / 10^8; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(720575941)) >> 24) + 1; + digits = static_cast(prod >> 32); + *buffer = static_cast('0' + digits); + number_of_digits_printed++; + } + // If we want to print an even number of digits from the + // first_subsegment, + else { + // Convert to 64-bit fixed-point fractional form with 2-digits + // integer part. The magic number 450359963 is a good enough + // approximation of 2^(32 + 20) / 10^7; see + // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case + // for details. + prod = ((subsegment * static_cast(450359963)) >> 20) + 1; + digits = static_cast(prod >> 32); + copy2(buffer, digits2(digits)); + number_of_digits_printed += 2; + } + + // Print all digit pairs. + while (number_of_digits_printed < number_of_digits_to_print) { + prod = static_cast(prod) * static_cast(100); + digits = static_cast(prod >> 32); + copy2(buffer + number_of_digits_printed, digits2(digits)); + number_of_digits_printed += 2; + } + }; + + // Print first subsegment. + print_subsegment(first_subsegment, buf.data()); + + // Perform rounding if the first subsegment is the last subsegment to + // print. + if (precision <= 9) { + // Rounding inside the subsegment. + // We round-up if: + // - either the fractional part is strictly larger than 1/2, or + // - the fractional part is exactly 1/2 and the last digit is odd. + // We rely on the following observations: + // - If fractional_part >= threshold, then the fractional part is + // strictly larger than 1/2. + // - If the MSB of fractional_part is set, then the fractional part + // must be at least 1/2. + // - When the MSB of fractional_part is set, either + // second_third_subsegments being nonzero or has_more_segments + // being true means there are further digits not printed, so the + // fractional part is strictly larger than 1/2. + if (precision < 9) { + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (second_third_subsegments != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + // In this case, the fractional part is at least 1/2 if and only if + // second_third_subsegments >= 5000000000ULL, and is strictly larger + // than 1/2 if we further have either second_third_subsegments > + // 5000000000ULL or has_more_segments == true. + else { + should_round_up = second_third_subsegments > 5000000000ULL || + (second_third_subsegments == 5000000000ULL && + ((digits & 1) != 0 || has_more_segments)); + } + } + // Otherwise, print the second subsegment. + else { + // Compilers are not aware of how to leverage the maximum value of + // second_third_subsegments to find out a better magic number which + // allows us to eliminate an additional shift. 1844674407370955162 = + // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))). + const uint32_t second_subsegment = + static_cast(dragonbox::umul128_upper64( + second_third_subsegments, 1844674407370955162ULL)); + const uint32_t third_subsegment = + static_cast(second_third_subsegments) - + second_subsegment * 10; + + number_of_digits_to_print = precision - 9; + print_subsegment(second_subsegment, buf.data() + 9); + + // Rounding inside the subsegment. + if (precision < 18) { + // The condition third_subsegment != 0 implies that the segment was + // of 19 digits, so in this case the third segment should be + // consisting of a genuine digit from the input. + uint32_t fractional_part = static_cast(prod); + should_round_up = + fractional_part >= fractional_part_rounding_thresholds( + 8 - number_of_digits_to_print) || + ((fractional_part >> 31) & + ((digits & 1) | (third_subsegment != 0) | + has_more_segments)) != 0; + } + // Rounding at the subsegment boundary. + else { + // In this case, the segment must be of 19 digits, thus + // the third subsegment should be consisting of a genuine digit from + // the input. + should_round_up = third_subsegment > 5 || + (third_subsegment == 5 && + ((digits & 1) != 0 || has_more_segments)); + } + } + + // Round-up if necessary. + if (should_round_up) { + ++buf[precision - 1]; + for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) { + buf[i] = '0'; + ++buf[i - 1]; + } + if (buf[0] > '9') { + buf[0] = '1'; + if (fixed) + buf[precision++] = '0'; + else + ++exp; + } + } + buf.try_resize(to_unsigned(precision)); + } + } // if (digits_in_the_first_segment > precision) + else { + // Adjust the exponent for its use in Dragon4. + exp += digits_in_the_first_segment - 1; + } + } + if (use_dragon) { + auto f = basic_fp(); + bool is_predecessor_closer = specs.binary32 + ? f.assign(static_cast(value)) + : f.assign(converted_value); + if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; + if (fixed) dragon_flags |= dragon::fixed; + // Limit precision to the maximum possible number of significant digits in + // an IEEE754 double because we don't need to generate zeros. + const int max_double_digits = 767; + if (precision > max_double_digits) precision = max_double_digits; + format_dragon(f, dragon_flags, precision, buf, exp); + } + if (!fixed && !specs.showpoint) { + // Remove trailing zeros. + auto num_digits = buf.size(); + while (num_digits > 0 && buf[num_digits - 1] == '0') { + --num_digits; + ++exp; + } + buf.try_resize(num_digits); + } + return exp; +} + +template +FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs, + locale_ref loc) -> OutputIt { + sign_t sign = specs.sign; + if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. + sign = sign::minus; + value = -value; + } else if (sign == sign::minus) { + sign = sign::none; + } + + if (!detail::isfinite(value)) + return write_nonfinite(out, detail::isnan(value), specs, sign); + + if (specs.align == align::numeric && sign) { + auto it = reserve(out, 1); + *it++ = detail::sign(sign); + out = base_iterator(out, it); + sign = sign::none; + if (specs.width != 0) --specs.width; + } + + memory_buffer buffer; + if (specs.type == presentation_type::hexfloat) { + if (sign) buffer.push_back(detail::sign(sign)); + format_hexfloat(convert_float(value), specs, buffer); + return write_bytes(out, {buffer.data(), buffer.size()}, + specs); + } + + int precision = specs.precision >= 0 || specs.type == presentation_type::none + ? specs.precision + : 6; + if (specs.type == presentation_type::exp) { + if (precision == max_value()) + report_error("number is too big"); + else + ++precision; + } else if (specs.type != presentation_type::fixed && precision == 0) { + precision = 1; + } + float_specs fspecs = parse_float_type_spec(specs); + fspecs.sign = sign; + if (const_check(std::is_same())) fspecs.binary32 = true; + int exp = format_float(convert_float(value), precision, fspecs, buffer); + fspecs.precision = precision; + auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; + return write_float(out, f, specs, fspecs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs, + locale_ref loc = {}) -> OutputIt { + if (const_check(!is_supported_floating_point(value))) return out; + return specs.localized && write_loc(out, value, specs, loc) + ? out + : write_float(out, value, specs, loc); +} + +template ::value)> +FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { + if (is_constant_evaluated()) return write(out, value, format_specs()); + if (const_check(!is_supported_floating_point(value))) return out; + + auto sign = sign_t::none; + if (detail::signbit(value)) { + sign = sign::minus; + value = -value; + } + + constexpr auto specs = format_specs(); + using floaty = conditional_t::value, double, T>; + using floaty_uint = typename dragonbox::float_info::carrier_uint; + floaty_uint mask = exponent_mask(); + if ((bit_cast(value) & mask) == mask) + return write_nonfinite(out, std::isnan(value), specs, sign); + + auto fspecs = float_specs(); + fspecs.sign = sign; + auto dec = dragonbox::to_decimal(static_cast(value)); + return write_float(out, dec, specs, fspecs, {}); +} + +template ::value && + !is_fast_float::value)> +inline auto write(OutputIt out, T value) -> OutputIt { + return write(out, value, format_specs()); +} + +template +auto write(OutputIt out, monostate, format_specs = {}, locale_ref = {}) + -> OutputIt { + FMT_ASSERT(false, ""); + return out; +} + +template +FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) + -> OutputIt { + return copy_noinline(value.begin(), value.end(), out); +} + +template ::value)> +constexpr auto write(OutputIt out, const T& value) -> OutputIt { + return write(out, to_string_view(value)); +} + +// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. +template < + typename Char, typename OutputIt, typename T, + bool check = + std::is_enum::value && !std::is_same::value && + mapped_type_constant>::value != + type::custom_type, + FMT_ENABLE_IF(check)> +FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { + return write(out, static_cast>(value)); +} + +template ::value)> +FMT_CONSTEXPR auto write(OutputIt out, T value, const format_specs& specs = {}, + locale_ref = {}) -> OutputIt { + return specs.type != presentation_type::none && + specs.type != presentation_type::string + ? write(out, value ? 1 : 0, specs, {}) + : write_bytes(out, value ? "true" : "false", specs); +} + +template +FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { + auto it = reserve(out, 1); + *it++ = value; + return base_iterator(out, it); +} + +template +FMT_CONSTEXPR20 auto write(OutputIt out, const Char* value) -> OutputIt { + if (value) return write(out, basic_string_view(value)); + report_error("string pointer is null"); + return out; +} + +template ::value)> +auto write(OutputIt out, const T* value, const format_specs& specs = {}, + locale_ref = {}) -> OutputIt { + return write_ptr(out, bit_cast(value), &specs); +} + +// A write overload that handles implicit conversions. +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< + std::is_class::value && !has_to_string_view::value && + !is_floating_point::value && !std::is_same::value && + !std::is_same().map( + value))>>::value, + OutputIt> { + return write(out, arg_mapper().map(value)); +} + +template > +FMT_CONSTEXPR auto write(OutputIt out, const T& value) + -> enable_if_t::value == + type::custom_type && + !std::is_fundamental::value, + OutputIt> { + auto formatter = typename Context::template formatter_type(); + auto parse_ctx = typename Context::parse_context_type({}); + formatter.parse(parse_ctx); + auto ctx = Context(out, {}, {}); + return formatter.format(value, ctx); +} + +// An argument visitor that formats the argument and writes it via the output +// iterator. It's a class and not a generic lambda for compatibility with C++11. +template struct default_arg_formatter { + using iterator = basic_appender; + using context = buffered_context; + + iterator out; + basic_format_args args; + locale_ref loc; + + template auto operator()(T value) -> iterator { + return write(out, value); + } + auto operator()(typename basic_format_arg::handle h) -> iterator { + basic_format_parse_context parse_ctx({}); + context format_ctx(out, args, loc); + h.format(parse_ctx, format_ctx); + return format_ctx.out(); + } +}; + +template struct arg_formatter { + using iterator = basic_appender; + using context = buffered_context; + + iterator out; + const format_specs& specs; + locale_ref locale; + + template + FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { + return detail::write(out, value, specs, locale); + } + auto operator()(typename basic_format_arg::handle) -> iterator { + // User-defined types are handled separately because they require access + // to the parse context. + return out; + } +}; + +struct width_checker { + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) report_error("negative width"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + report_error("width is not integer"); + return 0; + } +}; + +struct precision_checker { + template ::value)> + FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { + if (is_negative(value)) report_error("negative precision"); + return static_cast(value); + } + + template ::value)> + FMT_CONSTEXPR auto operator()(T) -> unsigned long long { + report_error("precision is not integer"); + return 0; + } +}; + +template +FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg) -> int { + unsigned long long value = arg.visit(Handler()); + if (value > to_unsigned(max_value())) report_error("number is too big"); + return static_cast(value); +} + +template +FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) -> decltype(ctx.arg(id)) { + auto arg = ctx.arg(id); + if (!arg) report_error("argument not found"); + return arg; +} + +template +FMT_CONSTEXPR void handle_dynamic_spec(int& value, + arg_ref ref, + Context& ctx) { + switch (ref.kind) { + case arg_id_kind::none: + break; + case arg_id_kind::index: + value = detail::get_dynamic_spec(get_arg(ctx, ref.val.index)); + break; + case arg_id_kind::name: + value = detail::get_dynamic_spec(get_arg(ctx, ref.val.name)); + break; + } +} + +#if FMT_USE_USER_DEFINED_LITERALS +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template Str> +struct statically_named_arg : view { + static constexpr auto name = Str.data; + + const T& value; + statically_named_arg(const T& v) : value(v) {} +}; + +template Str> +struct is_named_arg> : std::true_type {}; + +template Str> +struct is_statically_named_arg> + : std::true_type {}; + +template Str> +struct udl_arg { + template auto operator=(T&& value) const { + return statically_named_arg(std::forward(value)); + } +}; +# else +template struct udl_arg { + const Char* str; + + template auto operator=(T&& value) const -> named_arg { + return {str, std::forward(value)}; + } +}; +# endif +#endif // FMT_USE_USER_DEFINED_LITERALS + +template +auto vformat(const Locale& loc, basic_string_view fmt, + typename detail::vformat_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return {buf.data(), buf.size()}; +} + +using format_func = void (*)(detail::buffer&, int, const char*); + +FMT_API void format_error_code(buffer& out, int error_code, + string_view message) noexcept; + +using fmt::report_error; +FMT_API void report_error(format_func func, int error_code, + const char* message) noexcept; +} // namespace detail + +FMT_BEGIN_EXPORT +FMT_API auto vsystem_error(int error_code, string_view format_str, + format_args args) -> std::system_error; + +/** + * Constructs `std::system_error` with a message formatted with + * `fmt::format(fmt, args...)`. + * `error_code` is a system error code as given by `errno`. + * + * **Example**: + * + * // This throws std::system_error with the description + * // cannot open file 'madeup': No such file or directory + * // or similar (system message may vary). + * const char* filename = "madeup"; + * std::FILE* file = std::fopen(filename, "r"); + * if (!file) + * throw fmt::system_error(errno, "cannot open file '{}'", filename); + */ +template +auto system_error(int error_code, format_string fmt, T&&... args) + -> std::system_error { + return vsystem_error(error_code, fmt, fmt::make_format_args(args...)); +} + +/** + * Formats an error message for an error returned by an operating system or a + * language runtime, for example a file opening error, and writes it to `out`. + * The format is the same as the one used by `std::system_error(ec, message)` + * where `ec` is `std::error_code(error_code, std::generic_category())`. + * It is implementation-defined but normally looks like: + * + * : + * + * where `` is the passed message and `` is the system + * message corresponding to the error code. + * `error_code` is a system error code as given by `errno`. + */ +FMT_API void format_system_error(detail::buffer& out, int error_code, + const char* message) noexcept; + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_system_error(int error_code, const char* message) noexcept; + +/// A fast integer formatter. +class format_int { + 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_; + + template + FMT_CONSTEXPR20 auto format_unsigned(UInt value) -> char* { + auto n = static_cast>(value); + return detail::format_decimal(buffer_, n, buffer_size - 1).begin; + } + + template + FMT_CONSTEXPR20 auto format_signed(Int value) -> char* { + auto abs_value = static_cast>(value); + bool negative = value < 0; + if (negative) abs_value = 0 - abs_value; + auto begin = format_unsigned(abs_value); + if (negative) *--begin = '-'; + return begin; + } + + public: + explicit FMT_CONSTEXPR20 format_int(int value) : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(long value) + : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(long long value) + : str_(format_signed(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned value) + : str_(format_unsigned(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned long value) + : str_(format_unsigned(value)) {} + explicit FMT_CONSTEXPR20 format_int(unsigned long long value) + : str_(format_unsigned(value)) {} + + /// Returns the number of characters written to the output buffer. + FMT_CONSTEXPR20 auto size() const -> size_t { + return detail::to_unsigned(buffer_ - str_ + buffer_size - 1); + } + + /// Returns a pointer to the output buffer content. No terminating null + /// character is appended. + FMT_CONSTEXPR20 auto data() const -> const char* { return str_; } + + /// Returns a pointer to the output buffer content with terminating null + /// character appended. + FMT_CONSTEXPR20 auto c_str() const -> const char* { + buffer_[buffer_size - 1] = '\0'; + return str_; + } + + /// Returns the content of the output buffer as an `std::string`. + auto str() const -> std::string { return std::string(str_, size()); } +}; + +template +struct formatter::value>> + : formatter, Char> { + template + auto format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) { + auto&& val = format_as(value); // Make an lvalue reference for format. + return formatter, Char>::format(val, ctx); + } +}; + +#define FMT_FORMAT_AS(Type, Base) \ + template \ + struct formatter : formatter { \ + template \ + auto format(Type value, FormatContext& ctx) const -> decltype(ctx.out()) { \ + return formatter::format(value, ctx); \ + } \ + } + +FMT_FORMAT_AS(signed char, int); +FMT_FORMAT_AS(unsigned char, unsigned); +FMT_FORMAT_AS(short, int); +FMT_FORMAT_AS(unsigned short, unsigned); +FMT_FORMAT_AS(long, detail::long_type); +FMT_FORMAT_AS(unsigned long, detail::ulong_type); +FMT_FORMAT_AS(Char*, const Char*); +FMT_FORMAT_AS(std::nullptr_t, const void*); +FMT_FORMAT_AS(detail::std_string_view, basic_string_view); +FMT_FORMAT_AS(void*, const void*); + +template +class formatter, Char> + : public formatter, Char> {}; + +template +struct formatter : formatter, Char> {}; + +/** + * Converts `p` to `const void*` for pointer formatting. + * + * **Example**: + * + * auto s = fmt::format("{}", fmt::ptr(p)); + */ +template auto ptr(T p) -> const void* { + static_assert(std::is_pointer::value, ""); + return detail::bit_cast(p); +} + +/** + * Converts `e` to the underlying type. + * + * **Example**: + * + * enum class color { red, green, blue }; + * auto s = fmt::format("{}", fmt::underlying(color::red)); + */ +template +constexpr auto underlying(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} + +namespace enums { +template ::value)> +constexpr auto format_as(Enum e) noexcept -> underlying_t { + return static_cast>(e); +} +} // namespace enums + +class bytes { + private: + string_view data_; + friend struct formatter; + + public: + explicit bytes(string_view data) : data_(data) {} +}; + +template <> struct formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::string_type); + } + + template + auto format(bytes b, FormatContext& ctx) const -> decltype(ctx.out()) { + auto specs = specs_; + detail::handle_dynamic_spec(specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, ctx); + return detail::write_bytes(ctx.out(), b.data_, specs); + } +}; + +// group_digits_view is not derived from view because it copies the argument. +template struct group_digits_view { + T value; +}; + +/** + * Returns a view that formats an integer value using ',' as a + * locale-independent thousands separator. + * + * **Example**: + * + * fmt::print("{}", fmt::group_digits(12345)); + * // Output: "12,345" + */ +template auto group_digits(T value) -> group_digits_view { + return {value}; +} + +template struct formatter> : formatter { + private: + detail::dynamic_format_specs<> specs_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const char* { + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type::int_type); + } + + template + auto format(group_digits_view t, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + detail::handle_dynamic_spec(specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, ctx); + auto arg = detail::make_write_int_arg(t.value, specs.sign); + return detail::write_int( + ctx.out(), static_cast>(arg.abs_value), + arg.prefix, specs, detail::digit_grouping("\3", ",")); + } +}; + +template struct nested_view { + const formatter* fmt; + const T* value; +}; + +template +struct formatter, Char> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + template + auto format(nested_view view, FormatContext& ctx) const + -> decltype(ctx.out()) { + return view.fmt->format(*view.value, ctx); + } +}; + +template struct nested_formatter { + private: + int width_; + detail::fill_t fill_; + align_t align_ : 4; + formatter formatter_; + + public: + constexpr nested_formatter() : width_(0), align_(align_t::none) {} + + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto specs = detail::dynamic_format_specs(); + auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx, + detail::type::none_type); + width_ = specs.width; + fill_ = specs.fill; + align_ = specs.align; + ctx.advance_to(it); + return formatter_.parse(ctx); + } + + template + auto write_padded(FormatContext& ctx, F write) const -> decltype(ctx.out()) { + if (width_ == 0) return write(ctx.out()); + auto buf = basic_memory_buffer(); + write(basic_appender(buf)); + auto specs = format_specs(); + specs.width = width_; + specs.fill = fill_; + specs.align = align_; + return detail::write( + ctx.out(), basic_string_view(buf.data(), buf.size()), specs); + } + + auto nested(const T& value) const -> nested_view { + return nested_view{&formatter_, &value}; + } +}; + +/** + * Converts `value` to `std::string` using the default format for type `T`. + * + * **Example**: + * + * std::string answer = fmt::to_string(42); + */ +template ::value && + !detail::has_format_as::value)> +inline auto to_string(const T& value) -> std::string { + auto buffer = memory_buffer(); + detail::write(appender(buffer), value); + return {buffer.data(), buffer.size()}; +} + +template ::value)> +FMT_NODISCARD inline auto to_string(T value) -> std::string { + // The buffer should be large enough to store the number including the sign + // or "false" for bool. + constexpr int max_size = detail::digits10() + 2; + char buffer[max_size > 5 ? static_cast(max_size) : 5]; + char* begin = buffer; + return std::string(begin, detail::write(begin, value)); +} + +template +FMT_NODISCARD auto to_string(const basic_memory_buffer& buf) + -> std::basic_string { + auto size = buf.size(); + detail::assume(size < std::basic_string().max_size()); + return std::basic_string(buf.data(), size); +} + +template ::value && + detail::has_format_as::value)> +inline auto to_string(const T& value) -> std::string { + return to_string(format_as(value)); +} + +FMT_END_EXPORT + +namespace detail { + +template +void vformat_to(buffer& buf, basic_string_view fmt, + typename vformat_args::type args, locale_ref loc) { + auto out = basic_appender(buf); + if (fmt.size() == 2 && equal2(fmt.data(), "{}")) { + auto arg = args.get(0); + if (!arg) report_error("argument not found"); + arg.visit(default_arg_formatter{out, args, loc}); + return; + } + + struct format_handler { + basic_format_parse_context parse_context; + buffered_context context; + + format_handler(basic_appender p_out, basic_string_view str, + basic_format_args> p_args, + locale_ref p_loc) + : parse_context(str), context(p_out, p_args, p_loc) {} + + void on_text(const Char* begin, const Char* end) { + auto text = basic_string_view(begin, to_unsigned(end - begin)); + context.advance_to(write(context.out(), text)); + } + + FMT_CONSTEXPR auto on_arg_id() -> int { + return parse_context.next_arg_id(); + } + FMT_CONSTEXPR auto on_arg_id(int id) -> int { + parse_context.check_arg_id(id); + return id; + } + FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { + parse_context.check_arg_id(id); + int arg_id = context.arg_id(id); + if (arg_id < 0) report_error("argument not found"); + return arg_id; + } + + FMT_INLINE void on_replacement_field(int id, const Char*) { + auto arg = get_arg(context, id); + context.advance_to(arg.visit(default_arg_formatter{ + context.out(), context.args(), context.locale()})); + } + + auto on_format_specs(int id, const Char* begin, const Char* end) + -> const Char* { + auto arg = get_arg(context, id); + // Not using a visitor for custom types gives better codegen. + if (arg.format_custom(begin, parse_context, context)) + return parse_context.begin(); + auto specs = detail::dynamic_format_specs(); + begin = parse_format_specs(begin, end, specs, parse_context, arg.type()); + detail::handle_dynamic_spec( + specs.width, specs.width_ref, context); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, context); + if (begin == end || *begin != '}') + report_error("missing '}' in format string"); + context.advance_to(arg.visit( + arg_formatter{context.out(), specs, context.locale()})); + return begin; + } + + FMT_NORETURN void on_error(const char* message) { report_error(message); } + }; + detail::parse_format_string(fmt, format_handler(out, fmt, args, loc)); +} + +FMT_BEGIN_EXPORT + +#ifndef FMT_HEADER_ONLY +extern template FMT_API void vformat_to(buffer&, string_view, + typename vformat_args<>::type, + locale_ref); +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto thousands_sep_impl(locale_ref) + -> thousands_sep_result; +extern template FMT_API auto decimal_point_impl(locale_ref) -> char; +extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; +#endif // FMT_HEADER_ONLY + +FMT_END_EXPORT + +template +template +FMT_CONSTEXPR FMT_INLINE auto native_formatter::format( + const T& val, FormatContext& ctx) const -> decltype(ctx.out()) { + if (specs_.width_ref.kind == arg_id_kind::none && + specs_.precision_ref.kind == arg_id_kind::none) { + return write(ctx.out(), val, specs_, ctx.locale()); + } + auto specs = specs_; + handle_dynamic_spec(specs.width, specs.width_ref, ctx); + handle_dynamic_spec(specs.precision, specs.precision_ref, + ctx); + return write(ctx.out(), val, specs, ctx.locale()); +} + +} // namespace detail + +FMT_BEGIN_EXPORT + +template +struct formatter + : detail::native_formatter {}; + +#if FMT_USE_USER_DEFINED_LITERALS +inline namespace literals { +/** + * User-defined literal equivalent of `fmt::arg`. + * + * **Example**: + * + * using namespace fmt::literals; + * fmt::print("The answer is {answer}.", "answer"_a=42); + */ +# if FMT_USE_NONTYPE_TEMPLATE_ARGS +template constexpr auto operator""_a() { + using char_t = remove_cvref_t; + return detail::udl_arg(); +} +# else +constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg { + return {s}; +} +# endif +} // namespace literals +#endif // FMT_USE_USER_DEFINED_LITERALS + +FMT_API auto vformat(string_view fmt, format_args args) -> std::string; + +/** + * Formats `args` according to specifications in `fmt` and returns the result + * as a string. + * + * **Example**: + * + * #include + * std::string message = fmt::format("The answer is {}.", 42); + */ +template +FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) + -> std::string { + return vformat(fmt, fmt::make_format_args(args...)); +} + +template ::value)> +inline auto vformat(const Locale& loc, string_view fmt, format_args args) + -> std::string { + return detail::vformat(loc, fmt, args); +} + +template ::value)> +inline auto format(const Locale& loc, format_string fmt, T&&... args) + -> std::string { + return fmt::vformat(loc, string_view(fmt), fmt::make_format_args(args...)); +} + +template ::value&& + detail::is_locale::value)> +auto vformat_to(OutputIt out, const Locale& loc, string_view fmt, + format_args args) -> OutputIt { + using detail::get_buffer; + auto&& buf = get_buffer(out); + detail::vformat_to(buf, fmt, args, detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template ::value&& + detail::is_locale::value)> +FMT_INLINE auto format_to(OutputIt out, const Locale& loc, + format_string fmt, T&&... args) -> OutputIt { + return vformat_to(out, loc, fmt, fmt::make_format_args(args...)); +} + +template ::value)> +FMT_NODISCARD FMT_INLINE auto formatted_size(const Locale& loc, + format_string fmt, + T&&... args) -> size_t { + auto buf = detail::counting_buffer<>(); + detail::vformat_to(buf, fmt, fmt::make_format_args(args...), + detail::locale_ref(loc)); + return buf.count(); +} + +FMT_END_EXPORT + +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format-inl.h" +#else +# define FMT_FUNC +#endif + +// Restore _LIBCPP_REMOVE_TRANSITIVE_INCLUDES. +#ifdef FMT_REMOVE_TRANSITIVE_INCLUDES +# undef _LIBCPP_REMOVE_TRANSITIVE_INCLUDES +#endif + +#endif // FMT_FORMAT_H_ diff --git a/cpp_src/vendor/fmt/os.cc b/cpp_src/vendor/fmt/os.cc new file mode 100644 index 000000000..273664997 --- /dev/null +++ b/cpp_src/vendor/fmt/os.cc @@ -0,0 +1,403 @@ +// Formatting library for C++ - optional OS-specific functionality +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +// Disable bogus MSVC warnings. +#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "fmt/os.h" + +#ifndef FMT_MODULE +# include + +# if FMT_USE_FCNTL +# include +# include + +# ifdef _WRS_KERNEL // VxWorks7 kernel +# include // getpagesize +# endif + +# ifndef _WIN32 +# include +# else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# endif // _WIN32 +# endif // FMT_USE_FCNTL + +# ifdef _WIN32 +# include +# endif +#endif + +#ifdef _WIN32 +# ifndef S_IRUSR +# define S_IRUSR _S_IREAD +# endif +# ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +# endif +# ifndef S_IRGRP +# define S_IRGRP 0 +# endif +# ifndef S_IWGRP +# define S_IWGRP 0 +# endif +# ifndef S_IROTH +# define S_IROTH 0 +# endif +# ifndef S_IWOTH +# define S_IWOTH 0 +# endif +#endif + +namespace { +#ifdef _WIN32 +// Return type of read and write functions. +using rwresult = int; + +// On Windows the count argument to read and write is unsigned, so convert +// it from size_t preventing integer overflow. +inline unsigned convert_rwcount(std::size_t count) { + return count <= UINT_MAX ? static_cast(count) : UINT_MAX; +} +#elif FMT_USE_FCNTL +// Return type of read and write functions. +using rwresult = ssize_t; + +inline std::size_t convert_rwcount(std::size_t count) { return count; } +#endif +} // namespace + +FMT_BEGIN_NAMESPACE + +#ifdef _WIN32 +namespace detail { + +class system_message { + system_message(const system_message&) = delete; + void operator=(const system_message&) = delete; + + unsigned long result_; + wchar_t* message_; + + static bool is_whitespace(wchar_t c) noexcept { + return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; + } + + public: + explicit system_message(unsigned long error_code) + : result_(0), message_(nullptr) { + result_ = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&message_), 0, nullptr); + if (result_ != 0) { + while (result_ != 0 && is_whitespace(message_[result_ - 1])) { + --result_; + } + } + } + ~system_message() { LocalFree(message_); } + explicit operator bool() const noexcept { return result_ != 0; } + operator basic_string_view() const noexcept { + return basic_string_view(message_, result_); + } +}; + +class utf8_system_category final : public std::error_category { + public: + const char* name() const noexcept override { return "system"; } + std::string message(int error_code) const override { + auto&& msg = system_message(error_code); + if (msg) { + auto utf8_message = to_utf8(); + if (utf8_message.convert(msg)) { + return utf8_message.str(); + } + } + return "unknown error"; + } +}; + +} // namespace detail + +FMT_API const std::error_category& system_category() noexcept { + static const detail::utf8_system_category category; + return category; +} + +std::system_error vwindows_error(int err_code, string_view format_str, + format_args args) { + auto ec = std::error_code(err_code, system_category()); + return std::system_error(ec, vformat(format_str, args)); +} + +void detail::format_windows_error(detail::buffer& out, int error_code, + const char* message) noexcept { + FMT_TRY { + auto&& msg = system_message(error_code); + if (msg) { + auto utf8_message = to_utf8(); + if (utf8_message.convert(msg)) { + fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, + string_view(utf8_message)); + return; + } + } + } + FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +void report_windows_error(int error_code, const char* message) noexcept { + report_error(detail::format_windows_error, error_code, message); +} +#endif // _WIN32 + +buffered_file::~buffered_file() noexcept { + if (file_ && FMT_SYSTEM(fclose(file_)) != 0) + report_system_error(errno, "cannot close file"); +} + +buffered_file::buffered_file(cstring_view filename, cstring_view mode) { + FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), + nullptr); + if (!file_) + FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), + filename.c_str())); +} + +void buffered_file::close() { + if (!file_) return; + int result = FMT_SYSTEM(fclose(file_)); + file_ = nullptr; + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); +} + +int buffered_file::descriptor() const { +#ifdef FMT_HAS_SYSTEM + // fileno is a macro on OpenBSD. +# ifdef fileno +# undef fileno +# endif + int fd = FMT_POSIX_CALL(fileno(file_)); +#elif defined(_WIN32) + int fd = _fileno(file_); +#else + int fd = fileno(file_); +#endif + if (fd == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); + return fd; +} + +#if FMT_USE_FCNTL +# ifdef _WIN32 +using mode_t = int; +# endif + +constexpr mode_t default_open_mode = + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + +file::file(cstring_view path, int oflag) { +# if defined(_WIN32) && !defined(__MINGW32__) + fd_ = -1; + auto converted = detail::utf8_to_utf16(string_view(path.c_str())); + *this = file::open_windows_file(converted.c_str(), oflag); +# else + FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); + if (fd_ == -1) + FMT_THROW( + system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); +# endif +} + +file::~file() noexcept { + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) + report_system_error(errno, "cannot close file"); +} + +void file::close() { + if (fd_ == -1) return; + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + int result = FMT_POSIX_CALL(close(fd_)); + fd_ = -1; + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); +} + +long long file::size() const { +# ifdef _WIN32 + // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT + // is less than 0x0500 as is the case with some default MinGW builds. + // Both functions support large file sizes. + DWORD size_upper = 0; + HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); + DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); + if (size_lower == INVALID_FILE_SIZE) { + DWORD error = GetLastError(); + if (error != NO_ERROR) + FMT_THROW(windows_error(GetLastError(), "cannot get file size")); + } + unsigned long long long_size = size_upper; + return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; +# else + using Stat = struct stat; + Stat file_stat = Stat(); + if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); + static_assert(sizeof(long long) >= sizeof(file_stat.st_size), + "return type of file::size is not large enough"); + return file_stat.st_size; +# endif +} + +std::size_t file::read(void* buffer, std::size_t count) { + rwresult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); + return detail::to_unsigned(result); +} + +std::size_t file::write(const void* buffer, std::size_t count) { + rwresult result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); + if (result < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); + return detail::to_unsigned(result); +} + +file file::dup(int fd) { + // Don't retry as dup doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html + int new_fd = FMT_POSIX_CALL(dup(fd)); + if (new_fd == -1) + FMT_THROW(system_error( + errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); + return file(new_fd); +} + +void file::dup2(int fd) { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) { + FMT_THROW(system_error( + errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, + fd)); + } +} + +void file::dup2(int fd, std::error_code& ec) noexcept { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) ec = std::error_code(errno, std::generic_category()); +} + +buffered_file file::fdopen(const char* mode) { +// Don't retry as fdopen doesn't return EINTR. +# if defined(__MINGW32__) && defined(_POSIX_) + FILE* f = ::fdopen(fd_, mode); +# else + FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); +# endif + if (!f) { + FMT_THROW(system_error( + errno, FMT_STRING("cannot associate stream with file descriptor"))); + } + buffered_file bf(f); + fd_ = -1; + return bf; +} + +# if defined(_WIN32) && !defined(__MINGW32__) +file file::open_windows_file(wcstring_view path, int oflag) { + int fd = -1; + auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); + if (fd == -1) { + FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), + detail::to_utf8(path.c_str()).c_str())); + } + return file(fd); +} +# endif + +pipe::pipe() { + int fds[2] = {}; +# ifdef _WIN32 + // Make the default pipe capacity same as on Linux 2.6.11+. + enum { DEFAULT_CAPACITY = 65536 }; + int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); +# else + // Don't retry as the pipe function doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html + int result = FMT_POSIX_CALL(pipe(fds)); +# endif + if (result != 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); + // The following assignments don't throw. + read_end = file(fds[0]); + write_end = file(fds[1]); +} + +# if !defined(__MSDOS__) +long getpagesize() { +# ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +# else +# ifdef _WRS_KERNEL + long size = FMT_POSIX_CALL(getpagesize()); +# else + long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); +# endif + + if (size < 0) + FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); + return size; +# endif +} +# endif + +namespace detail { + +void file_buffer::grow(buffer& buf, size_t) { + if (buf.size() == buf.capacity()) static_cast(buf).flush(); +} + +file_buffer::file_buffer(cstring_view path, const ostream_params& params) + : buffer(grow), file_(path, params.oflag) { + set(new char[params.buffer_size], params.buffer_size); +} + +file_buffer::file_buffer(file_buffer&& other) noexcept + : buffer(grow, other.data(), other.size(), other.capacity()), + file_(std::move(other.file_)) { + other.clear(); + other.set(nullptr, 0); +} + +file_buffer::~file_buffer() { + flush(); + delete[] data(); +} +} // namespace detail + +ostream::~ostream() = default; +#endif // FMT_USE_FCNTL +FMT_END_NAMESPACE diff --git a/cpp_src/vendor/fmt/os.h b/cpp_src/vendor/fmt/os.h new file mode 100644 index 000000000..5c85ea08f --- /dev/null +++ b/cpp_src/vendor/fmt/os.h @@ -0,0 +1,439 @@ +// Formatting library for C++ - optional OS-specific functionality +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OS_H_ +#define FMT_OS_H_ + +#include "format.h" + +#ifndef FMT_MODULE +# include +# include +# include +# include // std::system_error + +# if FMT_HAS_INCLUDE() +# include // LC_NUMERIC_MASK on macOS +# endif +#endif // FMT_MODULE + +#ifndef FMT_USE_FCNTL +// UWP doesn't provide _pipe. +# if FMT_HAS_INCLUDE("winapifamily.h") +# include +# endif +# if (FMT_HAS_INCLUDE() || defined(__APPLE__) || \ + defined(__linux__)) && \ + (!defined(WINAPI_FAMILY) || \ + (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) +# include // for O_RDONLY +# define FMT_USE_FCNTL 1 +# else +# define FMT_USE_FCNTL 0 +# endif +#endif + +#ifndef FMT_POSIX +# if defined(_WIN32) && !defined(__MINGW32__) +// Fix warnings about deprecated symbols. +# define FMT_POSIX(call) _##call +# else +# define FMT_POSIX(call) call +# endif +#endif + +// Calls to system functions are wrapped in FMT_SYSTEM for testability. +#ifdef FMT_SYSTEM +# define FMT_HAS_SYSTEM +# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) +#else +# define FMT_SYSTEM(call) ::call +# ifdef _WIN32 +// Fix warnings about deprecated symbols. +# define FMT_POSIX_CALL(call) ::_##call +# else +# define FMT_POSIX_CALL(call) ::call +# endif +#endif + +// Retries the expression while it evaluates to error_result and errno +// equals to EINTR. +#ifndef _WIN32 +# define FMT_RETRY_VAL(result, expression, error_result) \ + do { \ + (result) = (expression); \ + } while ((result) == (error_result) && errno == EINTR) +#else +# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) +#endif + +#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +/** + * A reference to a null-terminated string. It can be constructed from a C + * string or `std::string`. + * + * You can use one of the following type aliases for common character types: + * + * +---------------+-----------------------------+ + * | Type | Definition | + * +===============+=============================+ + * | cstring_view | basic_cstring_view | + * +---------------+-----------------------------+ + * | wcstring_view | basic_cstring_view | + * +---------------+-----------------------------+ + * + * This class is most useful as a parameter type for functions that wrap C APIs. + */ +template class basic_cstring_view { + private: + const Char* data_; + + public: + /// Constructs a string reference object from a C string. + basic_cstring_view(const Char* s) : data_(s) {} + + /// Constructs a string reference from an `std::string` object. + basic_cstring_view(const std::basic_string& s) : data_(s.c_str()) {} + + /// Returns the pointer to a C string. + auto c_str() const -> const Char* { return data_; } +}; + +using cstring_view = basic_cstring_view; +using wcstring_view = basic_cstring_view; + +#ifdef _WIN32 +FMT_API const std::error_category& system_category() noexcept; + +namespace detail { +FMT_API void format_windows_error(buffer& out, int error_code, + const char* message) noexcept; +} + +FMT_API std::system_error vwindows_error(int error_code, string_view format_str, + format_args args); + +/** + * Constructs a `std::system_error` 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`. + * If `error_code` is not a valid error code such as -1, the system message + * will look like "error -1". + * + * **Example**: + * + * // This throws a system_error with the description + * // cannot open file 'madeup': The system cannot find the file + * specified. + * // or similar (system message may vary). + * const char *filename = "madeup"; + * LPOFSTRUCT of = LPOFSTRUCT(); + * HFILE file = OpenFile(filename, &of, OF_READ); + * if (file == HFILE_ERROR) { + * throw fmt::windows_error(GetLastError(), + * "cannot open file '{}'", filename); + * } + */ +template +std::system_error windows_error(int error_code, string_view message, + const Args&... args) { + return vwindows_error(error_code, message, fmt::make_format_args(args...)); +} + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +FMT_API void report_windows_error(int error_code, const char* message) noexcept; +#else +inline auto system_category() noexcept -> const std::error_category& { + return std::system_category(); +} +#endif // _WIN32 + +// std::system is not available on some platforms such as iOS (#2248). +#ifdef __OSX__ +template > +void say(const S& format_str, Args&&... args) { + std::system(format("say \"{}\"", format(format_str, args...)).c_str()); +} +#endif + +// A buffered file. +class buffered_file { + private: + FILE* file_; + + friend class file; + + explicit buffered_file(FILE* f) : file_(f) {} + + public: + buffered_file(const buffered_file&) = delete; + void operator=(const buffered_file&) = delete; + + // Constructs a buffered_file object which doesn't represent any file. + buffered_file() noexcept : file_(nullptr) {} + + // Destroys the object closing the file it represents if any. + FMT_API ~buffered_file() noexcept; + + public: + buffered_file(buffered_file&& other) noexcept : file_(other.file_) { + other.file_ = nullptr; + } + + auto operator=(buffered_file&& other) -> buffered_file& { + close(); + file_ = other.file_; + other.file_ = nullptr; + return *this; + } + + // Opens a file. + FMT_API buffered_file(cstring_view filename, cstring_view mode); + + // Closes the file. + FMT_API void close(); + + // Returns the pointer to a FILE object representing this file. + auto get() const noexcept -> FILE* { return file_; } + + FMT_API auto descriptor() const -> int; + + template + inline void print(string_view fmt, const T&... args) { + const auto& vargs = fmt::make_format_args(args...); + detail::is_locking() ? fmt::vprint_buffered(file_, fmt, vargs) + : fmt::vprint(file_, fmt, vargs); + } +}; + +#if FMT_USE_FCNTL + +// A file. Closed file is represented by a file object with descriptor -1. +// Methods that are not declared with noexcept may throw +// fmt::system_error in case of failure. Note that some errors such as +// closing the file multiple times will cause a crash on Windows rather +// than an exception. You can get standard behavior by overriding the +// invalid parameter handler with _set_invalid_parameter_handler. +class FMT_API file { + private: + int fd_; // File descriptor. + + // Constructs a file object with a given descriptor. + explicit file(int fd) : fd_(fd) {} + + friend struct pipe; + + public: + // Possible values for the oflag argument to the constructor. + enum { + RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. + WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. + RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing. + CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist. + APPEND = FMT_POSIX(O_APPEND), // Open in append mode. + TRUNC = FMT_POSIX(O_TRUNC) // Truncate the content of the file. + }; + + // Constructs a file object which doesn't represent any file. + file() noexcept : fd_(-1) {} + + // Opens a file and constructs a file object representing this file. + file(cstring_view path, int oflag); + + public: + file(const file&) = delete; + void operator=(const file&) = delete; + + file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } + + // Move assignment is not noexcept because close may throw. + auto operator=(file&& other) -> file& { + close(); + fd_ = other.fd_; + other.fd_ = -1; + return *this; + } + + // Destroys the object closing the file it represents if any. + ~file() noexcept; + + // Returns the file descriptor. + auto descriptor() const noexcept -> int { return fd_; } + + // Closes the file. + void close(); + + // Returns the file size. The size has signed type for consistency with + // stat::st_size. + auto size() const -> long long; + + // Attempts to read count bytes from the file into the specified buffer. + auto read(void* buffer, size_t count) -> size_t; + + // Attempts to write count bytes from the specified buffer to the file. + auto write(const void* buffer, size_t count) -> size_t; + + // Duplicates a file descriptor with the dup function and returns + // the duplicate as a file object. + static auto dup(int fd) -> file; + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd); + + // Makes fd be the copy of this file descriptor, closing fd first if + // necessary. + void dup2(int fd, std::error_code& ec) noexcept; + + // Creates a buffered_file object associated with this file and detaches + // this file object from the file. + auto fdopen(const char* mode) -> buffered_file; + +# if defined(_WIN32) && !defined(__MINGW32__) + // Opens a file and constructs a file object representing this file by + // wcstring_view filename. Windows only. + static file open_windows_file(wcstring_view path, int oflag); +# endif +}; + +struct FMT_API pipe { + file read_end; + file write_end; + + // Creates a pipe setting up read_end and write_end file objects for reading + // and writing respectively. + pipe(); +}; + +// Returns the memory page size. +auto getpagesize() -> long; + +namespace detail { + +struct buffer_size { + buffer_size() = default; + size_t value = 0; + auto operator=(size_t val) const -> buffer_size { + auto bs = buffer_size(); + bs.value = val; + return bs; + } +}; + +struct ostream_params { + int oflag = file::WRONLY | file::CREATE | file::TRUNC; + size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; + + ostream_params() {} + + template + ostream_params(T... params, int new_oflag) : ostream_params(params...) { + oflag = new_oflag; + } + + template + ostream_params(T... params, detail::buffer_size bs) + : ostream_params(params...) { + this->buffer_size = bs.value; + } + +// Intel has a bug that results in failure to deduce a constructor +// for empty parameter packs. +# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 + ostream_params(int new_oflag) : oflag(new_oflag) {} + ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} +# endif +}; + +class file_buffer final : public buffer { + private: + file file_; + + FMT_API static void grow(buffer& buf, size_t); + + public: + FMT_API file_buffer(cstring_view path, const ostream_params& params); + FMT_API file_buffer(file_buffer&& other) noexcept; + FMT_API ~file_buffer(); + + void flush() { + if (size() == 0) return; + file_.write(data(), size() * sizeof(data()[0])); + clear(); + } + + void close() { + flush(); + file_.close(); + } +}; + +} // namespace detail + +constexpr auto buffer_size = detail::buffer_size(); + +/// A fast output stream for writing from a single thread. Writing from +/// multiple threads without external synchronization may result in a data race. +class FMT_API ostream { + private: + FMT_MSC_WARNING(suppress : 4251) + detail::file_buffer buffer_; + + ostream(cstring_view path, const detail::ostream_params& params) + : buffer_(path, params) {} + + public: + ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} + + ~ostream(); + + void flush() { buffer_.flush(); } + + template + friend auto output_file(cstring_view path, T... params) -> ostream; + + void close() { buffer_.close(); } + + /// Formats `args` according to specifications in `fmt` and writes the + /// output to the file. + template void print(format_string fmt, T&&... args) { + vformat_to(appender(buffer_), fmt, fmt::make_format_args(args...)); + } +}; + +/** + * Opens a file for writing. Supported parameters passed in `params`: + * + * - ``: Flags passed to [open]( + * https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html) + * (`file::WRONLY | file::CREATE | file::TRUNC` by default) + * - `buffer_size=`: Output buffer size + * + * **Example**: + * + * auto out = fmt::output_file("guide.txt"); + * out.print("Don't {}", "Panic"); + */ +template +inline auto output_file(cstring_view path, T... params) -> ostream { + return {path, detail::ostream_params(params...)}; +} +#endif // FMT_USE_FCNTL + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_OS_H_ diff --git a/cpp_src/vendor/fmt/ostream.h b/cpp_src/vendor/fmt/ostream.h new file mode 100644 index 000000000..98faef659 --- /dev/null +++ b/cpp_src/vendor/fmt/ostream.h @@ -0,0 +1,211 @@ +// Formatting library for C++ - std::ostream support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#ifndef FMT_MODULE +# include // std::filebuf +#endif + +#ifdef _WIN32 +# ifdef __GLIBCXX__ +# include +# include +# endif +# include +#endif + +#include "chrono.h" // formatbuf + +FMT_BEGIN_NAMESPACE +namespace detail { + +// Generate a unique explicit instantion in every translation unit using a tag +// type in an anonymous namespace. +namespace { +struct file_access_tag {}; +} // namespace +template +class file_access { + friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } +}; + +#if FMT_MSC_VERSION +template class file_access; +auto get_file(std::filebuf&) -> FILE*; +#endif + +inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data) + -> bool { + FILE* f = nullptr; +#if FMT_MSC_VERSION && FMT_USE_RTTI + if (auto* buf = dynamic_cast(os.rdbuf())) + f = get_file(*buf); + else + return false; +#elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI + auto* rdbuf = os.rdbuf(); + if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf*>(rdbuf)) + f = sfbuf->file(); + else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf*>(rdbuf)) + f = fbuf->file(); + else + return false; +#else + ignore_unused(os, data, f); +#endif +#ifdef _WIN32 + if (f) { + int fd = _fileno(f); + if (_isatty(fd)) { + os.flush(); + return write_console(fd, data); + } + } +#endif + return false; +} +inline auto write_ostream_unicode(std::wostream&, + fmt::basic_string_view) -> bool { + return false; +} + +// Write the content of buf to os. +// It is a separate function rather than a part of vprint to simplify testing. +template +void write_buffer(std::basic_ostream& os, buffer& buf) { + const Char* buf_data = buf.data(); + using unsigned_streamsize = std::make_unsigned::type; + unsigned_streamsize size = buf.size(); + unsigned_streamsize max_size = to_unsigned(max_value()); + do { + unsigned_streamsize n = size <= max_size ? size : max_size; + os.write(buf_data, static_cast(n)); + buf_data += n; + size -= n; + } while (size != 0); +} + +template +void format_value(buffer& buf, const T& value) { + auto&& format_buf = formatbuf>(buf); + auto&& output = std::basic_ostream(&format_buf); +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) + output.imbue(std::locale::classic()); // The default is always unlocalized. +#endif + output << value; + output.exceptions(std::ios_base::failbit | std::ios_base::badbit); +} + +template struct streamed_view { + const T& value; +}; + +} // namespace detail + +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct basic_ostream_formatter : formatter, Char> { + void set_debug_format() = delete; + + template + auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { + auto buffer = basic_memory_buffer(); + detail::format_value(buffer, value); + return formatter, Char>::format( + {buffer.data(), buffer.size()}, ctx); + } +}; + +using ostream_formatter = basic_ostream_formatter; + +template +struct formatter, Char> + : basic_ostream_formatter { + template + auto format(detail::streamed_view view, Context& ctx) const + -> decltype(ctx.out()) { + return basic_ostream_formatter::format(view.value, ctx); + } +}; + +/** + * Returns a view that formats `value` via an ostream `operator<<`. + * + * **Example**: + * + * fmt::print("Current thread id: {}\n", + * fmt::streamed(std::this_thread::get_id())); + */ +template +constexpr auto streamed(const T& value) -> detail::streamed_view { + return {value}; +} + +namespace detail { + +inline void vprint_directly(std::ostream& os, string_view format_str, + format_args args) { + auto buffer = memory_buffer(); + detail::vformat_to(buffer, format_str, args); + detail::write_buffer(os, buffer); +} + +} // namespace detail + +FMT_EXPORT template +void vprint(std::basic_ostream& os, + basic_string_view> format_str, + typename detail::vformat_args::type args) { + auto buffer = basic_memory_buffer(); + detail::vformat_to(buffer, format_str, args); + if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; + detail::write_buffer(os, buffer); +} + +/** + * Prints formatted data to the stream `os`. + * + * **Example**: + * + * fmt::print(cerr, "Don't {}!", "panic"); + */ +FMT_EXPORT template +void print(std::ostream& os, format_string fmt, T&&... args) { + const auto& vargs = fmt::make_format_args(args...); + if (detail::use_utf8()) + vprint(os, fmt, vargs); + else + detail::vprint_directly(os, fmt, vargs); +} + +FMT_EXPORT +template +void print(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + vprint(os, fmt, fmt::make_format_args>(args...)); +} + +FMT_EXPORT template +void println(std::ostream& os, format_string fmt, T&&... args) { + fmt::print(os, "{}\n", fmt::format(fmt, std::forward(args)...)); +} + +FMT_EXPORT +template +void println(std::wostream& os, + basic_format_string...> fmt, + Args&&... args) { + print(os, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +FMT_END_NAMESPACE + +#endif // FMT_OSTREAM_H_ diff --git a/cpp_src/vendor/fmt/printf.h b/cpp_src/vendor/fmt/printf.h new file mode 100644 index 000000000..208574e7d --- /dev/null +++ b/cpp_src/vendor/fmt/printf.h @@ -0,0 +1,656 @@ +// Formatting library for C++ - legacy printf implementation +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#ifndef FMT_MODULE +# include // std::max +# include // std::numeric_limits +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT + +template struct printf_formatter { + printf_formatter() = delete; +}; + +template class basic_printf_context { + private: + basic_appender out_; + basic_format_args args_; + + static_assert(std::is_same::value || + std::is_same::value, + "Unsupported code unit type."); + + public: + using char_type = Char; + using parse_context_type = basic_format_parse_context; + template using formatter_type = printf_formatter; + + /// Constructs a `printf_context` object. References to the arguments are + /// stored in the context object so make sure they have appropriate lifetimes. + basic_printf_context(basic_appender out, + basic_format_args args) + : out_(out), args_(args) {} + + auto out() -> basic_appender { return out_; } + void advance_to(basic_appender) {} + + auto locale() -> detail::locale_ref { return {}; } + + auto arg(int id) const -> basic_format_arg { + return args_.get(id); + } +}; + +namespace detail { + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template struct int_checker { + template static auto fits_in_int(T value) -> bool { + unsigned max = to_unsigned(max_value()); + return value <= max; + } + static auto fits_in_int(bool) -> bool { return true; } +}; + +template <> struct int_checker { + template static auto fits_in_int(T value) -> bool { + return value >= (std::numeric_limits::min)() && + value <= max_value(); + } + static auto fits_in_int(int) -> bool { return true; } +}; + +struct printf_precision_handler { + template ::value)> + auto operator()(T value) -> int { + if (!int_checker::is_signed>::fits_in_int(value)) + report_error("number is too big"); + return (std::max)(static_cast(value), 0); + } + + template ::value)> + auto operator()(T) -> int { + report_error("precision is not integer"); + return 0; + } +}; + +// An argument visitor that returns true iff arg is a zero integer. +struct is_zero_int { + template ::value)> + auto operator()(T value) -> bool { + return value == 0; + } + + template ::value)> + auto operator()(T) -> bool { + return false; + } +}; + +template struct make_unsigned_or_bool : std::make_unsigned {}; + +template <> struct make_unsigned_or_bool { + using type = bool; +}; + +template class arg_converter { + private: + using char_type = typename Context::char_type; + + basic_format_arg& arg_; + char_type type_; + + public: + arg_converter(basic_format_arg& arg, char_type type) + : arg_(arg), type_(type) {} + + void operator()(bool value) { + if (type_ != 's') operator()(value); + } + + template ::value)> + void operator()(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using target_type = conditional_t::value, U, T>; + if (const_check(sizeof(target_type) <= sizeof(int))) { + // Extra casts are used to silence warnings. + if (is_signed) { + auto n = static_cast(static_cast(value)); + arg_ = detail::make_arg(n); + } else { + using unsigned_type = typename make_unsigned_or_bool::type; + auto n = static_cast(static_cast(value)); + arg_ = detail::make_arg(n); + } + } else { + if (is_signed) { + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + auto n = static_cast(value); + arg_ = detail::make_arg(n); + } else { + auto n = static_cast::type>(value); + arg_ = detail::make_arg(n); + } + } + } + + template ::value)> + void operator()(U) {} // No conversion needed for non-integral types. +}; + +// Converts an integer argument to T for printf, if T is an integral type. +// If T is void, the argument is converted to corresponding signed or unsigned +// type depending on the type specifier: 'd' and 'i' - signed, other - +// unsigned). +template +void convert_arg(basic_format_arg& arg, Char type) { + arg.visit(arg_converter(arg, type)); +} + +// Converts an integer argument to char for printf. +template class char_converter { + private: + basic_format_arg& arg_; + + public: + explicit char_converter(basic_format_arg& arg) : arg_(arg) {} + + template ::value)> + void operator()(T value) { + auto c = static_cast(value); + arg_ = detail::make_arg(c); + } + + template ::value)> + void operator()(T) {} // No conversion needed for non-integral types. +}; + +// An argument visitor that return a pointer to a C string if argument is a +// string or null otherwise. +template struct get_cstring { + template auto operator()(T) -> const Char* { return nullptr; } + auto operator()(const Char* s) -> const Char* { return s; } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class printf_width_handler { + private: + format_specs& specs_; + + public: + explicit printf_width_handler(format_specs& specs) : specs_(specs) {} + + template ::value)> + auto operator()(T value) -> unsigned { + auto width = static_cast>(value); + if (detail::is_negative(value)) { + specs_.align = align::left; + width = 0 - width; + } + unsigned int_max = to_unsigned(max_value()); + if (width > int_max) report_error("number is too big"); + return static_cast(width); + } + + template ::value)> + auto operator()(T) -> unsigned { + report_error("width is not integer"); + return 0; + } +}; + +// Workaround for a bug with the XL compiler when initializing +// printf_arg_formatter's base class. +template +auto make_arg_formatter(basic_appender iter, format_specs& s) + -> arg_formatter { + return {iter, s, locale_ref()}; +} + +// The `printf` argument formatter. +template +class printf_arg_formatter : public arg_formatter { + private: + using base = arg_formatter; + using context_type = basic_printf_context; + + context_type& context_; + + void write_null_pointer(bool is_string = false) { + auto s = this->specs; + s.type = presentation_type::none; + write_bytes(this->out, is_string ? "(null)" : "(nil)", s); + } + + public: + printf_arg_formatter(basic_appender iter, format_specs& s, + context_type& ctx) + : base(make_arg_formatter(iter, s)), context_(ctx) {} + + void operator()(monostate value) { base::operator()(value); } + + template ::value)> + void operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and Char so use + // std::is_same instead. + if (!std::is_same::value) { + base::operator()(value); + return; + } + format_specs s = this->specs; + if (s.type != presentation_type::none && s.type != presentation_type::chr) { + return (*this)(static_cast(value)); + } + s.sign = sign::none; + s.alt = false; + s.fill = ' '; // Ignore '0' flag for char types. + // align::numeric needs to be overwritten here since the '0' flag is + // ignored for non-numeric types + if (s.align == align::none || s.align == align::numeric) + s.align = align::right; + write(this->out, static_cast(value), s); + } + + template ::value)> + void operator()(T value) { + base::operator()(value); + } + + void operator()(const char* value) { + if (value) + base::operator()(value); + else + write_null_pointer(this->specs.type != presentation_type::pointer); + } + + void operator()(const wchar_t* value) { + if (value) + base::operator()(value); + else + write_null_pointer(this->specs.type != presentation_type::pointer); + } + + void operator()(basic_string_view value) { base::operator()(value); } + + void operator()(const void* value) { + if (value) + base::operator()(value); + else + write_null_pointer(); + } + + void operator()(typename basic_format_arg::handle handle) { + auto parse_ctx = basic_format_parse_context({}); + handle.format(parse_ctx, context_); + } +}; + +template +void parse_flags(format_specs& specs, const Char*& it, const Char* end) { + for (; it != end; ++it) { + switch (*it) { + case '-': + specs.align = align::left; + break; + case '+': + specs.sign = sign::plus; + break; + case '0': + specs.fill = '0'; + break; + case ' ': + if (specs.sign != sign::plus) specs.sign = sign::space; + break; + case '#': + specs.alt = true; + break; + default: + return; + } + } +} + +template +auto parse_header(const Char*& it, const Char* end, format_specs& specs, + GetArg get_arg) -> int { + int arg_index = -1; + Char c = *it; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + int value = parse_nonnegative_int(it, end, -1); + if (it != end && *it == '$') { // value is an argument index + ++it; + arg_index = value != -1 ? value : max_value(); + } else { + if (c == '0') specs.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. + if (value == -1) report_error("number is too big"); + specs.width = value; + return arg_index; + } + } + } + parse_flags(specs, it, end); + // Parse width. + if (it != end) { + if (*it >= '0' && *it <= '9') { + specs.width = parse_nonnegative_int(it, end, -1); + if (specs.width == -1) report_error("number is too big"); + } else if (*it == '*') { + ++it; + specs.width = static_cast( + get_arg(-1).visit(detail::printf_width_handler(specs))); + } + } + return arg_index; +} + +inline auto parse_printf_presentation_type(char c, type t, bool& upper) + -> presentation_type { + using pt = presentation_type; + constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; + switch (c) { + case 'd': + return in(t, integral_set) ? pt::dec : pt::none; + case 'o': + return in(t, integral_set) ? pt::oct : pt::none; + case 'X': + upper = true; + FMT_FALLTHROUGH; + case 'x': + return in(t, integral_set) ? pt::hex : pt::none; + case 'E': + upper = true; + FMT_FALLTHROUGH; + case 'e': + return in(t, float_set) ? pt::exp : pt::none; + case 'F': + upper = true; + FMT_FALLTHROUGH; + case 'f': + return in(t, float_set) ? pt::fixed : pt::none; + case 'G': + upper = true; + FMT_FALLTHROUGH; + case 'g': + return in(t, float_set) ? pt::general : pt::none; + case 'A': + upper = true; + FMT_FALLTHROUGH; + case 'a': + return in(t, float_set) ? pt::hexfloat : pt::none; + case 'c': + return in(t, integral_set) ? pt::chr : pt::none; + case 's': + return in(t, string_set | cstring_set) ? pt::string : pt::none; + case 'p': + return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; + default: + return pt::none; + } +} + +template +void vprintf(buffer& buf, basic_string_view format, + basic_format_args args) { + using iterator = basic_appender; + auto out = iterator(buf); + auto context = basic_printf_context(out, args); + auto parse_ctx = basic_format_parse_context(format); + + // Returns the argument with specified index or, if arg_index is -1, the next + // argument. + auto get_arg = [&](int arg_index) { + if (arg_index < 0) + arg_index = parse_ctx.next_arg_id(); + else + parse_ctx.check_arg_id(--arg_index); + return detail::get_arg(context, arg_index); + }; + + const Char* start = parse_ctx.begin(); + const Char* end = parse_ctx.end(); + auto it = start; + while (it != end) { + if (!find(it, end, '%', it)) { + it = end; // find leaves it == nullptr if it doesn't find '%'. + break; + } + Char c = *it++; + if (it != end && *it == c) { + write(out, basic_string_view(start, to_unsigned(it - start))); + start = ++it; + continue; + } + write(out, basic_string_view(start, to_unsigned(it - 1 - start))); + + auto specs = format_specs(); + specs.align = align::right; + + // Parse argument index, flags and width. + int arg_index = parse_header(it, end, specs, get_arg); + if (arg_index == 0) report_error("argument not found"); + + // Parse precision. + if (it != end && *it == '.') { + ++it; + c = it != end ? *it : 0; + if ('0' <= c && c <= '9') { + specs.precision = parse_nonnegative_int(it, end, 0); + } else if (c == '*') { + ++it; + specs.precision = + static_cast(get_arg(-1).visit(printf_precision_handler())); + } else { + specs.precision = 0; + } + } + + auto arg = get_arg(arg_index); + // For d, i, o, u, x, and X conversion specifiers, if a precision is + // specified, the '0' flag is ignored + if (specs.precision >= 0 && arg.is_integral()) { + // Ignore '0' for non-numeric types or if '-' present. + specs.fill = ' '; + } + if (specs.precision >= 0 && arg.type() == type::cstring_type) { + auto str = arg.visit(get_cstring()); + auto str_end = str + specs.precision; + auto nul = std::find(str, str_end, Char()); + auto sv = basic_string_view( + str, to_unsigned(nul != str_end ? nul - str : specs.precision)); + arg = make_arg>(sv); + } + if (specs.alt && arg.visit(is_zero_int())) specs.alt = false; + if (specs.fill.template get() == '0') { + if (arg.is_arithmetic() && specs.align != align::left) + specs.align = align::numeric; + else + specs.fill = ' '; // Ignore '0' flag for non-numeric types or if '-' + // flag is also present. + } + + // Parse length and convert the argument to the required type. + c = it != end ? *it++ : 0; + Char t = it != end ? *it : 0; + switch (c) { + case 'h': + if (t == 'h') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'l': + if (t == 'l') { + ++it; + t = it != end ? *it : 0; + convert_arg(arg, t); + } else { + convert_arg(arg, t); + } + break; + case 'j': + convert_arg(arg, t); + break; + case 'z': + convert_arg(arg, t); + break; + case 't': + convert_arg(arg, t); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --it; + convert_arg(arg, c); + } + + // Parse type. + if (it == end) report_error("invalid format string"); + char type = static_cast(*it++); + if (arg.is_integral()) { + // Normalize type. + switch (type) { + case 'i': + case 'u': + type = 'd'; + break; + case 'c': + arg.visit(char_converter>(arg)); + break; + } + } + bool upper = false; + specs.type = parse_printf_presentation_type(type, arg.type(), upper); + if (specs.type == presentation_type::none && arg.type() != type::custom_type) + report_error("invalid format specifier"); + specs.upper = upper; + + start = it; + + // Format argument. + arg.visit(printf_arg_formatter(out, specs, context)); + } + write(out, basic_string_view(start, to_unsigned(it - start))); +} +} // namespace detail + +using printf_context = basic_printf_context; +using wprintf_context = basic_printf_context; + +using printf_args = basic_format_args; +using wprintf_args = basic_format_args; + +/// Constructs an `format_arg_store` object that contains references to +/// arguments and can be implicitly converted to `printf_args`. +template +inline auto make_printf_args(T&... args) + -> decltype(fmt::make_format_args>(args...)) { + return fmt::make_format_args>(args...); +} + +template struct vprintf_args { + using type = basic_format_args>; +}; + +template +inline auto vsprintf(basic_string_view fmt, + typename vprintf_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + return to_string(buf); +} + +/** + * Formats `args` according to specifications in `fmt` and returns the result + * as as string. + * + * **Example**: + * + * std::string message = fmt::sprintf("The answer is %d", 42); + */ +template > +inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string { + return vsprintf(detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template +inline auto vfprintf(std::FILE* f, basic_string_view fmt, + typename vprintf_args::type args) -> int { + auto buf = basic_memory_buffer(); + detail::vprintf(buf, fmt, args); + size_t size = buf.size(); + return std::fwrite(buf.data(), sizeof(Char), size, f) < size + ? -1 + : static_cast(size); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `f`. + * + * **Example**: + * + * fmt::fprintf(stderr, "Don't %s!", "panic"); + */ +template > +inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { + return vfprintf(f, detail::to_string_view(fmt), + make_printf_args(args...)); +} + +template +FMT_DEPRECATED inline auto vprintf(basic_string_view fmt, + typename vprintf_args::type args) + -> int { + return vfprintf(stdout, fmt, args); +} + +/** + * Formats `args` according to specifications in `fmt` and writes the output + * to `stdout`. + * + * **Example**: + * + * fmt::printf("Elapsed time: %.2f seconds", 1.23); + */ +template +inline auto printf(string_view fmt, const T&... args) -> int { + return vfprintf(stdout, fmt, make_printf_args(args...)); +} +template +FMT_DEPRECATED inline auto printf(basic_string_view fmt, + const T&... args) -> int { + return vfprintf(stdout, fmt, make_printf_args(args...)); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_PRINTF_H_ diff --git a/cpp_src/vendor/fmt/ranges.h b/cpp_src/vendor/fmt/ranges.h new file mode 100644 index 000000000..0d3dfbd8d --- /dev/null +++ b/cpp_src/vendor/fmt/ranges.h @@ -0,0 +1,882 @@ +// Formatting library for C++ - range and tuple support +// +// Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#ifndef FMT_MODULE +# include +# include +# include +# include +# include +# include +#endif + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +FMT_EXPORT +enum class range_format { disabled, map, set, sequence, string, debug_string }; + +namespace detail { + +template class is_map { + template static auto check(U*) -> typename U::mapped_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +template class is_set { + template static auto check(U*) -> typename U::key_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value && !is_map::value; +}; + +template struct conditional_helper {}; + +template struct is_range_ : std::false_type {}; + +#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 + +# define FMT_DECLTYPE_RETURN(val) \ + ->decltype(val) { return val; } \ + static_assert( \ + true, "") // This makes it so that a semicolon is required after the + // macro, which helps clang-format handle the formatting. + +// C array overload +template +auto range_begin(const T (&arr)[N]) -> const T* { + return arr; +} +template +auto range_end(const T (&arr)[N]) -> const T* { + return arr + N; +} + +template +struct has_member_fn_begin_end_t : std::false_type {}; + +template +struct has_member_fn_begin_end_t().begin()), + decltype(std::declval().end())>> + : std::true_type {}; + +// Member function overloads. +template +auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).begin()); +template +auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast(rng).end()); + +// ADL overloads. Only participate in overload resolution if member functions +// are not found. +template +auto range_begin(T&& rng) + -> enable_if_t::value, + decltype(begin(static_cast(rng)))> { + return begin(static_cast(rng)); +} +template +auto range_end(T&& rng) -> enable_if_t::value, + decltype(end(static_cast(rng)))> { + return end(static_cast(rng)); +} + +template +struct has_const_begin_end : std::false_type {}; +template +struct has_mutable_begin_end : std::false_type {}; + +template +struct has_const_begin_end< + T, void_t&>())), + decltype(detail::range_end( + std::declval&>()))>> + : std::true_type {}; + +template +struct has_mutable_begin_end< + T, void_t())), + decltype(detail::range_end(std::declval())), + // the extra int here is because older versions of MSVC don't + // SFINAE properly unless there are distinct types + int>> : std::true_type {}; + +template +struct is_range_ + : std::integral_constant::value || + has_mutable_begin_end::value)> {}; +# undef FMT_DECLTYPE_RETURN +#endif + +// tuple_size and tuple_element check. +template class is_tuple_like_ { + template + static auto check(U* p) -> decltype(std::tuple_size::value, int()); + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +// Check for integer_sequence +#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 +template +using integer_sequence = std::integer_sequence; +template using index_sequence = std::index_sequence; +template using make_index_sequence = std::make_index_sequence; +#else +template struct integer_sequence { + using value_type = T; + + static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } +}; + +template using index_sequence = integer_sequence; + +template +struct make_integer_sequence : make_integer_sequence {}; +template +struct make_integer_sequence : integer_sequence {}; + +template +using make_index_sequence = make_integer_sequence; +#endif + +template +using tuple_index_sequence = make_index_sequence::value>; + +template ::value> +class is_tuple_formattable_ { + public: + static constexpr const bool value = false; +}; +template class is_tuple_formattable_ { + template + static auto all_true(index_sequence, + integer_sequence= 0)...>) -> std::true_type; + static auto all_true(...) -> std::false_type; + + template + static auto check(index_sequence) -> decltype(all_true( + index_sequence{}, + integer_sequence::type, + C>::value)...>{})); + + public: + static constexpr const bool value = + decltype(check(tuple_index_sequence{}))::value; +}; + +template +FMT_CONSTEXPR void for_each(index_sequence, Tuple&& t, F&& f) { + using std::get; + // Using a free function get(Tuple) now. + const int unused[] = {0, ((void)f(get(t)), 0)...}; + ignore_unused(unused); +} + +template +FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { + for_each(tuple_index_sequence>(), + std::forward(t), std::forward(f)); +} + +template +void for_each2(index_sequence, Tuple1&& t1, Tuple2&& t2, F&& f) { + using std::get; + const int unused[] = {0, ((void)f(get(t1), get(t2)), 0)...}; + ignore_unused(unused); +} + +template +void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { + for_each2(tuple_index_sequence>(), + std::forward(t1), std::forward(t2), + std::forward(f)); +} + +namespace tuple { +// Workaround a bug in MSVC 2019 (v140). +template +using result_t = std::tuple, Char>...>; + +using std::get; +template +auto get_formatters(index_sequence) + -> result_t(std::declval()))...>; +} // namespace tuple + +#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 +// Older MSVC doesn't get the reference type correctly for arrays. +template struct range_reference_type_impl { + using type = decltype(*detail::range_begin(std::declval())); +}; + +template struct range_reference_type_impl { + using type = T&; +}; + +template +using range_reference_type = typename range_reference_type_impl::type; +#else +template +using range_reference_type = + decltype(*detail::range_begin(std::declval())); +#endif + +// We don't use the Range's value_type for anything, but we do need the Range's +// reference type, with cv-ref stripped. +template +using uncvref_type = remove_cvref_t>; + +template +FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) + -> decltype(f.set_debug_format(set)) { + f.set_debug_format(set); +} +template +FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} + +template +struct range_format_kind_ + : std::integral_constant, T>::value + ? range_format::disabled + : is_map::value ? range_format::map + : is_set::value ? range_format::set + : range_format::sequence> {}; + +template +using range_format_constant = std::integral_constant; + +// These are not generic lambdas for compatibility with C++11. +template struct parse_empty_specs { + template FMT_CONSTEXPR void operator()(Formatter& f) { + f.parse(ctx); + detail::maybe_set_debug_format(f, true); + } + ParseContext& ctx; +}; +template struct format_tuple_element { + using char_type = typename FormatContext::char_type; + + template + void operator()(const formatter& f, const T& v) { + if (i > 0) ctx.advance_to(detail::copy(separator, ctx.out())); + ctx.advance_to(f.format(v, ctx)); + ++i; + } + + int i; + FormatContext& ctx; + basic_string_view separator; +}; + +} // namespace detail + +template struct is_tuple_like { + static constexpr const bool value = + detail::is_tuple_like_::value && !detail::is_range_::value; +}; + +template struct is_tuple_formattable { + static constexpr const bool value = + detail::is_tuple_formattable_::value; +}; + +template +struct formatter::value && + fmt::is_tuple_formattable::value>> { + private: + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + + public: + FMT_CONSTEXPR formatter() {} + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + if (it != ctx.end() && *it != '}') report_error("invalid format specifier"); + detail::for_each(formatters_, detail::parse_empty_specs{ctx}); + return it; + } + + template + auto format(const Tuple& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + ctx.advance_to(detail::copy(opening_bracket_, ctx.out())); + detail::for_each2( + formatters_, value, + detail::format_tuple_element{0, ctx, separator_}); + return detail::copy(closing_bracket_, ctx.out()); + } +}; + +template struct is_range { + static constexpr const bool value = + detail::is_range_::value && !detail::has_to_string_view::value; +}; + +namespace detail { +template struct range_mapper { + using mapper = arg_mapper; + + template , Context>::value)> + static auto map(T&& value) -> T&& { + return static_cast(value); + } + template , Context>::value)> + static auto map(T&& value) + -> decltype(mapper().map(static_cast(value))) { + return mapper().map(static_cast(value)); + } +}; + +template +using range_formatter_type = + formatter>{} + .map(std::declval()))>, + Char>; + +template +using maybe_const_range = + conditional_t::value, const R, R>; + +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 +template +struct is_formattable_delayed + : is_formattable>, Char> {}; +#endif +} // namespace detail + +template struct conjunction : std::true_type {}; +template struct conjunction

: P {}; +template +struct conjunction + : conditional_t, P1> {}; + +template +struct range_formatter; + +template +struct range_formatter< + T, Char, + enable_if_t>, + is_formattable>::value>> { + private: + detail::range_formatter_type underlying_; + basic_string_view separator_ = detail::string_literal{}; + basic_string_view opening_bracket_ = + detail::string_literal{}; + basic_string_view closing_bracket_ = + detail::string_literal{}; + bool is_debug = false; + + template ::value)> + auto write_debug_string(Output& out, It it, Sentinel end) const -> Output { + auto buf = basic_memory_buffer(); + for (; it != end; ++it) buf.push_back(*it); + auto specs = format_specs(); + specs.type = presentation_type::debug; + return detail::write( + out, basic_string_view(buf.data(), buf.size()), specs); + } + + template ::value)> + auto write_debug_string(Output& out, It, Sentinel) const -> Output { + return out; + } + + public: + FMT_CONSTEXPR range_formatter() {} + + FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type& { + return underlying_; + } + + FMT_CONSTEXPR void set_separator(basic_string_view sep) { + separator_ = sep; + } + + FMT_CONSTEXPR void set_brackets(basic_string_view open, + basic_string_view close) { + opening_bracket_ = open; + closing_bracket_ = close; + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + detail::maybe_set_debug_format(underlying_, true); + if (it == end) return underlying_.parse(ctx); + + switch (detail::to_ascii(*it)) { + case 'n': + set_brackets({}, {}); + ++it; + break; + case '?': + is_debug = true; + set_brackets({}, {}); + ++it; + if (it == end || *it != 's') report_error("invalid format specifier"); + FMT_FALLTHROUGH; + case 's': + if (!std::is_same::value) + report_error("invalid format specifier"); + if (!is_debug) { + set_brackets(detail::string_literal{}, + detail::string_literal{}); + set_separator({}); + detail::maybe_set_debug_format(underlying_, false); + } + ++it; + return it; + } + + if (it != end && *it != '}') { + if (*it != ':') report_error("invalid format specifier"); + detail::maybe_set_debug_format(underlying_, false); + ++it; + } + + ctx.advance_to(it); + return underlying_.parse(ctx); + } + + template + auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { + auto mapper = detail::range_mapper>(); + auto out = ctx.out(); + auto it = detail::range_begin(range); + auto end = detail::range_end(range); + if (is_debug) return write_debug_string(out, std::move(it), end); + + out = detail::copy(opening_bracket_, out); + int i = 0; + for (; it != end; ++it) { + if (i > 0) out = detail::copy(separator_, out); + ctx.advance_to(out); + auto&& item = *it; // Need an lvalue + out = underlying_.format(mapper.map(item), ctx); + ++i; + } + out = detail::copy(closing_bracket_, out); + return out; + } +}; + +FMT_EXPORT +template +struct range_format_kind + : conditional_t< + is_range::value, detail::range_format_kind_, + std::integral_constant> {}; + +template +struct formatter< + R, Char, + enable_if_t::value != range_format::disabled && + range_format_kind::value != range_format::map && + range_format_kind::value != range_format::string && + range_format_kind::value != range_format::debug_string> +// Workaround a bug in MSVC 2015 and earlier. +#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 + , + detail::is_formattable_delayed +#endif + >::value>> { + private: + using range_type = detail::maybe_const_range; + range_formatter, Char> range_formatter_; + + public: + using nonlocking = void; + + FMT_CONSTEXPR formatter() { + if (detail::const_check(range_format_kind::value != + range_format::set)) + return; + range_formatter_.set_brackets(detail::string_literal{}, + detail::string_literal{}); + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return range_formatter_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + return range_formatter_.format(range, ctx); + } +}; + +// A map formatter. +template +struct formatter< + R, Char, + enable_if_t::value == range_format::map>> { + private: + using map_type = detail::maybe_const_range; + using element_type = detail::uncvref_type; + + decltype(detail::tuple::get_formatters( + detail::tuple_index_sequence())) formatters_; + bool no_delimiters_ = false; + + public: + FMT_CONSTEXPR formatter() {} + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end) { + if (detail::to_ascii(*it) == 'n') { + no_delimiters_ = true; + ++it; + } + if (it != end && *it != '}') { + if (*it != ':') report_error("invalid format specifier"); + ++it; + } + ctx.advance_to(it); + } + detail::for_each(formatters_, detail::parse_empty_specs{ctx}); + return it; + } + + template + auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) { + auto out = ctx.out(); + basic_string_view open = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(open, out); + int i = 0; + auto mapper = detail::range_mapper>(); + basic_string_view sep = detail::string_literal{}; + for (auto&& value : map) { + if (i > 0) out = detail::copy(sep, out); + ctx.advance_to(out); + detail::for_each2(formatters_, mapper.map(value), + detail::format_tuple_element{ + 0, ctx, detail::string_literal{}}); + ++i; + } + basic_string_view close = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(close, out); + return out; + } +}; + +// A (debug_)string formatter. +template +struct formatter< + R, Char, + enable_if_t::value == range_format::string || + range_format_kind::value == + range_format::debug_string>> { + private: + using range_type = detail::maybe_const_range; + using string_type = + conditional_t, + decltype(detail::range_begin(std::declval())), + decltype(detail::range_end(std::declval()))>::value, + detail::std_string_view, std::basic_string>; + + formatter underlying_; + + public: + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return underlying_.parse(ctx); + } + + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + if (detail::const_check(range_format_kind::value == + range_format::debug_string)) + *out++ = '"'; + out = underlying_.format( + string_type{detail::range_begin(range), detail::range_end(range)}, ctx); + if (detail::const_check(range_format_kind::value == + range_format::debug_string)) + *out++ = '"'; + return out; + } +}; + +template +struct join_view : detail::view { + It begin; + Sentinel end; + basic_string_view sep; + + join_view(It b, Sentinel e, basic_string_view s) + : begin(std::move(b)), end(e), sep(s) {} +}; + +template +struct formatter, Char> { + private: + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif + formatter, Char> value_formatter_; + + using view_ref = conditional_t::value, + const join_view&, + join_view&&>; + + public: + using nonlocking = void; + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { + return value_formatter_.parse(ctx); + } + + template + auto format(view_ref& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto it = std::forward(value).begin; + auto out = ctx.out(); + if (it == value.end) return out; + out = value_formatter_.format(*it, ctx); + ++it; + while (it != value.end) { + out = detail::copy(value.sep.begin(), value.sep.end(), out); + ctx.advance_to(out); + out = value_formatter_.format(*it, ctx); + ++it; + } + return out; + } +}; + +/// Returns a view that formats the iterator range `[begin, end)` with elements +/// separated by `sep`. +template +auto join(It begin, Sentinel end, string_view sep) -> join_view { + return {std::move(begin), end, sep}; +} + +/** + * Returns a view that formats `range` with elements separated by `sep`. + * + * **Example**: + * + * auto v = std::vector{1, 2, 3}; + * fmt::print("{}", fmt::join(v, ", ")); + * // Output: 1, 2, 3 + * + * `fmt::join` applies passed format specifiers to the range elements: + * + * fmt::print("{:02}", fmt::join(v, ", ")); + * // Output: 01, 02, 03 + */ +template +auto join(Range&& r, string_view sep) + -> join_view { + return {detail::range_begin(r), detail::range_end(r), sep}; +} + +template struct tuple_join_view : detail::view { + const std::tuple& tuple; + basic_string_view sep; + + tuple_join_view(const std::tuple& t, basic_string_view s) + : tuple(t), sep{s} {} +}; + +// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers +// support in tuple_join. It is disabled by default because of issues with +// the dynamic width and precision. +#ifndef FMT_TUPLE_JOIN_SPECIFIERS +# define FMT_TUPLE_JOIN_SPECIFIERS 0 +#endif + +template +struct formatter, Char> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return do_parse(ctx, std::integral_constant()); + } + + template + auto format(const tuple_join_view& value, + FormatContext& ctx) const -> typename FormatContext::iterator { + return do_format(value, ctx, + std::integral_constant()); + } + + private: + std::tuple::type, Char>...> formatters_; + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto do_parse(ParseContext& ctx, + std::integral_constant) + -> decltype(ctx.begin()) { + auto end = ctx.begin(); +#if FMT_TUPLE_JOIN_SPECIFIERS + end = std::get(formatters_).parse(ctx); + if (N > 1) { + auto end1 = do_parse(ctx, std::integral_constant()); + if (end != end1) + report_error("incompatible format specs for tuple elements"); + } +#endif + return end; + } + + template + auto do_format(const tuple_join_view&, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + return ctx.out(); + } + + template + auto do_format(const tuple_join_view& value, FormatContext& ctx, + std::integral_constant) const -> + typename FormatContext::iterator { + auto out = std::get(formatters_) + .format(std::get(value.tuple), ctx); + if (N <= 1) return out; + out = detail::copy(value.sep, out); + ctx.advance_to(out); + return do_format(value, ctx, std::integral_constant()); + } +}; + +namespace detail { +// Check if T has an interface like a container adaptor (e.g. std::stack, +// std::queue, std::priority_queue). +template class is_container_adaptor_like { + template static auto check(U* p) -> typename U::container_type; + template static void check(...); + + public: + static constexpr const bool value = + !std::is_void(nullptr))>::value; +}; + +template struct all { + const Container& c; + auto begin() const -> typename Container::const_iterator { return c.begin(); } + auto end() const -> typename Container::const_iterator { return c.end(); } +}; +} // namespace detail + +template +struct formatter< + T, Char, + enable_if_t, + bool_constant::value == + range_format::disabled>>::value>> + : formatter, Char> { + using all = detail::all; + template + auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { + struct getter : T { + static auto get(const T& t) -> all { + return {t.*(&getter::c)}; // Access c through the derived class. + } + }; + return formatter::format(getter::get(t), ctx); + } +}; + +FMT_BEGIN_EXPORT + +/** + * Returns an object that formats `std::tuple` with elements separated by `sep`. + * + * **Example**: + * + * auto t = std::tuple{1, 'a'}; + * fmt::print("{}", fmt::join(t, ", ")); + * // Output: 1, a + */ +template +FMT_CONSTEXPR auto join(const std::tuple& tuple, string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +/** + * Returns an object that formats `std::initializer_list` with elements + * separated by `sep`. + * + * **Example**: + * + * fmt::print("{}", fmt::join({1, 2, 3}, ", ")); + * // Output: "1, 2, 3" + */ +template +auto join(std::initializer_list list, string_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_RANGES_H_ diff --git a/cpp_src/vendor/fmt/std.h b/cpp_src/vendor/fmt/std.h new file mode 100644 index 000000000..fb43940bc --- /dev/null +++ b/cpp_src/vendor/fmt/std.h @@ -0,0 +1,699 @@ +// Formatting library for C++ - formatters for standard library types +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_STD_H_ +#define FMT_STD_H_ + +#include "format.h" +#include "ostream.h" + +#ifndef FMT_MODULE +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC. +# if FMT_CPLUSPLUS >= 201703L +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +# if FMT_HAS_INCLUDE() +# include +# endif +# endif +// Use > instead of >= in the version check because may be +// available after C++17 but before C++20 is marked as implemented. +# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() +# include +# endif +# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE() +# include +# endif +#endif // FMT_MODULE + +#if FMT_HAS_INCLUDE() +# include +#endif + +// GCC 4 does not support FMT_HAS_INCLUDE. +#if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) +# include +// Android NDK with gabi++ library on some architectures does not implement +// abi::__cxa_demangle(). +# ifndef __GABIXX_CXXABI_H__ +# define FMT_HAS_ABI_CXA_DEMANGLE +# endif +#endif + +// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. +#ifndef FMT_CPP_LIB_FILESYSTEM +# ifdef __cpp_lib_filesystem +# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem +# else +# define FMT_CPP_LIB_FILESYSTEM 0 +# endif +#endif + +#ifndef FMT_CPP_LIB_VARIANT +# ifdef __cpp_lib_variant +# define FMT_CPP_LIB_VARIANT __cpp_lib_variant +# else +# define FMT_CPP_LIB_VARIANT 0 +# endif +#endif + +#if FMT_CPP_LIB_FILESYSTEM +FMT_BEGIN_NAMESPACE + +namespace detail { + +template +auto get_path_string(const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && std::is_same_v) + return to_utf8(native, to_utf8_error_policy::replace); + else + return p.string(); +} + +template +void write_escaped_path(basic_memory_buffer& quoted, + const std::filesystem::path& p, + const std::basic_string& native) { + if constexpr (std::is_same_v && + std::is_same_v) { + auto buf = basic_memory_buffer(); + write_escaped_string(std::back_inserter(buf), native); + bool valid = to_utf8::convert(quoted, {buf.data(), buf.size()}); + FMT_ASSERT(valid, "invalid utf16"); + } else if constexpr (std::is_same_v) { + write_escaped_string( + std::back_inserter(quoted), native); + } else { + write_escaped_string(std::back_inserter(quoted), p.string()); + } +} + +} // namespace detail + +FMT_EXPORT +template struct formatter { + private: + format_specs specs_; + detail::arg_ref width_ref_; + bool debug_ = false; + char path_type_ = 0; + + public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it != end && *it == '?') { + debug_ = true; + ++it; + } + if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++); + return it; + } + + template + auto format(const std::filesystem::path& p, FormatContext& ctx) const { + auto specs = specs_; + auto path_string = + !path_type_ ? p.native() + : p.generic_string(); + + detail::handle_dynamic_spec(specs.width, width_ref_, + ctx); + if (!debug_) { + auto s = detail::get_path_string(p, path_string); + return detail::write(ctx.out(), basic_string_view(s), specs); + } + auto quoted = basic_memory_buffer(); + detail::write_escaped_path(quoted, p, path_string); + return detail::write(ctx.out(), + basic_string_view(quoted.data(), quoted.size()), + specs); + } +}; + +class path : public std::filesystem::path { + public: + auto display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{}"), base); + } + auto system_string() const -> std::string { return string(); } + + auto generic_display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{:g}"), base); + } + auto generic_system_string() const -> std::string { return generic_string(); } +}; + +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_FILESYSTEM + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char> : nested_formatter { + private: + // Functor because C++11 doesn't support generic lambdas. + struct writer { + const std::bitset& bs; + + template + FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { + for (auto pos = N; pos > 0; --pos) { + out = detail::write(out, bs[pos - 1] ? Char('1') : Char('0')); + } + + return out; + } + }; + + public: + template + auto format(const std::bitset& bs, FormatContext& ctx) const + -> decltype(ctx.out()) { + return write_padded(ctx, writer{bs}); + } +}; + +FMT_EXPORT +template +struct formatter : basic_ostream_formatter {}; +FMT_END_NAMESPACE + +#ifdef __cpp_lib_optional +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char, + std::enable_if_t::value>> { + private: + formatter underlying_; + static constexpr basic_string_view optional = + detail::string_literal{}; + static constexpr basic_string_view none = + detail::string_literal{}; + + template + FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) + -> decltype(u.set_debug_format(set)) { + u.set_debug_format(set); + } + + template + FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} + + public: + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + maybe_set_debug_format(underlying_, true); + return underlying_.parse(ctx); + } + + template + auto format(const std::optional& opt, FormatContext& ctx) const + -> decltype(ctx.out()) { + if (!opt) return detail::write(ctx.out(), none); + + auto out = ctx.out(); + out = detail::write(out, optional); + ctx.advance_to(out); + out = underlying_.format(*opt, ctx); + return detail::write(out, ')'); + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_optional + +#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { + if constexpr (has_to_string_view::value) + return write_escaped_string(out, detail::to_string_view(v)); + if constexpr (std::is_same_v) return write_escaped_char(out, v); + return write(out, v); +} + +} // namespace detail + +FMT_END_NAMESPACE +#endif + +#ifdef __cpp_lib_expected +FMT_BEGIN_NAMESPACE + +FMT_EXPORT +template +struct formatter, Char, + std::enable_if_t::value && + is_formattable::value>> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::expected& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + if (value.has_value()) { + out = detail::write(out, "expected("); + out = detail::write_escaped_alternative(out, *value); + } else { + out = detail::write(out, "unexpected("); + out = detail::write_escaped_alternative(out, value.error()); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // __cpp_lib_expected + +#ifdef __cpp_lib_source_location +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template <> struct formatter { + template FMT_CONSTEXPR auto parse(ParseContext& ctx) { + return ctx.begin(); + } + + template + auto format(const std::source_location& loc, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write(out, loc.file_name()); + out = detail::write(out, ':'); + out = detail::write(out, loc.line()); + out = detail::write(out, ':'); + out = detail::write(out, loc.column()); + out = detail::write(out, ": "); + out = detail::write(out, loc.function_name()); + return out; + } +}; +FMT_END_NAMESPACE +#endif + +#if FMT_CPP_LIB_VARIANT +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using variant_index_sequence = + std::make_index_sequence::value>; + +template struct is_variant_like_ : std::false_type {}; +template +struct is_variant_like_> : std::true_type {}; + +// formattable element check. +template class is_variant_formattable_ { + template + static std::conjunction< + is_formattable, C>...> + check(std::index_sequence); + + public: + static constexpr const bool value = + decltype(check(variant_index_sequence{}))::value; +}; + +} // namespace detail + +template struct is_variant_like { + static constexpr const bool value = detail::is_variant_like_::value; +}; + +template struct is_variant_formattable { + static constexpr const bool value = + detail::is_variant_formattable_::value; +}; + +FMT_EXPORT +template struct formatter { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::monostate&, FormatContext& ctx) const + -> decltype(ctx.out()) { + return detail::write(ctx.out(), "monostate"); + } +}; + +FMT_EXPORT +template +struct formatter< + Variant, Char, + std::enable_if_t, is_variant_formattable>>> { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const Variant& value, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + + out = detail::write(out, "variant("); + FMT_TRY { + std::visit( + [&](const auto& v) { + out = detail::write_escaped_alternative(out, v); + }, + value); + } + FMT_CATCH(const std::bad_variant_access&) { + detail::write(out, "valueless by exception"); + } + *out++ = ')'; + return out; + } +}; +FMT_END_NAMESPACE +#endif // FMT_CPP_LIB_VARIANT + +FMT_BEGIN_NAMESPACE +FMT_EXPORT +template struct formatter { + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); + out = detail::write_bytes(out, ec.category().name(), format_specs()); + out = detail::write(out, Char(':')); + out = detail::write(out, ec.value()); + return out; + } +}; + +#if FMT_USE_RTTI +namespace detail { + +template +auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { +# ifdef FMT_HAS_ABI_CXA_DEMANGLE + int status = 0; + std::size_t size = 0; + std::unique_ptr demangled_name_ptr( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = demangled_name_ptr.get(); + + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* begin = demangled_name_ptr.get(); + char* to = begin + 5; // std:: + for (char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; + } + } + *to++ = *from++; + } + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + } + } else { + demangled_name_view = string_view(ti.name()); + } + return detail::write_bytes(out, demangled_name_view); +# elif FMT_MSC_VERSION + const string_view demangled_name(ti.name()); + for (std::size_t i = 0; i < demangled_name.size(); ++i) { + auto sub = demangled_name; + sub.remove_prefix(i); + if (sub.starts_with("enum ")) { + i += 4; + continue; + } + if (sub.starts_with("class ") || sub.starts_with("union ")) { + i += 5; + continue; + } + if (sub.starts_with("struct ")) { + i += 6; + continue; + } + if (*sub.begin() != ' ') *out++ = *sub.begin(); + } + return out; +# else + return detail::write_bytes(out, string_view(ti.name())); +# endif +} + +} // namespace detail + +FMT_EXPORT +template +struct formatter { + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const std::type_info& ti, Context& ctx) const + -> decltype(ctx.out()) { + return detail::write_demangled_name(ctx.out(), ti); + } +}; +#endif + +FMT_EXPORT +template +struct formatter< + T, Char, // DEPRECATED! Mixing code unit types. + typename std::enable_if::value>::type> { + private: + bool with_typename_ = false; + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it == end || *it == '}') return it; + if (*it == 't') { + ++it; + with_typename_ = FMT_USE_RTTI != 0; + } + return it; + } + + template + auto format(const std::exception& ex, Context& ctx) const + -> decltype(ctx.out()) { + auto out = ctx.out(); +#if FMT_USE_RTTI + if (with_typename_) { + out = detail::write_demangled_name(out, typeid(ex)); + *out++ = ':'; + *out++ = ' '; + } +#endif + return detail::write_bytes(out, string_view(ex.what())); + } +}; + +namespace detail { + +template +struct has_flip : std::false_type {}; + +template +struct has_flip().flip())>> + : std::true_type {}; + +template struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible::value && + std::is_nothrow_assignable::value && has_flip::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template +struct is_bit_reference_like> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector::reference and +// std::bitset::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template +struct formatter::value>> + : formatter { + template + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v, ctx); + } +}; + +template +auto ptr(const std::unique_ptr& p) -> const void* { + return p.get(); +} +template auto ptr(const std::shared_ptr& p) -> const void* { + return p.get(); +} + +FMT_EXPORT +template +struct formatter, Char, + enable_if_t::value>> + : formatter { + template + auto format(const std::atomic& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.load(), ctx); + } +}; + +#ifdef __cpp_lib_atomic_flag_test +FMT_EXPORT +template +struct formatter : formatter { + template + auto format(const std::atomic_flag& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter::format(v.test(), ctx); + } +}; +#endif // __cpp_lib_atomic_flag_test + +FMT_EXPORT +template struct formatter, Char> { + private: + detail::dynamic_format_specs specs_; + + template + FMT_CONSTEXPR auto do_format(const std::complex& c, + detail::dynamic_format_specs& specs, + FormatContext& ctx, OutputIt out) const + -> OutputIt { + if (c.real() != 0) { + *out++ = Char('('); + out = detail::write(out, c.real(), specs, ctx.locale()); + specs.sign = sign::plus; + out = detail::write(out, c.imag(), specs, ctx.locale()); + if (!detail::isfinite(c.imag())) *out++ = Char(' '); + *out++ = Char('i'); + *out++ = Char(')'); + return out; + } + out = detail::write(out, c.imag(), specs, ctx.locale()); + if (!detail::isfinite(c.imag())) *out++ = Char(' '); + *out++ = Char('i'); + return out; + } + + public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); + return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, + detail::type_constant::value); + } + + template + auto format(const std::complex& c, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto specs = specs_; + if (specs.width_ref.kind != detail::arg_id_kind::none || + specs.precision_ref.kind != detail::arg_id_kind::none) { + detail::handle_dynamic_spec(specs.width, + specs.width_ref, ctx); + detail::handle_dynamic_spec( + specs.precision, specs.precision_ref, ctx); + } + + if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); + auto buf = basic_memory_buffer(); + + auto outer_specs = format_specs(); + outer_specs.width = specs.width; + outer_specs.fill = specs.fill; + outer_specs.align = specs.align; + + specs.width = 0; + specs.fill = {}; + specs.align = align::none; + + do_format(c, specs, ctx, basic_appender(buf)); + return detail::write(ctx.out(), + basic_string_view(buf.data(), buf.size()), + outer_specs); + } +}; + +FMT_END_NAMESPACE +#endif // FMT_STD_H_ diff --git a/cpp_src/vendor/fmt/xchar.h b/cpp_src/vendor/fmt/xchar.h new file mode 100644 index 000000000..b1f39ed22 --- /dev/null +++ b/cpp_src/vendor/fmt/xchar.h @@ -0,0 +1,322 @@ +// Formatting library for C++ - optional wchar_t and exotic character support +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_XCHAR_H_ +#define FMT_XCHAR_H_ + +#include "color.h" +#include "format.h" +#include "ranges.h" + +#ifndef FMT_MODULE +# include +# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include +# endif +#endif + +FMT_BEGIN_NAMESPACE +namespace detail { + +template +using is_exotic_char = bool_constant::value>; + +template struct format_string_char {}; + +template +struct format_string_char< + S, void_t())))>> { + using type = char_t; +}; + +template +struct format_string_char::value>> { + using type = typename S::char_type; +}; + +template +using format_string_char_t = typename format_string_char::type; + +inline auto write_loc(basic_appender out, loc_value value, + const format_specs& specs, locale_ref loc) -> bool { +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR + auto& numpunct = + std::use_facet>(loc.get()); + auto separator = std::wstring(); + auto grouping = numpunct.grouping(); + if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); + return value.visit(loc_writer{out, specs, separator, grouping, {}}); +#endif + return false; +} +} // namespace detail + +FMT_BEGIN_EXPORT + +using wstring_view = basic_string_view; +using wformat_parse_context = basic_format_parse_context; +using wformat_context = buffered_context; +using wformat_args = basic_format_args; +using wmemory_buffer = basic_memory_buffer; + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 +// Workaround broken conversion on older gcc. +template using wformat_string = wstring_view; +inline auto runtime(wstring_view s) -> wstring_view { return s; } +#else +template +using wformat_string = basic_format_string...>; +inline auto runtime(wstring_view s) -> runtime_format_string { + return {{s}}; +} +#endif + +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; +template <> struct is_char : std::true_type {}; + +#ifdef __cpp_char8_t +template <> +struct is_char : bool_constant {}; +#endif + +template +constexpr auto make_wformat_args(T&... args) + -> decltype(fmt::make_format_args(args...)) { + return fmt::make_format_args(args...); +} + +inline namespace literals { +#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS +constexpr auto operator""_a(const wchar_t* s, size_t) + -> detail::udl_arg { + return {s}; +} +#endif +} // namespace literals + +template +auto join(It begin, Sentinel end, wstring_view sep) + -> join_view { + return {begin, end, sep}; +} + +template +auto join(Range&& range, wstring_view sep) + -> join_view, detail::sentinel_t, + wchar_t> { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(std::initializer_list list, wstring_view sep) + -> join_view { + return join(std::begin(list), std::end(list), sep); +} + +template +auto join(const std::tuple& tuple, basic_string_view sep) + -> tuple_join_view { + return {tuple, sep}; +} + +template ::value)> +auto vformat(basic_string_view format_str, + typename detail::vformat_args::type args) + -> std::basic_string { + auto buf = basic_memory_buffer(); + detail::vformat_to(buf, format_str, args); + return to_string(buf); +} + +template +auto format(wformat_string fmt, T&&... args) -> std::wstring { + return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template +auto format_to(OutputIt out, wformat_string fmt, T&&... args) + -> OutputIt { + return vformat_to(out, fmt::wstring_view(fmt), + fmt::make_wformat_args(args...)); +} + +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. +template , + FMT_ENABLE_IF(!std::is_same::value && + !std::is_same::value)> +auto format(const S& format_str, T&&... args) -> std::basic_string { + return vformat(detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat(const Locale& loc, const S& format_str, + typename detail::vformat_args::type args) + -> std::basic_string { + return detail::vformat(loc, detail::to_string_view(format_str), args); +} + +template , + FMT_ENABLE_IF(detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto format(const Locale& loc, const S& format_str, T&&... args) + -> std::basic_string { + return detail::vformat( + loc, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +auto vformat_to(OutputIt out, const S& format_str, + typename detail::vformat_args::type args) -> OutputIt { + auto&& buf = detail::get_buffer(out); + detail::vformat_to(buf, detail::to_string_view(format_str), args); + return detail::get_iterator(buf, out); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value && + !std::is_same::value && + !std::is_same::value)> +inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { + return vformat_to(out, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_locale::value&& + detail::is_exotic_char::value)> +inline auto vformat_to(OutputIt out, const Locale& loc, const S& format_str, + typename detail::vformat_args::type args) + -> OutputIt { + auto&& buf = detail::get_buffer(out); + vformat_to(buf, detail::to_string_view(format_str), args, + detail::locale_ref(loc)); + return detail::get_iterator(buf, out); +} + +template , + bool enable = detail::is_output_iterator::value && + detail::is_locale::value && + detail::is_exotic_char::value> +inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, + T&&... args) -> + typename std::enable_if::type { + return vformat_to(out, loc, detail::to_string_view(format_str), + fmt::make_format_args>(args...)); +} + +template ::value&& + detail::is_exotic_char::value)> +inline auto vformat_to_n(OutputIt out, size_t n, + basic_string_view format_str, + typename detail::vformat_args::type args) + -> format_to_n_result { + using traits = detail::fixed_buffer_traits; + auto buf = detail::iterator_buffer(out, n); + detail::vformat_to(buf, format_str, args); + return {buf.out(), buf.count()}; +} + +template , + FMT_ENABLE_IF(detail::is_output_iterator::value&& + detail::is_exotic_char::value)> +inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) + -> format_to_n_result { + return vformat_to_n(out, n, fmt::basic_string_view(fmt), + fmt::make_format_args>(args...)); +} + +template , + FMT_ENABLE_IF(detail::is_exotic_char::value)> +inline auto formatted_size(const S& fmt, T&&... args) -> size_t { + auto buf = detail::counting_buffer(); + detail::vformat_to(buf, detail::to_string_view(fmt), + fmt::make_format_args>(args...)); + return buf.count(); +} + +inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, fmt, args); + buf.push_back(L'\0'); + if (std::fputws(buf.data(), f) == -1) + FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); +} + +inline void vprint(wstring_view fmt, wformat_args args) { + vprint(stdout, fmt, args); +} + +template +void print(std::FILE* f, wformat_string fmt, T&&... args) { + return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template void print(wformat_string fmt, T&&... args) { + return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); +} + +template +void println(std::FILE* f, wformat_string fmt, T&&... args) { + return print(f, L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +template void println(wformat_string fmt, T&&... args) { + return print(L"{}\n", fmt::format(fmt, std::forward(args)...)); +} + +inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) + -> std::wstring { + auto buf = wmemory_buffer(); + detail::vformat_to(buf, ts, fmt, args); + return fmt::to_string(buf); +} + +template +inline auto format(const text_style& ts, wformat_string fmt, T&&... args) + -> std::wstring { + return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); +} + +template +FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, + wformat_string fmt, const T&... args) { + vprint(f, ts, fmt, fmt::make_wformat_args(args...)); +} + +template +FMT_DEPRECATED void print(const text_style& ts, wformat_string fmt, + const T&... args) { + return print(stdout, ts, fmt, args...); +} + +/// Converts `value` to `std::wstring` using the default format for type `T`. +template inline auto to_wstring(const T& value) -> std::wstring { + return format(FMT_STRING(L"{}"), value); +} +FMT_END_EXPORT +FMT_END_NAMESPACE + +#endif // FMT_XCHAR_H_ diff --git a/cpp_src/vendor/gason/gason.cc b/cpp_src/vendor/gason/gason.cc index e13c27768..db4bdb701 100644 --- a/cpp_src/vendor/gason/gason.cc +++ b/cpp_src/vendor/gason/gason.cc @@ -15,7 +15,7 @@ namespace gason { using double_conversion::StringToDoubleConverter; -const char *jsonStrError(int err) { +const char* jsonStrError(int err) { switch (err) { #define XX(no, str) \ case JSON_##no: \ @@ -27,18 +27,20 @@ const char *jsonStrError(int err) { } } -void *JsonAllocator::allocate(size_t size) { +void* JsonAllocator::allocate(size_t size) { size = (size + 7) & ~7; if (head && head->used + size <= JSON_ZONE_SIZE) { - char *p = (char *)head + head->used; + char* p = (char*)head + head->used; head->used += size; return p; } size_t allocSize = sizeof(Zone) + size; - Zone *zone = (Zone *)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); - if (zone == nullptr) return nullptr; + Zone* zone = (Zone*)malloc(allocSize <= JSON_ZONE_SIZE ? JSON_ZONE_SIZE : allocSize); + if (zone == nullptr) { + return nullptr; + } zone->used = allocSize; if (allocSize <= JSON_ZONE_SIZE || head == nullptr) { zone->next = head; @@ -47,12 +49,12 @@ void *JsonAllocator::allocate(size_t size) { zone->next = head->next; head->next = zone; } - return (char *)zone + sizeof(Zone); + return (char*)zone + sizeof(Zone); } void JsonAllocator::deallocate() { while (head) { - Zone *next = head->next; + Zone* next = head->next; free(head); head = next; } @@ -68,11 +70,13 @@ static inline bool isdigit(char c) { return c >= '0' && c <= '9'; } static inline bool isxdigit(char c) { return (c >= '0' && c <= '9') || ((c & ~' ') >= 'A' && (c & ~' ') <= 'F'); } static inline int char2int(char c) { - if (c <= '9') return c - '0'; + if (c <= '9') { + return c - '0'; + } return (c & ~' ') - 'A' + 10; } -bool isDouble(char *s, size_t &size) { +bool isDouble(char* s, size_t& size) { size = 0; if (*s == '-') { @@ -111,7 +115,7 @@ bool isDouble(char *s, size_t &size) { return res; } -static double string2double(char *s, char **endptr, size_t size) { +static double string2double(char* s, char** endptr, size_t size) { StringToDoubleConverter sd(StringToDoubleConverter::NO_FLAGS, 0, 0, "inf", "nan"); int len; double vv = sd.StringToDouble(s, size, &len); @@ -119,14 +123,16 @@ static double string2double(char *s, char **endptr, size_t size) { return vv; } -static inline JsonNode *insertAfter(JsonNode *tail, JsonNode *node) { - if (!tail) return node->next = node; +static inline JsonNode* insertAfter(JsonNode* tail, JsonNode* node) { + if (!tail) { + return node->next = node; + } node->next = tail->next; tail->next = node; return node; } -static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { +static inline JsonValue listToValue(JsonTag tag, JsonNode* tail) { if (tail) { auto head = tail->next; tail->next = nullptr; @@ -135,25 +141,29 @@ static inline JsonValue listToValue(JsonTag tag, JsonNode *tail) { return JsonValue(tag, nullptr); } -static int jsonParse(span str, char **endptr, JsonValue *value, JsonAllocator &allocator, LargeStringStorageT &largeStrings) { - JsonNode *tails[JSON_STACK_SIZE]; +static int jsonParse(span str, char** endptr, JsonValue* value, JsonAllocator& allocator, LargeStringStorageT& largeStrings) { + JsonNode* tails[JSON_STACK_SIZE]; JsonTag tags[JSON_STACK_SIZE]; JsonString keys[JSON_STACK_SIZE]; JsonValue o; int pos = -1; - char *s = str.data(); + char* s = str.data(); size_t l = str.size(); bool separator = true; - JsonNode *node; + JsonNode* node; *endptr = s; size_t size = 0; while (l) { while (l && isspace(*s)) { ++s, --l; - if (!l) break; + if (!l) { + break; + } + } + if (!l) { + break; } - if (!l) break; *endptr = s++; --l; bool negative = false; @@ -193,8 +203,10 @@ static int jsonParse(span str, char **endptr, JsonValue *value, JsonAlloca } break; case '"': - if (s - str.data() < 2) return JSON_UNEXPECTED_CHARACTER; - for (char *it = s - 2; l; ++it, ++s, --l) { + if (s - str.data() < 2) { + return JSON_UNEXPECTED_CHARACTER; + } + for (char* it = s - 2; l; ++it, ++s, --l) { int c = *it = *s; if (c == '\\') { c = *++s; @@ -257,51 +269,75 @@ static int jsonParse(span str, char **endptr, JsonValue *value, JsonAlloca } break; case 't': - if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) return JSON_BAD_IDENTIFIER; + if (!(s[0] == 'r' && s[1] == 'u' && s[2] == 'e' && isdelim(s[3]))) { + return JSON_BAD_IDENTIFIER; + } o = JsonValue(JSON_TRUE); s += 3, l -= 3; break; case 'f': - if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) return JSON_BAD_IDENTIFIER; + if (!(s[0] == 'a' && s[1] == 'l' && s[2] == 's' && s[3] == 'e' && isdelim(s[4]))) { + return JSON_BAD_IDENTIFIER; + } o = JsonValue(JSON_FALSE); s += 4, l -= 4; break; case 'n': - if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) return JSON_BAD_IDENTIFIER; + if (!(s[0] == 'u' && s[1] == 'l' && s[2] == 'l' && isdelim(s[3]))) { + return JSON_BAD_IDENTIFIER; + } o = JsonValue(JSON_NULL); s += 3, l -= 3; break; case ']': - if (pos == -1) return JSON_STACK_UNDERFLOW; - if (tags[pos] != JSON_ARRAY) return JSON_MISMATCH_BRACKET; + if (pos == -1) { + return JSON_STACK_UNDERFLOW; + } + if (tags[pos] != JSON_ARRAY) { + return JSON_MISMATCH_BRACKET; + } o = listToValue(JSON_ARRAY, tails[pos--]); break; case '}': - if (pos == -1) return JSON_STACK_UNDERFLOW; - if (tags[pos] != JSON_OBJECT) return JSON_MISMATCH_BRACKET; - if (keys[pos].ptr != nullptr) return JSON_UNEXPECTED_CHARACTER; + if (pos == -1) { + return JSON_STACK_UNDERFLOW; + } + if (tags[pos] != JSON_OBJECT) { + return JSON_MISMATCH_BRACKET; + } + if (keys[pos].ptr != nullptr) { + return JSON_UNEXPECTED_CHARACTER; + } o = listToValue(JSON_OBJECT, tails[pos--]); break; case '[': - if (++pos == JSON_STACK_SIZE) return JSON_STACK_OVERFLOW; + if (++pos == JSON_STACK_SIZE) { + return JSON_STACK_OVERFLOW; + } tails[pos] = nullptr; tags[pos] = JSON_ARRAY; keys[pos] = JsonString(); separator = true; continue; case '{': - if (++pos == JSON_STACK_SIZE) return JSON_STACK_OVERFLOW; + if (++pos == JSON_STACK_SIZE) { + return JSON_STACK_OVERFLOW; + } tails[pos] = nullptr; tags[pos] = JSON_OBJECT; keys[pos] = JsonString(); separator = true; continue; case ':': - if (separator || keys[pos].ptr == nullptr) return JSON_UNEXPECTED_CHARACTER; + if (separator || keys[pos].ptr == nullptr) { + return JSON_UNEXPECTED_CHARACTER; + } separator = true; continue; case ',': - if (separator || keys[pos].ptr != nullptr) return JSON_UNEXPECTED_CHARACTER; + if (separator || keys[pos].ptr != nullptr) { + return JSON_UNEXPECTED_CHARACTER; + } separator = true; continue; case '\0': @@ -320,16 +356,22 @@ static int jsonParse(span str, char **endptr, JsonValue *value, JsonAlloca if (tags[pos] == JSON_OBJECT) { if (!keys[pos].ptr) { - if (o.getTag() != JSON_STRING) return JSON_UNQUOTED_KEY; + if (o.getTag() != JSON_STRING) { + return JSON_UNQUOTED_KEY; + } keys[pos] = o.sval; continue; } - if ((node = (JsonNode *)allocator.allocate(sizeof(JsonNode))) == nullptr) return JSON_ALLOCATION_FAILURE; + if ((node = (JsonNode*)allocator.allocate(sizeof(JsonNode))) == nullptr) { + return JSON_ALLOCATION_FAILURE; + } tails[pos] = insertAfter(tails[pos], node); tails[pos]->key = keys[pos]; keys[pos] = JsonString(); } else { - if ((node = (JsonNode *)allocator.allocate(sizeof(JsonNode))) == nullptr) return JSON_ALLOCATION_FAILURE; + if ((node = (JsonNode*)allocator.allocate(sizeof(JsonNode))) == nullptr) { + return JSON_ALLOCATION_FAILURE; + } tails[pos] = insertAfter(tails[pos], node); tails[pos]->key = JsonString(); } @@ -338,39 +380,47 @@ static int jsonParse(span str, char **endptr, JsonValue *value, JsonAlloca return JSON_BREAKING_BAD; } -JsonNode *JsonNode::toNode() const { - if (empty() || value.getTag() == JSON_NULL) return nullptr; - if (value.getTag() != JSON_OBJECT && value.getTag() != JSON_ARRAY) +JsonNode* JsonNode::toNode() const { + if (empty() || value.getTag() == JSON_NULL) { + return nullptr; + } + if (value.getTag() != JSON_OBJECT && value.getTag() != JSON_ARRAY) { throw Exception(std::string("Can't convert json field '") + std::string(key) + "' to object or array"); + } return value.toNode(); } -const JsonNode &JsonNode::operator[](std::string_view key) const { +const JsonNode& JsonNode::operator[](std::string_view key) const { if (value.getTag() != JSON_OBJECT && value.getTag() != JSON_NULL) { throw Exception(std::string("Can't obtain json field '") + std::string(key) + "' from non-object json node"); } - for (auto &v : (*this)) - if (std::string_view(v.key) == key) return v; + for (auto& v : (*this)) { + if (std::string_view(v.key) == key) { + return v; + } + } // TODO: Remove NOLINT after pyreindexer update. Issue #1736 static JsonNode empty_node{{JsonTag(JSON_EMPTY)}, nullptr, {}}; // NOLINT(*EnumCastOutOfRange) return empty_node; } -JsonNode JsonParser::Parse(span str, size_t *length) { +JsonNode JsonParser::Parse(span str, size_t* length) { largeStrings_->clear(); - char *endp = nullptr; + char* endp = nullptr; JsonNode val{{}, nullptr, {}}; - const char *begin = str.data(); + const char* begin = str.data(); int status = jsonParse(str, &endp, &val.value, alloc_, *largeStrings_); if (status != JSON_OK) { size_t pos = endp - str.data(); throw Exception(std::string("Error parsing json: ") + jsonStrError(status) + ", pos " + std::to_string(pos)); } - if (length) *length = endp - begin; + if (length) { + *length = endp - begin; + } return val; } -JsonNode JsonParser::Parse(std::string_view str, size_t *length) { +JsonNode JsonParser::Parse(std::string_view str, size_t* length) { tmp_.reserve(str.size()); tmp_.assign(str.begin(), str.end()); return Parse(span(&tmp_[0], tmp_.size()), length); @@ -380,12 +430,14 @@ static inline bool haveEqualType(JsonTag lt, JsonTag rt) noexcept { return lt == rt || (lt == JSON_TRUE && rt == JSON_FALSE) || (lt == JSON_FALSE && rt == JSON_TRUE); } -bool isHomogeneousArray(const gason::JsonValue &v) noexcept { +bool isHomogeneousArray(const gason::JsonValue& v) noexcept { bool hasTag = false; gason::JsonTag prevTag; - for (const auto &elem : v) { + for (const auto& elem : v) { if (hasTag) { - if (!haveEqualType(prevTag, elem.value.getTag())) return false; + if (!haveEqualType(prevTag, elem.value.getTag())) { + return false; + } } else { hasTag = true; } diff --git a/cpp_src/vendor/gason/gason.h b/cpp_src/vendor/gason/gason.h index 906634e67..77899bb6c 100644 --- a/cpp_src/vendor/gason/gason.h +++ b/cpp_src/vendor/gason/gason.h @@ -25,6 +25,7 @@ enum JsonTag : uint8_t { JSON_FALSE, JSON_NULL = 0xF, }; +constexpr inline int format_as(JsonTag v) noexcept { return int(v); } // TODO: Move this to the JsonTag-enum, when pyreindexer deploy will be fixed. Currently this would break old pyrx builds // Issue #1736 @@ -37,33 +38,35 @@ using Exception = std::runtime_error; using LargeStringStorageT = std::vector>; struct JsonString { - JsonString(char *beg, char *end, LargeStringStorageT &largeStrings) { + JsonString(char* beg, char* end, LargeStringStorageT& largeStrings) { ptr = end; const uint64_t l = end - beg; if (l >= (uint64_t(1) << 31)) { throw Exception("JSON string too long. Limit is 2^31 bytes"); } - reindexer::json_string::encode(reinterpret_cast(end), l, largeStrings); + reindexer::json_string::encode(reinterpret_cast(end), l, largeStrings); } - JsonString(const char *end = nullptr) : ptr(end) {} + JsonString(const char* end = nullptr) : ptr(end) {} size_t length() const noexcept { assertrx(ptr); - return reindexer::json_string::length(reinterpret_cast(ptr)); + return reindexer::json_string::length(reinterpret_cast(ptr)); } size_t size() const noexcept { return ptr ? length() : 0; } - const char *data() const noexcept { - if (!ptr) return nullptr; + const char* data() const noexcept { + if (!ptr) { + return nullptr; + } - return reindexer::json_string::to_string_view(reinterpret_cast(ptr)).data(); + return reindexer::json_string::to_string_view(reinterpret_cast(ptr)).data(); } explicit operator std::string() const { return ptr ? std::string(data(), length()) : std::string(); } operator std::string_view() const noexcept { return ptr ? std::string_view(data(), length()) : std::string_view(); } - const char *ptr; + const char* ptr; }; -inline static std::ostream &operator<<(std::ostream &o, const gason::JsonString &sv) { +inline static std::ostream& operator<<(std::ostream& o, const gason::JsonString& sv) { o.write(sv.data(), sv.length()); return o; } @@ -73,7 +76,7 @@ union JsonValue { JsonValue(int64_t x) : ival(x) { u.tag = JSON_NUMBER; } JsonValue(JsonString x) : sval(x) { u.tag = JSON_STRING; } - JsonValue(JsonTag tag = JSON_NULL, void *payload = nullptr) { + JsonValue(JsonTag tag = JSON_NULL, void* payload = nullptr) { u.tag = tag; ival = uintptr_t(payload); } @@ -82,19 +85,23 @@ union JsonValue { int64_t toNumber() const { assertrx(getTag() == JSON_NUMBER || getTag() == JSON_DOUBLE); - if (getTag() == JSON_NUMBER) return ival; + if (getTag() == JSON_NUMBER) { + return ival; + } return fval; } double toDouble() const { assertrx(getTag() == JSON_NUMBER || getTag() == JSON_DOUBLE); - if (getTag() == JSON_DOUBLE) return fval; + if (getTag() == JSON_DOUBLE) { + return fval; + } return ival; } std::string_view toString() const { assertrx(getTag() == JSON_STRING); return sval; } - JsonNode *toNode() const { + JsonNode* toNode() const { assertrx(getTag() == JSON_ARRAY || getTag() == JSON_OBJECT); return node; } @@ -106,41 +113,52 @@ union JsonValue { int64_t ival; double fval; JsonString sval; - JsonNode *node; + JsonNode* node; }; struct JsonNode { JsonValue value; - JsonNode *next; + JsonNode* next; JsonString key; template ::value || std::is_floating_point::value) && - !std::is_same::value>::type * = nullptr> + !std::is_same::value>::type* = nullptr> T As(T defval = T(), T minv = std::numeric_limits::lowest(), T maxv = std::numeric_limits::max()) const { - if (empty()) return defval; - if (value.getTag() != JSON_DOUBLE && value.getTag() != JSON_NUMBER) + if (empty()) { + return defval; + } + if (value.getTag() != JSON_DOUBLE && value.getTag() != JSON_NUMBER) { throw Exception(std::string("Can't convert json field '") + std::string(key) + "' to number"); + } T v; - if (std::is_integral::value) + if (std::is_integral::value) { v = value.toNumber(); - else + } else { v = value.toDouble(); + } - if (v < minv || v > maxv) + if (v < minv || v > maxv) { throw Exception(std::string("Value of '") + std::string(key) + "' - " + std::to_string(v) + " is out of bounds: [" + std::to_string(minv) + "," + std::to_string(maxv) + "]"); + } return v; } template ::value || std::is_same::value>::type * = nullptr> + typename std::enable_if::value || std::is_same::value>::type* = nullptr> T As(T defval = T()) const { - if (empty()) return defval; - if (value.getTag() != JSON_STRING) throw Exception(std::string("Can't convert json field '") + std::string(key) + "' to string"); + if (empty()) { + return defval; + } + if (value.getTag() != JSON_STRING) { + throw Exception(std::string("Can't convert json field '") + std::string(key) + "' to string"); + } return T(value.toString()); } - template ::value>::type * = nullptr> + template ::value>::type* = nullptr> T As(T defval = T()) const { - if (empty()) return defval; + if (empty()) { + return defval; + } switch (value.getTag()) { case JSON_TRUE: return true; @@ -157,35 +175,35 @@ struct JsonNode { } } - const JsonNode &operator[](std::string_view sv) const; + const JsonNode& operator[](std::string_view sv) const; bool empty() const noexcept { return uint8_t(value.getTag()) == JSON_EMPTY; } bool isObject() const noexcept { return value.getTag() == JSON_OBJECT; } - JsonNode *toNode() const; + JsonNode* toNode() const; }; struct JsonIterator { - JsonNode *p; + JsonNode* p; void operator++() noexcept { p = p->next; } - bool operator!=(const JsonIterator &x) const noexcept { return p != x.p; } - JsonNode &operator*() const noexcept { return *p; } - JsonNode *operator->() const noexcept { return p; } + bool operator!=(const JsonIterator& x) const noexcept { return p != x.p; } + JsonNode& operator*() const noexcept { return *p; } + JsonNode* operator->() const noexcept { return p; } }; inline JsonIterator begin(const JsonValue o) { return JsonIterator{o.toNode()}; } inline JsonIterator end(JsonValue) noexcept { return JsonIterator{nullptr}; } struct JsonNodeIterator { - const JsonNode *p; + const JsonNode* p; void operator++() noexcept { p = p->next; } - bool operator!=(const JsonNodeIterator &x) const noexcept { return p != x.p; } - const JsonNode &operator*() const noexcept { return *p; } - const JsonNode *operator->() const noexcept { return p; } + bool operator!=(const JsonNodeIterator& x) const noexcept { return p != x.p; } + const JsonNode& operator*() const noexcept { return *p; } + const JsonNode* operator->() const noexcept { return p; } }; -inline JsonNodeIterator begin(const JsonNode &w) { return JsonNodeIterator{w.toNode()}; } -inline JsonNodeIterator end(const JsonNode &) noexcept { return JsonNodeIterator{nullptr}; } +inline JsonNodeIterator begin(const JsonNode& w) { return JsonNodeIterator{w.toNode()}; } +inline JsonNodeIterator end(const JsonNode&) noexcept { return JsonNodeIterator{nullptr}; } #define JSON_ERRNO_MAP(XX) \ XX(OK, "ok") \ @@ -206,20 +224,20 @@ enum JsonErrno { #undef XX }; -const char *jsonStrError(int err); +const char* jsonStrError(int err); class JsonAllocator { struct Zone { - Zone *next; + Zone* next; size_t used; - } *head; + }* head; public: JsonAllocator() : head(nullptr) {} - JsonAllocator(const JsonAllocator &) = delete; - JsonAllocator &operator=(const JsonAllocator &) = delete; - JsonAllocator(JsonAllocator &&x) : head(x.head) { x.head = nullptr; } - JsonAllocator &operator=(JsonAllocator &&x) noexcept { + JsonAllocator(const JsonAllocator&) = delete; + JsonAllocator& operator=(const JsonAllocator&) = delete; + JsonAllocator(JsonAllocator&& x) : head(x.head) { x.head = nullptr; } + JsonAllocator& operator=(JsonAllocator&& x) noexcept { if (this != &x) { deallocate(); head = x.head; @@ -228,26 +246,26 @@ class JsonAllocator { return *this; } ~JsonAllocator() { deallocate(); } - void *allocate(size_t size); + void* allocate(size_t size); void deallocate(); }; -bool isHomogeneousArray(const JsonValue &v) noexcept; +bool isHomogeneousArray(const JsonValue& v) noexcept; // Parser wrapper class JsonParser { public: - JsonParser(LargeStringStorageT *strings = nullptr) : largeStrings_(strings ? strings : &internalLargeStrings_) {} + JsonParser(LargeStringStorageT* strings = nullptr) : largeStrings_(strings ? strings : &internalLargeStrings_) {} // Inplace parse. Buffer pointed by str will be changed - JsonNode Parse(span str, size_t *length = nullptr); + JsonNode Parse(span str, size_t* length = nullptr); // Copy str. Buffer pointed by str will be copied - JsonNode Parse(std::string_view str, size_t *length = nullptr); + JsonNode Parse(std::string_view str, size_t* length = nullptr); private: JsonAllocator alloc_; std::string tmp_; LargeStringStorageT internalLargeStrings_; - LargeStringStorageT *largeStrings_; + LargeStringStorageT* largeStrings_; }; } // namespace gason diff --git a/cpp_src/vendor/msgpack/msgpackparser.h b/cpp_src/vendor/msgpack/msgpackparser.h index af6356c59..37d8755ea 100644 --- a/cpp_src/vendor/msgpack/msgpackparser.h +++ b/cpp_src/vendor/msgpack/msgpackparser.h @@ -17,6 +17,7 @@ enum MsgPackTag : int { MSGPACK_ARRAY = 0x06, MSGPACK_MAP = 0x07, }; +inline constexpr int format_as(MsgPackTag v) noexcept { return int(v); } struct MsgPackValue { explicit MsgPackValue(const msgpack_object* p = nullptr); @@ -25,7 +26,9 @@ struct MsgPackValue { template ::value || std::is_floating_point::value) && !std::is_same::value>::type* = nullptr> T As(T defval = T(), T minv = std::numeric_limits::lowest(), T maxv = std::numeric_limits::max()) const { - if (!isValid()) return defval; + if (!isValid()) { + return defval; + } T v; MsgPackTag tag = getTag(); switch (tag) { @@ -47,13 +50,17 @@ struct MsgPackValue { default: throw reindexer::Error(errParseMsgPack, "Impossible to convert type [%d] to number", tag); } - if (v < minv || v > maxv) throw reindexer::Error(errParams, fmt::format("Value is out of bounds: [{},{}]", minv, maxv)); + if (v < minv || v > maxv) { + throw reindexer::Error(errParams, fmt::format("Value is out of bounds: [{},{}]", minv, maxv)); + } return v; } template ::value || std::is_same::value>::type* = nullptr> T As(T defval = T()) const { - if (!isValid()) return defval; + if (!isValid()) { + return defval; + } MsgPackTag tag = getTag(); if (tag != MSGPACK_STRING) { throw reindexer::Error(errParseMsgPack, "Impossible to convert type [%d] to string", tag); @@ -62,7 +69,9 @@ struct MsgPackValue { } template ::value>::type* = nullptr> T As(T defval = T()) const { - if (!isValid()) return defval; + if (!isValid()) { + return defval; + } MsgPackTag tag = getTag(); if (tag != MSGPACK_BOOLEAN) { throw reindexer::Error(errParseMsgPack, "Impossible to convert type [%d] to bool", tag); @@ -104,7 +113,9 @@ class MsgPackParser { MsgPackValue Parse(T data, size_t& offset) { prepare(); msgpack_unpack_return ret = msgpack_unpack_next(&unpacked_, data.data(), data.size(), &offset); - if (ret != MSGPACK_UNPACK_SUCCESS) return MsgPackValue(nullptr); + if (ret != MSGPACK_UNPACK_SUCCESS) { + return MsgPackValue(nullptr); + } return MsgPackValue(&unpacked_.data); } diff --git a/cpp_src/vendor/spdlog/async.h b/cpp_src/vendor/spdlog/async.h new file mode 100644 index 000000000..e96abd199 --- /dev/null +++ b/cpp_src/vendor/spdlog/async.h @@ -0,0 +1,100 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Async logging using global thread pool +// All loggers created here share same global thread pool. +// Each log message is pushed to a queue along with a shared pointer to the +// logger. +// If a logger deleted while having pending messages in the queue, it's actual +// destruction will defer +// until all its messages are processed by the thread pool. +// This is because each message in the queue holds a shared_ptr to the +// originating logger. + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { + +namespace details { +static const size_t default_async_q_size = 8192; +} + +// async logger factory - creates async loggers backed with thread pool. +// if a global thread pool doesn't already exist, create it with default queue +// size of 8192 items and single thread. +template +struct async_factory_impl { + template + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { + auto ®istry_inst = details::registry::instance(); + + // create global thread pool if not already exists.. + + auto &mutex = registry_inst.tp_mutex(); + std::lock_guard tp_lock(mutex); + auto tp = registry_inst.get_tp(); + if (tp == nullptr) { + tp = std::make_shared(details::default_async_q_size, 1U); + registry_inst.set_tp(tp); + } + + auto sink = std::make_shared(std::forward(args)...); + auto new_logger = std::make_shared(std::move(logger_name), std::move(sink), + std::move(tp), OverflowPolicy); + registry_inst.initialize_logger(new_logger); + return new_logger; + } +}; + +using async_factory = async_factory_impl; +using async_factory_nonblock = async_factory_impl; + +template +inline std::shared_ptr create_async(std::string logger_name, + SinkArgs &&...sink_args) { + return async_factory::create(std::move(logger_name), + std::forward(sink_args)...); +} + +template +inline std::shared_ptr create_async_nb(std::string logger_name, + SinkArgs &&...sink_args) { + return async_factory_nonblock::create(std::move(logger_name), + std::forward(sink_args)...); +} + +// set global thread pool. +inline void init_thread_pool(size_t q_size, + size_t thread_count, + std::function on_thread_start, + std::function on_thread_stop) { + auto tp = std::make_shared(q_size, thread_count, on_thread_start, + on_thread_stop); + details::registry::instance().set_tp(std::move(tp)); +} + +inline void init_thread_pool(size_t q_size, + size_t thread_count, + std::function on_thread_start) { + init_thread_pool(q_size, thread_count, on_thread_start, [] {}); +} + +inline void init_thread_pool(size_t q_size, size_t thread_count) { + init_thread_pool( + q_size, thread_count, [] {}, [] {}); +} + +// get the global thread pool. +inline std::shared_ptr thread_pool() { + return details::registry::instance().get_tp(); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/async_logger-inl.h b/cpp_src/vendor/spdlog/async_logger-inl.h new file mode 100644 index 000000000..499800d88 --- /dev/null +++ b/cpp_src/vendor/spdlog/async_logger-inl.h @@ -0,0 +1,86 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +#include +#include + +SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name, + sinks_init_list sinks_list, + std::weak_ptr tp, + async_overflow_policy overflow_policy) + : async_logger(std::move(logger_name), + sinks_list.begin(), + sinks_list.end(), + std::move(tp), + overflow_policy) {} + +SPDLOG_INLINE spdlog::async_logger::async_logger(std::string logger_name, + sink_ptr single_sink, + std::weak_ptr tp, + async_overflow_policy overflow_policy) + : async_logger( + std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) {} + +// send the log message to the thread pool +SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg){ + SPDLOG_TRY{if (auto pool_ptr = thread_pool_.lock()){ + pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); +} +else { + throw_spdlog_ex("async log: thread pool doesn't exist anymore"); +} +} +SPDLOG_LOGGER_CATCH(msg.source) +} + +// send flush request to the thread pool +SPDLOG_INLINE void spdlog::async_logger::flush_(){SPDLOG_TRY{auto pool_ptr = thread_pool_.lock(); +if (!pool_ptr) { + throw_spdlog_ex("async flush: thread pool doesn't exist anymore"); +} + +std::future future = pool_ptr->post_flush(shared_from_this(), overflow_policy_); +// Wait for the flush operation to complete. +// This might throw exception if the flush message get dropped because of overflow. +future.get(); +} +SPDLOG_LOGGER_CATCH(source_loc()) +} + +// +// backend functions - called from the thread pool to do the actual job +// +SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) { + for (auto &sink : sinks_) { + if (sink->should_log(msg.level)) { + SPDLOG_TRY { sink->log(msg); } + SPDLOG_LOGGER_CATCH(msg.source) + } + } + + if (should_flush_(msg)) { + backend_flush_(); + } +} + +SPDLOG_INLINE void spdlog::async_logger::backend_flush_() { + for (auto &sink : sinks_) { + SPDLOG_TRY { sink->flush(); } + SPDLOG_LOGGER_CATCH(source_loc()) + } +} + +SPDLOG_INLINE std::shared_ptr spdlog::async_logger::clone(std::string new_name) { + auto cloned = std::make_shared(*this); + cloned->name_ = std::move(new_name); + return cloned; +} diff --git a/cpp_src/vendor/spdlog/async_logger.h b/cpp_src/vendor/spdlog/async_logger.h index be577a3bc..846c4c6f0 100644 --- a/cpp_src/vendor/spdlog/async_logger.h +++ b/cpp_src/vendor/spdlog/async_logger.h @@ -1,81 +1,74 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -// Very fast asynchronous logger (millions of logs per second on an average desktop) -// Uses pre allocated lockfree queue for maximum throughput even under large number of threads. +// Fast asynchronous logger. +// Uses pre allocated queue. // Creates a single back thread to pop messages from the queue and log them. // // Upon each log write the logger: // 1. Checks if its log level is enough to log the message -// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue) -// 3. will throw spdlog_ex upon log exceptions -// Upon destruction, logs all remaining messages in the queue before destructing.. +// 2. Push a new copy of the message to a queue (or block the caller until +// space is available in the queue) +// Upon destruction, logs all remaining messages in the queue before +// destructing.. -#include "common.h" -#include "logger.h" +#include -#include -#include -#include -#include +namespace spdlog { -namespace spdlog -{ +// Async overflow policy - block by default. +enum class async_overflow_policy { + block, // Block until message can be enqueued + overrun_oldest, // Discard oldest message in the queue if full when trying to + // add new item. + discard_new // Discard new message if the queue is full when trying to add new item. +}; -namespace details -{ -class async_log_helper; +namespace details { +class thread_pool; } -class async_logger SPDLOG_FINAL : public logger -{ +class SPDLOG_API async_logger final : public std::enable_shared_from_this, + public logger { + friend class details::thread_pool; + public: - template - async_logger(const std::string& logger_name, - const It& begin, - const It& end, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), - const std::function& worker_teardown_cb = nullptr); + template + async_logger(std::string logger_name, + It begin, + It end, + std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block) + : logger(std::move(logger_name), begin, end), + thread_pool_(std::move(tp)), + overflow_policy_(overflow_policy) {} - async_logger(const std::string& logger_name, - sinks_init_list sinks, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), - const std::function& worker_teardown_cb = nullptr); + async_logger(std::string logger_name, + sinks_init_list sinks_list, + std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); - async_logger(const std::string& logger_name, + async_logger(std::string logger_name, sink_ptr single_sink, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), - const std::function& worker_teardown_cb = nullptr); - - //Wait for the queue to be empty, and flush synchronously - //Warning: this can potentially last forever as we wait it to complete - void flush() override; + std::weak_ptr tp, + async_overflow_policy overflow_policy = async_overflow_policy::block); - // Error handler - void set_error_handler(log_err_handler) override; - log_err_handler error_handler() override; + std::shared_ptr clone(std::string new_name) override; protected: - void _sink_it(details::log_msg& msg) override; - void _set_formatter(spdlog::formatter_ptr msg_formatter) override; - void _set_pattern(const std::string& pattern, pattern_time_type pattern_time) override; + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + void backend_sink_it_(const details::log_msg &incoming_log_msg); + void backend_flush_(); private: - std::unique_ptr _async_log_helper; + std::weak_ptr thread_pool_; + async_overflow_policy overflow_policy_; }; -} +} // namespace spdlog -#include "details/async_logger_impl.h" +#ifdef SPDLOG_HEADER_ONLY + #include "async_logger-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/cfg/argv.h b/cpp_src/vendor/spdlog/cfg/argv.h new file mode 100644 index 000000000..7de2f83e7 --- /dev/null +++ b/cpp_src/vendor/spdlog/cfg/argv.h @@ -0,0 +1,40 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include + +// +// Init log levels using each argv entry that starts with "SPDLOG_LEVEL=" +// +// set all loggers to debug level: +// example.exe "SPDLOG_LEVEL=debug" + +// set logger1 to trace level +// example.exe "SPDLOG_LEVEL=logger1=trace" + +// turn off all logging except for logger1 and logger2: +// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { + +// search for SPDLOG_LEVEL= in the args and use it to init the levels +inline void load_argv_levels(int argc, const char **argv) { + const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg.find(spdlog_level_prefix) == 0) { + auto levels_string = arg.substr(spdlog_level_prefix.size()); + helpers::load_levels(levels_string); + } + } +} + +inline void load_argv_levels(int argc, char **argv) { + load_argv_levels(argc, const_cast(argv)); +} + +} // namespace cfg +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/cfg/env.h b/cpp_src/vendor/spdlog/cfg/env.h new file mode 100644 index 000000000..6e5541454 --- /dev/null +++ b/cpp_src/vendor/spdlog/cfg/env.h @@ -0,0 +1,36 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include +#include +#include + +// +// Init levels and patterns from env variables SPDLOG_LEVEL +// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger). +// Note - fallback to "info" level on unrecognized levels +// +// Examples: +// +// set global level to debug: +// export SPDLOG_LEVEL=debug +// +// turn off all logging except for logger1: +// export SPDLOG_LEVEL="*=off,logger1=debug" +// + +// turn off all logging except for logger1 and logger2: +// export SPDLOG_LEVEL="off,logger1=debug,logger2=info" + +namespace spdlog { +namespace cfg { +inline void load_env_levels() { + auto env_val = details::os::getenv("SPDLOG_LEVEL"); + if (!env_val.empty()) { + helpers::load_levels(env_val); + } +} + +} // namespace cfg +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/cfg/helpers-inl.h b/cpp_src/vendor/spdlog/cfg/helpers-inl.h new file mode 100644 index 000000000..93650a2e8 --- /dev/null +++ b/cpp_src/vendor/spdlog/cfg/helpers-inl.h @@ -0,0 +1,107 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include +#include + +#include +#include +#include +#include + +namespace spdlog { +namespace cfg { +namespace helpers { + +// inplace convert to lowercase +inline std::string &to_lower_(std::string &str) { + std::transform(str.begin(), str.end(), str.begin(), [](char ch) { + return static_cast((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); + }); + return str; +} + +// inplace trim spaces +inline std::string &trim_(std::string &str) { + const char *spaces = " \n\r\t"; + str.erase(str.find_last_not_of(spaces) + 1); + str.erase(0, str.find_first_not_of(spaces)); + return str; +} + +// return (name,value) trimmed pair from given "name=value" string. +// return empty string on missing parts +// "key=val" => ("key", "val") +// " key = val " => ("key", "val") +// "key=" => ("key", "") +// "val" => ("", "val") + +inline std::pair extract_kv_(char sep, const std::string &str) { + auto n = str.find(sep); + std::string k, v; + if (n == std::string::npos) { + v = str; + } else { + k = str.substr(0, n); + v = str.substr(n + 1); + } + return std::make_pair(trim_(k), trim_(v)); +} + +// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." +// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} +inline std::unordered_map extract_key_vals_(const std::string &str) { + std::string token; + std::istringstream token_stream(str); + std::unordered_map rv{}; + while (std::getline(token_stream, token, ',')) { + if (token.empty()) { + continue; + } + auto kv = extract_kv_('=', token); + rv[kv.first] = kv.second; + } + return rv; +} + +SPDLOG_INLINE void load_levels(const std::string &input) { + if (input.empty() || input.size() > 512) { + return; + } + + auto key_vals = extract_key_vals_(input); + std::unordered_map levels; + level::level_enum global_level = level::info; + bool global_level_found = false; + + for (auto &name_level : key_vals) { + auto &logger_name = name_level.first; + auto level_name = to_lower_(name_level.second); + auto level = level::from_str(level_name); + // ignore unrecognized level names + if (level == level::off && level_name != "off") { + continue; + } + if (logger_name.empty()) // no logger name indicate global level + { + global_level_found = true; + global_level = level; + } else { + levels[logger_name] = level; + } + } + + details::registry::instance().set_levels(std::move(levels), + global_level_found ? &global_level : nullptr); +} + +} // namespace helpers +} // namespace cfg +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/cfg/helpers.h b/cpp_src/vendor/spdlog/cfg/helpers.h new file mode 100644 index 000000000..c02381891 --- /dev/null +++ b/cpp_src/vendor/spdlog/cfg/helpers.h @@ -0,0 +1,29 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace cfg { +namespace helpers { +// +// Init levels from given string +// +// Examples: +// +// set global level to debug: "debug" +// turn off all logging except for logger1: "off,logger1=debug" +// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info" +// +SPDLOG_API void load_levels(const std::string &txt); +} // namespace helpers + +} // namespace cfg +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "helpers-inl.h" +#endif // SPDLOG_HEADER_ONLY diff --git a/cpp_src/vendor/spdlog/common-inl.h b/cpp_src/vendor/spdlog/common-inl.h new file mode 100644 index 000000000..a8a0453c1 --- /dev/null +++ b/cpp_src/vendor/spdlog/common-inl.h @@ -0,0 +1,68 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +namespace spdlog { +namespace level { + +#if __cplusplus >= 201703L +constexpr +#endif + static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; + +static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; + +SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT { + return level_string_views[l]; +} + +SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT { + return short_level_names[l]; +} + +SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT { + auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); + if (it != std::end(level_string_views)) + return static_cast(std::distance(std::begin(level_string_views), it)); + + // check also for "warn" and "err" before giving up.. + if (name == "warn") { + return level::warn; + } + if (name == "err") { + return level::err; + } + return level::off; +} +} // namespace level + +SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) + : msg_(std::move(msg)) {} + +SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) { +#ifdef SPDLOG_USE_STD_FORMAT + msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); +#else + memory_buf_t outbuf; + fmt::format_system_error(outbuf, last_errno, msg.c_str()); + msg_ = fmt::to_string(outbuf); +#endif +} + +SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT { return msg_.c_str(); } + +SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) { + SPDLOG_THROW(spdlog_ex(msg, last_errno)); +} + +SPDLOG_INLINE void throw_spdlog_ex(std::string msg) { SPDLOG_THROW(spdlog_ex(std::move(msg))); } + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/common.h b/cpp_src/vendor/spdlog/common.h index cdf738234..aca483c20 100644 --- a/cpp_src/vendor/spdlog/common.h +++ b/cpp_src/vendor/spdlog/common.h @@ -1,168 +1,411 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#define SPDLOG_VERSION "0.16.3" - -#include "tweakme.h" +#include +#include -#include -#include -#include -#include #include +#include +#include #include -#include +#include +#include +#include +#include +#include -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -#include -#include +#ifdef SPDLOG_USE_STD_FORMAT + #include + #if __cpp_lib_format >= 202207L + #include + #else + #include + #endif #endif -#include "details/null_mutex.h" +#ifdef SPDLOG_COMPILED_LIB + #undef SPDLOG_HEADER_ONLY + #if defined(SPDLOG_SHARED_LIB) + #if defined(_WIN32) + #ifdef spdlog_EXPORTS + #define SPDLOG_API __declspec(dllexport) + #else // !spdlog_EXPORTS + #define SPDLOG_API __declspec(dllimport) + #endif + #else // !defined(_WIN32) + #define SPDLOG_API __attribute__((visibility("default"))) + #endif + #else // !defined(SPDLOG_SHARED_LIB) + #define SPDLOG_API + #endif + #define SPDLOG_INLINE +#else // !defined(SPDLOG_COMPILED_LIB) + #define SPDLOG_API + #define SPDLOG_HEADER_ONLY + #define SPDLOG_INLINE inline +#endif // #ifdef SPDLOG_COMPILED_LIB -//visual studio upto 2013 does not support noexcept nor constexpr -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#define SPDLOG_NOEXCEPT throw() -#define SPDLOG_CONSTEXPR +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) && \ + FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8 + #define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) + #define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string) + #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) + #include + #endif #else -#define SPDLOG_NOEXCEPT noexcept -#define SPDLOG_CONSTEXPR constexpr + #define SPDLOG_FMT_RUNTIME(format_string) format_string + #define SPDLOG_FMT_STRING(format_string) format_string #endif -// final keyword support. On by default. See tweakme.h -#if defined(SPDLOG_NO_FINAL) -#define SPDLOG_FINAL +// visual studio up to 2013 does not support noexcept nor constexpr +#if defined(_MSC_VER) && (_MSC_VER < 1900) + #define SPDLOG_NOEXCEPT _NOEXCEPT + #define SPDLOG_CONSTEXPR #else -#define SPDLOG_FINAL final + #define SPDLOG_NOEXCEPT noexcept + #define SPDLOG_CONSTEXPR constexpr #endif -#if defined(__GNUC__) || defined(__clang__) -#define SPDLOG_DEPRECATED __attribute__((deprecated)) +// If building with std::format, can just use constexpr, otherwise if building with fmt +// SPDLOG_CONSTEXPR_FUNC needs to be set the same as FMT_CONSTEXPR to avoid situations where +// a constexpr function in spdlog could end up calling a non-constexpr function in fmt +// depending on the compiler +// If fmt determines it can't use constexpr, we should inline the function instead +#ifdef SPDLOG_USE_STD_FORMAT + #define SPDLOG_CONSTEXPR_FUNC constexpr +#else // Being built with fmt + #if FMT_USE_CONSTEXPR + #define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR + #else + #define SPDLOG_CONSTEXPR_FUNC inline + #endif +#endif + +#if defined(__GNUC__) || defined(__clang__) + #define SPDLOG_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) -#define SPDLOG_DEPRECATED __declspec(deprecated) + #define SPDLOG_DEPRECATED __declspec(deprecated) #else -#define SPDLOG_DEPRECATED + #define SPDLOG_DEPRECATED #endif -#include "fmt/fmt.h" -#include "tools/clock.h" +// disable thread local on msvc 2013 +#ifndef SPDLOG_NO_TLS + #if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) + #define SPDLOG_NO_TLS 1 + #endif +#endif + +#ifndef SPDLOG_FUNCTION + #define SPDLOG_FUNCTION static_cast(__FUNCTION__) +#endif + +#ifdef SPDLOG_NO_EXCEPTIONS + #define SPDLOG_TRY + #define SPDLOG_THROW(ex) \ + do { \ + printf("spdlog fatal error: %s\n", ex.what()); \ + std::abort(); \ + } while (0) + #define SPDLOG_CATCH_STD +#else + #define SPDLOG_TRY try + #define SPDLOG_THROW(ex) throw(ex) + #define SPDLOG_CATCH_STD \ + catch (const std::exception &) { \ + } +#endif -namespace spdlog -{ +namespace spdlog { class formatter; -namespace sinks -{ +namespace sinks { class sink; } -using log_clock = reindexer::system_clock_w; -using sink_ptr = std::shared_ptr < sinks::sink >; -using sinks_init_list = std::initializer_list < sink_ptr >; -using formatter_ptr = std::shared_ptr; +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +using filename_t = std::wstring; + // allow macro expansion to occur in SPDLOG_FILENAME_T + #define SPDLOG_FILENAME_T_INNER(s) L##s + #define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) +#else +using filename_t = std::string; + #define SPDLOG_FILENAME_T(s) s +#endif + +using log_clock = std::chrono::system_clock; +using sink_ptr = std::shared_ptr; +using sinks_init_list = std::initializer_list; +using err_handler = std::function; +#ifdef SPDLOG_USE_STD_FORMAT +namespace fmt_lib = std; + +using string_view_t = std::string_view; +using memory_buf_t = std::string; + +template + #if __cpp_lib_format >= 202207L +using format_string_t = std::format_string; + #else +using format_string_t = std::string_view; + #endif + +template +struct is_convertible_to_basic_format_string + : std::integral_constant>::value> {}; + + #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = std::wstring_view; +using wmemory_buf_t = std::wstring; + +template + #if __cpp_lib_format >= 202207L +using wformat_string_t = std::wformat_string; + #else +using wformat_string_t = std::wstring_view; + #endif + #endif + #define SPDLOG_BUF_TO_STRING(x) x +#else // use fmt lib instead of std::format +namespace fmt_lib = fmt; + +using string_view_t = fmt::basic_string_view; +using memory_buf_t = fmt::basic_memory_buffer; + +template +using format_string_t = fmt::format_string; + +template +using remove_cvref_t = typename std::remove_cv::type>::type; + +template + #if FMT_VERSION >= 90101 +using fmt_runtime_string = fmt::runtime_format_string; + #else +using fmt_runtime_string = fmt::basic_runtime; + #endif + +// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the +// condition from basic_format_string here, in addition, fmt::basic_runtime is only +// convertible to basic_format_string but not basic_string_view +template +struct is_convertible_to_basic_format_string + : std::integral_constant>::value || + std::is_same, fmt_runtime_string>::value> { +}; + + #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +using wstring_view_t = fmt::basic_string_view; +using wmemory_buf_t = fmt::basic_memory_buffer; + +template +using wformat_string_t = fmt::wformat_string; + #endif + #define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x) +#endif + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + #ifndef _WIN32 + #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows + #endif // _WIN32 +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + +template +struct is_convertible_to_any_format_string + : std::integral_constant::value || + is_convertible_to_basic_format_string::value> {}; + #if defined(SPDLOG_NO_ATOMIC_LEVELS) using level_t = details::null_atomic_int; #else using level_t = std::atomic; #endif -using log_err_handler = std::function; - -//Log level enum -namespace level -{ -enum level_enum -{ - trace = 0, - debug = 1, - info = 2, - warn = 3, - err = 4, - critical = 5, - off = 6 +#define SPDLOG_LEVEL_TRACE 0 +#define SPDLOG_LEVEL_DEBUG 1 +#define SPDLOG_LEVEL_INFO 2 +#define SPDLOG_LEVEL_WARN 3 +#define SPDLOG_LEVEL_ERROR 4 +#define SPDLOG_LEVEL_CRITICAL 5 +#define SPDLOG_LEVEL_OFF 6 + +#if !defined(SPDLOG_ACTIVE_LEVEL) + #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +#endif + +// Log level enum +namespace level { +enum level_enum : int { + trace = SPDLOG_LEVEL_TRACE, + debug = SPDLOG_LEVEL_DEBUG, + info = SPDLOG_LEVEL_INFO, + warn = SPDLOG_LEVEL_WARN, + err = SPDLOG_LEVEL_ERROR, + critical = SPDLOG_LEVEL_CRITICAL, + off = SPDLOG_LEVEL_OFF, + n_levels }; +#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5) +#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5) +#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4) +#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7) +#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5) +#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8) +#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3) + #if !defined(SPDLOG_LEVEL_NAMES) -#define SPDLOG_LEVEL_NAMES { "trace", "debug", "info", "warning", "error", "critical", "off" } + #define SPDLOG_LEVEL_NAMES \ + { \ + SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, \ + SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, SPDLOG_LEVEL_NAME_CRITICAL, \ + SPDLOG_LEVEL_NAME_OFF \ + } #endif -static const char* level_names[] SPDLOG_LEVEL_NAMES; -static const char* short_level_names[] { "T", "D", "I", "W", "E", "C", "O" }; +#if !defined(SPDLOG_SHORT_LEVEL_NAMES) -inline const char* to_str(spdlog::level::level_enum l) -{ - return level_names[l]; -} + #define SPDLOG_SHORT_LEVEL_NAMES \ + { "T", "D", "I", "W", "E", "C", "O" } +#endif -inline const char* to_short_str(spdlog::level::level_enum l) -{ - return short_level_names[l]; -} -using level_hasher = std::hash; +SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; +SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; -} //level +} // namespace level // -// Async overflow policy - block by default. +// Color mode used by sinks with color support. // -enum class async_overflow_policy -{ - block_retry, // Block / yield / sleep until message can be enqueued - discard_log_msg // Discard the message it enqueue fails -}; +enum class color_mode { always, automatic, never }; // // Pattern time - specific time getting to use for pattern_formatter. // local time by default // -enum class pattern_time_type -{ - local, // log localtime - utc // log utc +enum class pattern_time_type { + local, // log localtime + utc // log utc }; // // Log exception // -namespace details -{ -namespace os -{ -std::string errno_str(int err_num); -} -} -class spdlog_ex : public std::exception -{ +class SPDLOG_API spdlog_ex : public std::exception { public: - explicit spdlog_ex(std::string msg) : _msg(std::move(msg)) - {} + explicit spdlog_ex(std::string msg); + spdlog_ex(const std::string &msg, int last_errno); + const char *what() const SPDLOG_NOEXCEPT override; - spdlog_ex(const std::string& msg, int last_errno) - { - _msg = msg + ": " + details::os::errno_str(last_errno); - } +private: + std::string msg_; +}; - const char* what() const SPDLOG_NOEXCEPT override - { - return _msg.c_str(); - } +[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); +[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); -private: - std::string _msg; +struct source_loc { + SPDLOG_CONSTEXPR source_loc() = default; + SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) + : filename{filename_in}, + line{line_in}, + funcname{funcname_in} {} + + SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT { return line <= 0; } + const char *filename{nullptr}; + int line{0}; + const char *funcname{nullptr}; }; -// -// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) -// -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -using filename_t = std::wstring; +struct file_event_handlers { + file_event_handlers() + : before_open(nullptr), + after_open(nullptr), + before_close(nullptr), + after_close(nullptr) {} + + std::function before_open; + std::function after_open; + std::function before_close; + std::function after_close; +}; + +namespace details { + +// to_string_view + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(const memory_buf_t &buf) + SPDLOG_NOEXCEPT { + return spdlog::string_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::string_view_t to_string_view(spdlog::string_view_t str) + SPDLOG_NOEXCEPT { + return str; +} + +#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(const wmemory_buf_t &buf) + SPDLOG_NOEXCEPT { + return spdlog::wstring_view_t{buf.data(), buf.size()}; +} + +SPDLOG_CONSTEXPR_FUNC spdlog::wstring_view_t to_string_view(spdlog::wstring_view_t str) + SPDLOG_NOEXCEPT { + return str; +} +#endif + +#ifndef SPDLOG_USE_STD_FORMAT +template +inline fmt::basic_string_view to_string_view(fmt::basic_format_string fmt) { + return fmt; +} +#elif __cpp_lib_format >= 202207L +template +SPDLOG_CONSTEXPR_FUNC std::basic_string_view to_string_view( + std::basic_format_string fmt) SPDLOG_NOEXCEPT { + return fmt.get(); +} +#endif + +// make_unique support for pre c++14 +#if __cplusplus >= 201402L // C++14 and beyond +using std::enable_if_t; +using std::make_unique; #else -using filename_t = std::string; +template +using enable_if_t = typename std::enable_if::type; + +template +std::unique_ptr make_unique(Args &&...args) { + static_assert(!std::is_array::value, "arrays not supported"); + return std::unique_ptr(new T(std::forward(args)...)); +} #endif -} //spdlog +// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) +template ::value, int> = 0> +constexpr T conditional_static_cast(U value) { + return static_cast(value); +} + +template ::value, int> = 0> +constexpr T conditional_static_cast(U value) { + return value; +} + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "common-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/async_log_helper.h b/cpp_src/vendor/spdlog/details/async_log_helper.h deleted file mode 100644 index 2c57d068f..000000000 --- a/cpp_src/vendor/spdlog/details/async_log_helper.h +++ /dev/null @@ -1,326 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -// async log helper : -// Process logs asynchronously using a back thread. -// -// If the internal queue of log messages reaches its max size, -// then the client call will block until there is more room. -// - -#pragma once - -#include "../common.h" -#include "../details/log_msg.h" -#include "../details/mpmc_bounded_q.h" -#include "../details/os.h" -#include "../formatter.h" -#include "../sinks/sink.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spdlog { -namespace details { - -class async_log_helper { - // Async msg to move to/from the queue - // Movable only. should never be copied - enum class async_msg_type { log, flush, terminate }; - - struct async_msg { - std::string logger_name; - level::level_enum level; - log_clock::time_point time; - size_t thread_id; - std::string txt; - async_msg_type msg_type; - size_t msg_id; - - async_msg() = default; - ~async_msg() = default; - - explicit async_msg(async_msg_type m_type) : level(level::info), thread_id(0), msg_type(m_type), msg_id(0) {} - - async_msg(async_msg&& other) SPDLOG_NOEXCEPT : logger_name(std::move(other.logger_name)), - level(other.level), - time(other.time), - thread_id(other.thread_id), - txt(std::move(other.txt)), - msg_type(other.msg_type), - msg_id(other.msg_id) {} - - async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT { - logger_name = std::move(other.logger_name); - level = other.level; - time = other.time; - thread_id = other.thread_id; - txt = std::move(other.txt); - msg_type = other.msg_type; - msg_id = other.msg_id; - return *this; - } - - // never copy or assign. should only be moved.. - async_msg(const async_msg&) = delete; - async_msg& operator=(const async_msg& other) = delete; - - // construct from log_msg - explicit async_msg(const details::log_msg& m) - : level(m.level), - time(m.time), - thread_id(m.thread_id), - txt(m.raw.data(), m.raw.size()), - msg_type(async_msg_type::log), - msg_id(m.msg_id) { -#ifndef SPDLOG_NO_NAME - logger_name = *m.logger_name; -#endif - } - - // copy into log_msg - void fill_log_msg(log_msg& msg) { - msg.logger_name = &logger_name; - msg.level = level; - msg.time = time; - msg.thread_id = thread_id; - msg.raw << txt; - msg.msg_id = msg_id; - } - }; - -public: - using item_type = async_msg; - using q_type = details::mpmc_bounded_queue; - - using clock = reindexer::steady_clock_w; - - async_log_helper(formatter_ptr formatter, std::vector sinks, size_t queue_size, const log_err_handler err_handler, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - std::function worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), - std::function worker_teardown_cb = nullptr); - - void log(const details::log_msg& msg); - - // stop logging and join the back thread - ~async_log_helper(); - - async_log_helper(const async_log_helper&) = delete; - async_log_helper& operator=(const async_log_helper&) = delete; - - void set_formatter(formatter_ptr msg_formatter); - - void flush(bool wait_for_q); - - void set_error_handler(spdlog::log_err_handler err_handler); - -private: - formatter_ptr _formatter; - std::vector> _sinks; - - // queue of messages to log - q_type _q; - - log_err_handler _err_handler; - - bool _flush_requested; - - bool _terminate_requested; - - // overflow policy - const async_overflow_policy _overflow_policy; - - // worker thread warmup callback - one can set thread priority, affinity, etc - const std::function _worker_warmup_cb; - - // auto periodic sink flush parameter - const std::chrono::milliseconds _flush_interval_ms; - - // worker thread teardown callback - const std::function _worker_teardown_cb; - - // worker thread - std::thread _worker_thread; - - void push_msg(async_msg&& new_msg); - - // worker thread main loop - void worker_loop(); - - // pop next message from the queue and process it. will set the last_pop to the pop time - // return false if termination of the queue is required - bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush); - - void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush); - - // sleep,yield or return immediately using the time passed since last message as a hint - static void sleep_or_yield(const spdlog::log_clock::time_point& now, const log_clock::time_point& last_op_time); - - // wait until the queue is empty - void wait_empty_q(); -}; -} // namespace details -} // namespace spdlog - -/////////////////////////////////////////////////////////////////////////////// -// async_sink class implementation -/////////////////////////////////////////////////////////////////////////////// -inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, std::vector sinks, size_t queue_size, - log_err_handler err_handler, const async_overflow_policy overflow_policy, - std::function worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms, - std::function worker_teardown_cb) - : _formatter(std::move(formatter)), - _sinks(std::move(sinks)), - _q(queue_size), - _err_handler(std::move(err_handler)), - _flush_requested(false), - _terminate_requested(false), - _overflow_policy(overflow_policy), - _worker_warmup_cb(std::move(worker_warmup_cb)), - _flush_interval_ms(flush_interval_ms), - _worker_teardown_cb(std::move(worker_teardown_cb)) { - _worker_thread = std::thread(&async_log_helper::worker_loop, this); -} - -// Send to the worker thread termination message(level=off) -// and wait for it to finish gracefully -inline spdlog::details::async_log_helper::~async_log_helper() { - try { - push_msg(async_msg(async_msg_type::terminate)); - _worker_thread.join(); - } catch (...) // don't crash in destructor - { - } -} - -// Try to push and block until succeeded (if the policy is not to discard when the queue is full) -inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { push_msg(async_msg(msg)); } - -inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) { - if (!_q.enqueue(std::move(new_msg)) && - (_overflow_policy != async_overflow_policy::discard_log_msg || new_msg.msg_type != async_msg_type::log)) { - auto last_op_time = details::os::now(); - auto now = last_op_time; - do { - now = details::os::now(); - sleep_or_yield(now, last_op_time); - } while (!_q.enqueue(std::move(new_msg))); - } -} - -// optionally wait for the queue be empty and request flush from the sinks -inline void spdlog::details::async_log_helper::flush(bool wait_for_q) { - push_msg(async_msg(async_msg_type::flush)); - if (wait_for_q) wait_empty_q(); // return when queue is empty -} - -inline void spdlog::details::async_log_helper::worker_loop() { - if (_worker_warmup_cb) _worker_warmup_cb(); - auto last_pop = details::os::now(); - auto last_flush = last_pop; - auto active = true; - while (active) { - try { - active = process_next_msg(last_pop, last_flush); - } catch (const std::exception& ex) { - _err_handler(ex.what()); - } catch (...) { - _err_handler("Unknown exeption in async logger worker loop."); - } - } - if (_worker_teardown_cb) _worker_teardown_cb(); -} - -// process next message in the queue -// return true if this thread should still be active (while no terminate msg was received) -inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush) { - async_msg incoming_async_msg; - - if (_q.dequeue(incoming_async_msg)) { - last_pop = details::os::now(); - switch (incoming_async_msg.msg_type) { - case async_msg_type::flush: - _flush_requested = true; - break; - - case async_msg_type::terminate: - _flush_requested = true; - _terminate_requested = true; - break; - - case async_msg_type::log: - log_msg incoming_log_msg; - incoming_async_msg.fill_log_msg(incoming_log_msg); - _formatter->format(incoming_log_msg); - for (auto& s : _sinks) { - if (s->should_log(incoming_log_msg.level)) { - s->log(incoming_log_msg); - } - } - } - return true; - } - - // Handle empty queue.. - // This is the only place where the queue can terminate or flush to avoid losing messages already in the queue - auto now = details::os::now(); - handle_flush_interval(now, last_flush); - sleep_or_yield(now, last_pop); - return !_terminate_requested; -} - -// flush all sinks if _flush_interval_ms has expired -inline void spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush) { - auto should_flush = - _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && now - last_flush >= _flush_interval_ms); - if (should_flush) { - for (auto& s : _sinks) s->flush(); - now = last_flush = details::os::now(); - _flush_requested = false; - } -} - -inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { _formatter = std::move(msg_formatter); } - -// spin, yield or sleep. use the time passed since last message as a hint -inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_clock::time_point& now, - const spdlog::log_clock::time_point& last_op_time) { - using std::chrono::milliseconds; - using std::chrono::microseconds; - - auto time_since_op = now - last_op_time; - - // spin upto 50 micros - if (time_since_op <= microseconds(50)) return; - - // yield upto 150 micros - if (time_since_op <= microseconds(100)) return std::this_thread::yield(); - - // sleep for 20 ms upto 200 ms - if (time_since_op <= milliseconds(200)) return details::os::sleep_for_millis(20); - - // sleep for 500 ms - return details::os::sleep_for_millis(500); -} - -// wait for the queue to be empty -inline void spdlog::details::async_log_helper::wait_empty_q() { - auto last_op = details::os::now(); - while (!_q.is_empty()) { - sleep_or_yield(details::os::now(), last_op); - } -} - -inline void spdlog::details::async_log_helper::set_error_handler(spdlog::log_err_handler err_handler) { - _err_handler = std::move(err_handler); -} diff --git a/cpp_src/vendor/spdlog/details/async_logger_impl.h b/cpp_src/vendor/spdlog/details/async_logger_impl.h deleted file mode 100644 index 72bd4f98c..000000000 --- a/cpp_src/vendor/spdlog/details/async_logger_impl.h +++ /dev/null @@ -1,107 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Async Logger implementation -// Use an async_sink (queue per logger) to perform the logging in a worker thread - -#include "../details/async_log_helper.h" -#include "../async_logger.h" - -#include -#include -#include -#include - -template -inline spdlog::async_logger::async_logger(const std::string& logger_name, - const It& begin, - const It& end, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms, - const std::function& worker_teardown_cb) : - logger(logger_name, begin, end), - _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, _err_handler, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)) -{ -} - -inline spdlog::async_logger::async_logger(const std::string& logger_name, - sinks_init_list sinks_list, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms, - const std::function& worker_teardown_cb) : - async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {} - -inline spdlog::async_logger::async_logger(const std::string& logger_name, - sink_ptr single_sink, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms, - const std::function& worker_teardown_cb) : - async_logger(logger_name, -{ - std::move(single_sink) -}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {} - - -inline void spdlog::async_logger::flush() -{ - _async_log_helper->flush(true); -} - -// Error handler -inline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_handler) -{ - _err_handler = err_handler; - _async_log_helper->set_error_handler(err_handler); - -} -inline spdlog::log_err_handler spdlog::async_logger::error_handler() -{ - return _err_handler; -} - - -inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) -{ - _formatter = msg_formatter; - _async_log_helper->set_formatter(_formatter); -} - -inline void spdlog::async_logger::_set_pattern(const std::string& pattern, pattern_time_type pattern_time) -{ - _formatter = std::make_shared(pattern, pattern_time); - _async_log_helper->set_formatter(_formatter); -} - - -inline void spdlog::async_logger::_sink_it(details::log_msg& msg) -{ - try - { -#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) - _incr_msg_counter(msg); -#endif - _async_log_helper->log(msg); - if (_should_flush_on(msg)) - _async_log_helper->flush(false); // do async flush - } - catch (const std::exception &ex) - { - _err_handler(ex.what()); - } - catch(...) - { - _err_handler("Unknown exception in logger " + _name); - throw; - } - -} diff --git a/cpp_src/vendor/spdlog/details/backtracer-inl.h b/cpp_src/vendor/spdlog/details/backtracer-inl.h new file mode 100644 index 000000000..43d100247 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/backtracer-inl.h @@ -0,0 +1,63 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif +namespace spdlog { +namespace details { +SPDLOG_INLINE backtracer::backtracer(const backtracer &other) { + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = other.messages_; +} + +SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT { + std::lock_guard lock(other.mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); +} + +SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) { + std::lock_guard lock(mutex_); + enabled_ = other.enabled(); + messages_ = std::move(other.messages_); + return *this; +} + +SPDLOG_INLINE void backtracer::enable(size_t size) { + std::lock_guard lock{mutex_}; + enabled_.store(true, std::memory_order_relaxed); + messages_ = circular_q{size}; +} + +SPDLOG_INLINE void backtracer::disable() { + std::lock_guard lock{mutex_}; + enabled_.store(false, std::memory_order_relaxed); +} + +SPDLOG_INLINE bool backtracer::enabled() const { return enabled_.load(std::memory_order_relaxed); } + +SPDLOG_INLINE void backtracer::push_back(const log_msg &msg) { + std::lock_guard lock{mutex_}; + messages_.push_back(log_msg_buffer{msg}); +} + +SPDLOG_INLINE bool backtracer::empty() const { + std::lock_guard lock{mutex_}; + return messages_.empty(); +} + +// pop all items in the q and apply the given fun on each of them. +SPDLOG_INLINE void backtracer::foreach_pop(std::function fun) { + std::lock_guard lock{mutex_}; + while (!messages_.empty()) { + auto &front_msg = messages_.front(); + fun(front_msg); + messages_.pop_front(); + } +} +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/backtracer.h b/cpp_src/vendor/spdlog/details/backtracer.h new file mode 100644 index 000000000..541339cdc --- /dev/null +++ b/cpp_src/vendor/spdlog/details/backtracer.h @@ -0,0 +1,45 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +#include +#include +#include + +// Store log messages in circular buffer. +// Useful for storing debug data in case of error/warning happens. + +namespace spdlog { +namespace details { +class SPDLOG_API backtracer { + mutable std::mutex mutex_; + std::atomic enabled_{false}; + circular_q messages_; + +public: + backtracer() = default; + backtracer(const backtracer &other); + + backtracer(backtracer &&other) SPDLOG_NOEXCEPT; + backtracer &operator=(backtracer other); + + void enable(size_t size); + void disable(); + bool enabled() const; + void push_back(const log_msg &msg); + bool empty() const; + + // pop all items in the q and apply the given fun on each of them. + void foreach_pop(std::function fun); +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "backtracer-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/circular_q.h b/cpp_src/vendor/spdlog/details/circular_q.h new file mode 100644 index 000000000..29e9d255f --- /dev/null +++ b/cpp_src/vendor/spdlog/details/circular_q.h @@ -0,0 +1,115 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// circular q view of std::vector. +#pragma once + +#include +#include + +#include "spdlog/common.h" + +namespace spdlog { +namespace details { +template +class circular_q { + size_t max_items_ = 0; + typename std::vector::size_type head_ = 0; + typename std::vector::size_type tail_ = 0; + size_t overrun_counter_ = 0; + std::vector v_; + +public: + using value_type = T; + + // empty ctor - create a disabled queue with no elements allocated at all + circular_q() = default; + + explicit circular_q(size_t max_items) + : max_items_(max_items + 1) // one item is reserved as marker for full q + , + v_(max_items_) {} + + circular_q(const circular_q &) = default; + circular_q &operator=(const circular_q &) = default; + + // move cannot be default, + // since we need to reset head_, tail_, etc to zero in the moved object + circular_q(circular_q &&other) SPDLOG_NOEXCEPT { copy_moveable(std::move(other)); } + + circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT { + copy_moveable(std::move(other)); + return *this; + } + + // push back, overrun (oldest) item if no room left + void push_back(T &&item) { + if (max_items_ > 0) { + v_[tail_] = std::move(item); + tail_ = (tail_ + 1) % max_items_; + + if (tail_ == head_) // overrun last item if full + { + head_ = (head_ + 1) % max_items_; + ++overrun_counter_; + } + } + } + + // Return reference to the front item. + // If there are no elements in the container, the behavior is undefined. + const T &front() const { return v_[head_]; } + + T &front() { return v_[head_]; } + + // Return number of elements actually stored + size_t size() const { + if (tail_ >= head_) { + return tail_ - head_; + } else { + return max_items_ - (head_ - tail_); + } + } + + // Return const reference to item by index. + // If index is out of range 0…size()-1, the behavior is undefined. + const T &at(size_t i) const { + assert(i < size()); + return v_[(head_ + i) % max_items_]; + } + + // Pop item from front. + // If there are no elements in the container, the behavior is undefined. + void pop_front() { head_ = (head_ + 1) % max_items_; } + + bool empty() const { return tail_ == head_; } + + bool full() const { + // head is ahead of the tail by 1 + if (max_items_ > 0) { + return ((tail_ + 1) % max_items_) == head_; + } + return false; + } + + size_t overrun_counter() const { return overrun_counter_; } + + void reset_overrun_counter() { overrun_counter_ = 0; } + +private: + // copy from other&& and reset it to disabled state + void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT { + max_items_ = other.max_items_; + head_ = other.head_; + tail_ = other.tail_; + overrun_counter_ = other.overrun_counter_; + v_ = std::move(other.v_); + + // put &&other in disabled, but valid state + other.max_items_ = 0; + other.head_ = other.tail_ = 0; + other.overrun_counter_ = 0; + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/console_globals.h b/cpp_src/vendor/spdlog/details/console_globals.h new file mode 100644 index 000000000..9c552106a --- /dev/null +++ b/cpp_src/vendor/spdlog/details/console_globals.h @@ -0,0 +1,28 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +namespace spdlog { +namespace details { + +struct console_mutex { + using mutex_t = std::mutex; + static mutex_t &mutex() { + static mutex_t s_mutex; + return s_mutex; + } +}; + +struct console_nullmutex { + using mutex_t = null_mutex; + static mutex_t &mutex() { + static mutex_t s_mutex; + return s_mutex; + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/file_helper-inl.h b/cpp_src/vendor/spdlog/details/file_helper-inl.h new file mode 100644 index 000000000..37d1d46fd --- /dev/null +++ b/cpp_src/vendor/spdlog/details/file_helper-inl.h @@ -0,0 +1,152 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE file_helper::file_helper(const file_event_handlers &event_handlers) + : event_handlers_(event_handlers) {} + +SPDLOG_INLINE file_helper::~file_helper() { close(); } + +SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) { + close(); + filename_ = fname; + + auto *mode = SPDLOG_FILENAME_T("ab"); + auto *trunc_mode = SPDLOG_FILENAME_T("wb"); + + if (event_handlers_.before_open) { + event_handlers_.before_open(filename_); + } + for (int tries = 0; tries < open_tries_; ++tries) { + // create containing folder if not exists already. + os::create_dir(os::dir_name(fname)); + if (truncate) { + // Truncate by opening-and-closing a tmp file in "wb" mode, always + // opening the actual log-we-write-to in "ab" mode, since that + // interacts more politely with eternal processes that might + // rotate/truncate the file underneath us. + std::FILE *tmp; + if (os::fopen_s(&tmp, fname, trunc_mode)) { + continue; + } + std::fclose(tmp); + } + if (!os::fopen_s(&fd_, fname, mode)) { + if (event_handlers_.after_open) { + event_handlers_.after_open(filename_, fd_); + } + return; + } + + details::os::sleep_for_millis(open_interval_); + } + + throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", + errno); +} + +SPDLOG_INLINE void file_helper::reopen(bool truncate) { + if (filename_.empty()) { + throw_spdlog_ex("Failed re opening file - was not opened before"); + } + this->open(filename_, truncate); +} + +SPDLOG_INLINE void file_helper::flush() { + if (std::fflush(fd_) != 0) { + throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE void file_helper::sync() { + if (!os::fsync(fd_)) { + throw_spdlog_ex("Failed to fsync file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE void file_helper::close() { + if (fd_ != nullptr) { + if (event_handlers_.before_close) { + event_handlers_.before_close(filename_, fd_); + } + + std::fclose(fd_); + fd_ = nullptr; + + if (event_handlers_.after_close) { + event_handlers_.after_close(filename_); + } + } +} + +SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) { + if (fd_ == nullptr) return; + size_t msg_size = buf.size(); + auto data = buf.data(); + if (std::fwrite(data, 1, msg_size, fd_) != msg_size) { + throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); + } +} + +SPDLOG_INLINE size_t file_helper::size() const { + if (fd_ == nullptr) { + throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)); + } + return os::filesize(fd_); +} + +SPDLOG_INLINE const filename_t &file_helper::filename() const { return filename_; } + +// +// return file path and its extension: +// +// "mylog.txt" => ("mylog", ".txt") +// "mylog" => ("mylog", "") +// "mylog." => ("mylog.", "") +// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") +// +// the starting dot in filenames is ignored (hidden files): +// +// ".mylog" => (".mylog". "") +// "my_folder/.mylog" => ("my_folder/.mylog", "") +// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") +SPDLOG_INLINE std::tuple file_helper::split_by_extension( + const filename_t &fname) { + auto ext_index = fname.rfind('.'); + + // no valid extension found - return whole path and empty string as + // extension + if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) { + return std::make_tuple(fname, filename_t()); + } + + // treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" + auto folder_index = fname.find_last_of(details::os::folder_seps_filename); + if (folder_index != filename_t::npos && folder_index >= ext_index - 1) { + return std::make_tuple(fname, filename_t()); + } + + // finally - return a valid base and extension tuple + return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); +} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/file_helper.h b/cpp_src/vendor/spdlog/details/file_helper.h index d7ccf59ba..f0e5d180e 100644 --- a/cpp_src/vendor/spdlog/details/file_helper.h +++ b/cpp_src/vendor/spdlog/details/file_helper.h @@ -1,111 +1,35 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -// Helper class for file sink -// When failing to open a file, retry several times(5) with small delay between the tries(10 ms) -// Throw spdlog_ex exception on errors - -#include "../details/os.h" -#include "../details/log_msg.h" - -#include -#include -#include -#include +#include #include -#include -namespace spdlog -{ -namespace details -{ +namespace spdlog { +namespace details { -class file_helper -{ +// Helper class for file sinks. +// When failing to open a file, retry several times(5) with a delay interval(10 ms). +// Throw spdlog_ex exception on errors. +class SPDLOG_API file_helper { public: - const int open_tries = 5; - const int open_interval = 10; - - explicit file_helper() = default; - - file_helper(const file_helper&) = delete; - file_helper& operator=(const file_helper&) = delete; - - ~file_helper() - { - close(); - } - - - void open(const filename_t& fname, bool truncate = false) - { - close(); - auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); - _filename = fname; - for (int tries = 0; tries < open_tries; ++tries) - { - if (!os::fopen_s(&_fd, fname, mode)) - return; - - details::os::sleep_for_millis(open_interval); - } - - throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno); - } - - void reopen(bool truncate) - { - if (_filename.empty()) - throw spdlog_ex("Failed re opening file - was not opened before"); - open(_filename, truncate); - - } - - void flush() - { - std::fflush(_fd); - } - - void close() - { - if (_fd != nullptr) - { - std::fclose(_fd); - _fd = nullptr; - } - } - - void write(const log_msg& msg) - { - size_t msg_size = msg.formatted.size(); - auto data = msg.formatted.data(); - if (std::fwrite(data, 1, msg_size, _fd) != msg_size) - throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); - } - - size_t size() const - { - if (_fd == nullptr) - { - throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)); - } - return os::filesize(_fd); - } - - const filename_t& filename() const - { - return _filename; - } - - static bool file_exists(const filename_t& fname) - { - return os::file_exists(fname); - } + file_helper() = default; + explicit file_helper(const file_event_handlers &event_handlers); + + file_helper(const file_helper &) = delete; + file_helper &operator=(const file_helper &) = delete; + ~file_helper(); + + void open(const filename_t &fname, bool truncate = false); + void reopen(bool truncate); + void flush(); + void sync(); + void close(); + void write(const memory_buf_t &buf); + size_t size() const; + const filename_t &filename() const; // // return file path and its extension: @@ -120,26 +44,18 @@ class file_helper // ".mylog" => (".mylog". "") // "my_folder/.mylog" => ("my_folder/.mylog", "") // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") - static std::tuple split_by_extenstion(const spdlog::filename_t& fname) - { - auto ext_index = fname.rfind('.'); - - // no valid extension found - return whole path and empty string as extension - if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) - return std::make_tuple(fname, spdlog::filename_t()); - - // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" - auto folder_index = fname.rfind(details::os::folder_sep); - if (folder_index != fname.npos && folder_index >= ext_index - 1) - return std::make_tuple(fname, spdlog::filename_t()); - - // finally - return a valid base and extension tuple - return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); - } + static std::tuple split_by_extension(const filename_t &fname); private: - FILE* _fd{ nullptr }; - filename_t _filename; + const int open_tries_ = 5; + const unsigned int open_interval_ = 10; + std::FILE *fd_{nullptr}; + filename_t filename_; + file_event_handlers event_handlers_; }; -} -} +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "file_helper-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/fmt_helper.h b/cpp_src/vendor/spdlog/details/fmt_helper.h new file mode 100644 index 000000000..61306003b --- /dev/null +++ b/cpp_src/vendor/spdlog/details/fmt_helper.h @@ -0,0 +1,141 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +#pragma once + +#include +#include +#include +#include +#include + +#ifdef SPDLOG_USE_STD_FORMAT + #include + #include +#endif + +// Some fmt helpers to efficiently format and pad ints and strings +namespace spdlog { +namespace details { +namespace fmt_helper { + +inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) { + auto *buf_ptr = view.data(); + dest.append(buf_ptr, buf_ptr + view.size()); +} + +#ifdef SPDLOG_USE_STD_FORMAT +template +inline void append_int(T n, memory_buf_t &dest) { + // Buffer should be large enough to hold all digits (digits10 + 1) and a sign + SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits::digits10 + 2; + char buf[BUF_SIZE]; + + auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); + if (ec == std::errc()) { + dest.append(buf, ptr); + } else { + throw_spdlog_ex("Failed to format int", static_cast(ec)); + } +} +#else +template +inline void append_int(T n, memory_buf_t &dest) { + fmt::format_int i(n); + dest.append(i.data(), i.data() + i.size()); +} +#endif + +template +SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) { + // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912 + unsigned int count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} + +template +inline unsigned int count_digits(T n) { + using count_type = + typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; +#ifdef SPDLOG_USE_STD_FORMAT + return count_digits_fallback(static_cast(n)); +#else + return static_cast(fmt:: + // fmt 7.0.0 renamed the internal namespace to detail. + // See: https://github.com/fmtlib/fmt/issues/1538 + #if FMT_VERSION < 70000 + internal + #else + detail + #endif + ::count_digits(static_cast(n))); +#endif +} + +inline void pad2(int n, memory_buf_t &dest) { + if (n >= 0 && n < 100) // 0-99 + { + dest.push_back(static_cast('0' + n / 10)); + dest.push_back(static_cast('0' + n % 10)); + } else // unlikely, but just in case, let fmt deal with it + { + fmt_lib::format_to(std::back_inserter(dest), SPDLOG_FMT_STRING("{:02}"), n); + } +} + +template +inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) { + static_assert(std::is_unsigned::value, "pad_uint must get unsigned T"); + for (auto digits = count_digits(n); digits < width; digits++) { + dest.push_back('0'); + } + append_int(n, dest); +} + +template +inline void pad3(T n, memory_buf_t &dest) { + static_assert(std::is_unsigned::value, "pad3 must get unsigned T"); + if (n < 1000) { + dest.push_back(static_cast(n / 100 + '0')); + n = n % 100; + dest.push_back(static_cast((n / 10) + '0')); + dest.push_back(static_cast((n % 10) + '0')); + } else { + append_int(n, dest); + } +} + +template +inline void pad6(T n, memory_buf_t &dest) { + pad_uint(n, 6, dest); +} + +template +inline void pad9(T n, memory_buf_t &dest) { + pad_uint(n, 9, dest); +} + +// return fraction of a second of the given time_point. +// e.g. +// fraction(tp) -> will return the millis part of the second +template +inline ToDuration time_fraction(log_clock::time_point tp) { + using std::chrono::duration_cast; + using std::chrono::seconds; + auto duration = tp.time_since_epoch(); + auto secs = duration_cast(duration); + return duration_cast(duration) - duration_cast(secs); +} + +} // namespace fmt_helper +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/log_msg-inl.h b/cpp_src/vendor/spdlog/details/log_msg-inl.h new file mode 100644 index 000000000..aa3a95768 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/log_msg-inl.h @@ -0,0 +1,44 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, + spdlog::source_loc loc, + string_view_t a_logger_name, + spdlog::level::level_enum lvl, + spdlog::string_view_t msg) + : logger_name(a_logger_name), + level(lvl), + time(log_time) +#ifndef SPDLOG_NO_THREAD_ID + , + thread_id(os::thread_id()) +#endif + , + source(loc), + payload(msg) { +} + +SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, + string_view_t a_logger_name, + spdlog::level::level_enum lvl, + spdlog::string_view_t msg) + : log_msg(os::now(), loc, a_logger_name, lvl, msg) {} + +SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, + spdlog::level::level_enum lvl, + spdlog::string_view_t msg) + : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) {} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/log_msg.h b/cpp_src/vendor/spdlog/details/log_msg.h index 8b441cab6..87df1e833 100644 --- a/cpp_src/vendor/spdlog/details/log_msg.h +++ b/cpp_src/vendor/spdlog/details/log_msg.h @@ -1,48 +1,40 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../common.h" -#include "../details/os.h" - +#include #include -#include -namespace spdlog -{ -namespace details -{ -struct log_msg -{ +namespace spdlog { +namespace details { +struct SPDLOG_API log_msg { log_msg() = default; - log_msg(const std::string *loggers_name, level::level_enum lvl) : - logger_name(loggers_name), - level(lvl) - { -#ifndef SPDLOG_NO_DATETIME - time = os::now(); -#endif - -#ifndef SPDLOG_NO_THREAD_ID - thread_id = os::thread_id(); -#endif - } - - log_msg(const log_msg& other) = delete; - log_msg& operator=(log_msg&& other) = delete; - log_msg(log_msg&& other) = delete; + log_msg(log_clock::time_point log_time, + source_loc loc, + string_view_t logger_name, + level::level_enum lvl, + string_view_t msg); + log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); + log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); + log_msg(const log_msg &other) = default; + log_msg &operator=(const log_msg &other) = default; + + string_view_t logger_name; + level::level_enum level{level::off}; + log_clock::time_point time; + size_t thread_id{0}; + // wrapping the formatted text with color (updated by pattern_formatter). + mutable size_t color_range_start{0}; + mutable size_t color_range_end{0}; - const std::string *logger_name{ nullptr }; - level::level_enum level; - log_clock::time_point time; - size_t thread_id; - fmt::MemoryWriter raw; - fmt::MemoryWriter formatted; - size_t msg_id{ 0 }; + source_loc source; + string_view_t payload; }; -} -} +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "log_msg-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/log_msg_buffer-inl.h b/cpp_src/vendor/spdlog/details/log_msg_buffer-inl.h new file mode 100644 index 000000000..2eb242859 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/log_msg_buffer-inl.h @@ -0,0 +1,54 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +namespace spdlog { +namespace details { + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) + : log_msg{orig_msg} { + buffer.append(logger_name.begin(), logger_name.end()); + buffer.append(payload.begin(), payload.end()); + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) + : log_msg{other} { + buffer.append(logger_name.begin(), logger_name.end()); + buffer.append(payload.begin(), payload.end()); + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT + : log_msg{other}, + buffer{std::move(other.buffer)} { + update_string_views(); +} + +SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) { + log_msg::operator=(other); + buffer.clear(); + buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); + update_string_views(); + return *this; +} + +SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT { + log_msg::operator=(other); + buffer = std::move(other.buffer); + update_string_views(); + return *this; +} + +SPDLOG_INLINE void log_msg_buffer::update_string_views() { + logger_name = string_view_t{buffer.data(), logger_name.size()}; + payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; +} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/log_msg_buffer.h b/cpp_src/vendor/spdlog/details/log_msg_buffer.h new file mode 100644 index 000000000..1143b3ba4 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/log_msg_buffer.h @@ -0,0 +1,32 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include + +namespace spdlog { +namespace details { + +// Extend log_msg with internal buffer to store its payload. +// This is needed since log_msg holds string_views that points to stack data. + +class SPDLOG_API log_msg_buffer : public log_msg { + memory_buf_t buffer; + void update_string_views(); + +public: + log_msg_buffer() = default; + explicit log_msg_buffer(const log_msg &orig_msg); + log_msg_buffer(const log_msg_buffer &other); + log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT; + log_msg_buffer &operator=(const log_msg_buffer &other); + log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "log_msg_buffer-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/logger_impl.h b/cpp_src/vendor/spdlog/details/logger_impl.h deleted file mode 100644 index 11cbc7e46..000000000 --- a/cpp_src/vendor/spdlog/details/logger_impl.h +++ /dev/null @@ -1,373 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include "../logger.h" -#include "../sinks/stdout_sinks.h" - -#include -#include - -// create logger with given name, sinks and the default pattern formatter -// all other ctors will call this one -template -inline spdlog::logger::logger(std::string logger_name, const It& begin, const It& end): - _name(std::move(logger_name)), - _sinks(begin, end), - _formatter(std::make_shared("%+")), - _level(level::info), - _flush_level(level::off), - _last_err_time(0), - _msg_counter(1) // message counter will start from 1. 0-message id will be reserved for controll messages -{ - _err_handler = [this](const std::string &msg) - { - this->_default_err_handler(msg); - }; -} - -// ctor with sinks as init list -inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list): - logger(logger_name, sinks_list.begin(), sinks_list.end()) -{} - - -// ctor with single sink -inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink): - logger(logger_name, -{ - std::move(single_sink) -}) -{} - - -inline spdlog::logger::~logger() = default; - - -inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter) -{ - _set_formatter(std::move(msg_formatter)); -} - -inline void spdlog::logger::set_pattern(const std::string& pattern, pattern_time_type pattern_time) -{ - _set_pattern(pattern, pattern_time); -} - -template -inline void spdlog::logger::log(level::level_enum lvl, const char* fmt, const Args&... args) -{ - if (!should_log(lvl)) return; - - try - { - details::log_msg log_msg(&_name, lvl); - -#if defined(SPDLOG_FMT_PRINTF) - fmt::printf(log_msg.raw, fmt, args...); -#else - log_msg.raw.write(fmt, args...); -#endif - _sink_it(log_msg); - } - catch (const std::exception &ex) - { - _err_handler(ex.what()); - } - catch(...) - { - _err_handler("Unknown exception in logger " + _name); - throw; - } -} - -template -inline void spdlog::logger::log(level::level_enum lvl, const char* msg) -{ - if (!should_log(lvl)) return; - try - { - details::log_msg log_msg(&_name, lvl); - log_msg.raw << msg; - _sink_it(log_msg); - } - catch (const std::exception &ex) - { - _err_handler(ex.what()); - } - catch (...) - { - _err_handler("Unknown exception in logger " + _name); - throw; - } -} - -template -inline void spdlog::logger::log(level::level_enum lvl, const T& msg) -{ - if (!should_log(lvl)) return; - try - { - details::log_msg log_msg(&_name, lvl); - log_msg.raw << msg; - _sink_it(log_msg); - } - catch (const std::exception &ex) - { - _err_handler(ex.what()); - } - catch (...) - { - _err_handler("Unknown exception in logger " + _name); - throw; - } -} - - -template -inline void spdlog::logger::trace(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::trace, fmt, arg1, args...); -} - -template -inline void spdlog::logger::debug(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::debug, fmt, arg1, args...); -} - -template -inline void spdlog::logger::info(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::info, fmt, arg1, args...); -} - -template -inline void spdlog::logger::warn(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::warn, fmt, arg1, args...); -} - -template -inline void spdlog::logger::error(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::err, fmt, arg1, args...); -} - -template -inline void spdlog::logger::critical(const char* fmt, const Arg1 &arg1, const Args&... args) -{ - log(level::critical, fmt, arg1, args...); -} - - -template -inline void spdlog::logger::trace(const T& msg) -{ - log(level::trace, msg); -} - -template -inline void spdlog::logger::debug(const T& msg) -{ - log(level::debug, msg); -} - - -template -inline void spdlog::logger::info(const T& msg) -{ - log(level::info, msg); -} - - -template -inline void spdlog::logger::warn(const T& msg) -{ - log(level::warn, msg); -} - -template -inline void spdlog::logger::error(const T& msg) -{ - log(level::err, msg); -} - -template -inline void spdlog::logger::critical(const T& msg) -{ - log(level::critical, msg); -} - - - -#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT -#include -#include - -template -inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* msg) -{ - std::wstring_convert > conv; - - log(lvl, conv.to_bytes(msg)); -} - -template -inline void spdlog::logger::log(level::level_enum lvl, const wchar_t* fmt, const Args&... args) -{ - fmt::WMemoryWriter wWriter; - - wWriter.write(fmt, args...); - log(lvl, wWriter.c_str()); -} - -template -inline void spdlog::logger::trace(const wchar_t* fmt, const Args&... args) -{ - log(level::trace, fmt, args...); -} - -template -inline void spdlog::logger::debug(const wchar_t* fmt, const Args&... args) -{ - log(level::debug, fmt, args...); -} - -template -inline void spdlog::logger::info(const wchar_t* fmt, const Args&... args) -{ - log(level::info, fmt, args...); -} - - -template -inline void spdlog::logger::warn(const wchar_t* fmt, const Args&... args) -{ - log(level::warn, fmt, args...); -} - -template -inline void spdlog::logger::error(const wchar_t* fmt, const Args&... args) -{ - log(level::err, fmt, args...); -} - -template -inline void spdlog::logger::critical(const wchar_t* fmt, const Args&... args) -{ - log(level::critical, fmt, args...); -} - -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - - - -// -// name and level -// -inline const std::string& spdlog::logger::name() const -{ - return _name; -} - -inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) -{ - _level.store(log_level); -} - -inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) -{ - _err_handler = std::move(err_handler); -} - -inline spdlog::log_err_handler spdlog::logger::error_handler() -{ - return _err_handler; -} - -inline void spdlog::logger::flush_on(level::level_enum log_level) -{ - _flush_level.store(log_level); -} - -inline spdlog::level::level_enum spdlog::logger::level() const -{ - return static_cast(_level.load(std::memory_order_relaxed)); -} - -inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const -{ - return msg_level >= _level.load(std::memory_order_relaxed); -} - -// -// protected virtual called at end of each user log call (if enabled) by the line_logger -// -inline void spdlog::logger::_sink_it(details::log_msg& msg) -{ -#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) - _incr_msg_counter(msg); -#endif - _formatter->format(msg); - for (auto &sink : _sinks) - { - if( sink->should_log( msg.level)) - { - sink->log(msg); - } - } - - if(_should_flush_on(msg)) - flush(); -} - -inline void spdlog::logger::_set_pattern(const std::string& pattern, pattern_time_type pattern_time) -{ - _formatter = std::make_shared(pattern, pattern_time); -} - -inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter) -{ - _formatter = std::move(msg_formatter); -} - -inline void spdlog::logger::flush() -{ - for (auto& sink : _sinks) - sink->flush(); -} - -inline void spdlog::logger::_default_err_handler(const std::string &msg) -{ - auto now = time(nullptr); - if (now - _last_err_time < 60) - return; - auto tm_time = details::os::localtime(now); - char date_buf[100]; - std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); - details::log_msg err_msg; - err_msg.formatted.write("[*** LOG ERROR ***] [{}] [{}] [{}]{}", name(), msg, date_buf, details::os::default_eol); - sinks::stderr_sink_mt::instance()->log(err_msg); - _last_err_time = now; -} - -inline bool spdlog::logger::_should_flush_on(const details::log_msg &msg) -{ - const auto flush_level = _flush_level.load(std::memory_order_relaxed); - return (msg.level >= flush_level) && (msg.level != level::off); -} - -inline void spdlog::logger::_incr_msg_counter(details::log_msg &msg) -{ - msg.msg_id = _msg_counter.fetch_add(1, std::memory_order_relaxed); -} - -inline const std::vector& spdlog::logger::sinks() const -{ - return _sinks; -} - diff --git a/cpp_src/vendor/spdlog/details/mpmc_blocking_q.h b/cpp_src/vendor/spdlog/details/mpmc_blocking_q.h new file mode 100644 index 000000000..5a474bf33 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/mpmc_blocking_q.h @@ -0,0 +1,177 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// multi producer-multi consumer blocking queue. +// enqueue(..) - will block until room found to put the new message. +// enqueue_nowait(..) - will return immediately with false if no room left in +// the queue. +// dequeue_for(..) - will block until the queue is not empty or timeout have +// passed. + +#include + +#include +#include +#include + +namespace spdlog { +namespace details { + +template +class mpmc_blocking_queue { +public: + using item_type = T; + explicit mpmc_blocking_queue(size_t max_items) + : q_(max_items) {} + +#ifndef __MINGW32__ + // try to enqueue and block if no room left + void enqueue(T &&item) { + { + std::unique_lock lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) { + { + std::unique_lock lock(queue_mutex_); + q_.push_back(std::move(item)); + } + push_cv_.notify_one(); + } + + void enqueue_if_have_room(T &&item) { + bool pushed = false; + { + std::unique_lock lock(queue_mutex_); + if (!q_.full()) { + q_.push_back(std::move(item)); + pushed = true; + } + } + + if (pushed) { + push_cv_.notify_one(); + } else { + ++discard_counter_; + } + } + + // dequeue with a timeout. + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { + { + std::unique_lock lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) { + return false; + } + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + return true; + } + + // blocking dequeue without a timeout. + void dequeue(T &popped_item) { + { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + } + pop_cv_.notify_one(); + } + +#else + // apparently mingw deadlocks if the mutex is released before cv.notify_one(), + // so release the mutex at the very end each function. + + // try to enqueue and block if no room left + void enqueue(T &&item) { + std::unique_lock lock(queue_mutex_); + pop_cv_.wait(lock, [this] { return !this->q_.full(); }); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + // enqueue immediately. overrun oldest message in the queue if no room left. + void enqueue_nowait(T &&item) { + std::unique_lock lock(queue_mutex_); + q_.push_back(std::move(item)); + push_cv_.notify_one(); + } + + void enqueue_if_have_room(T &&item) { + bool pushed = false; + std::unique_lock lock(queue_mutex_); + if (!q_.full()) { + q_.push_back(std::move(item)); + pushed = true; + } + + if (pushed) { + push_cv_.notify_one(); + } else { + ++discard_counter_; + } + } + + // dequeue with a timeout. + // Return true, if succeeded dequeue item, false otherwise + bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) { + std::unique_lock lock(queue_mutex_); + if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) { + return false; + } + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + return true; + } + + // blocking dequeue without a timeout. + void dequeue(T &popped_item) { + std::unique_lock lock(queue_mutex_); + push_cv_.wait(lock, [this] { return !this->q_.empty(); }); + popped_item = std::move(q_.front()); + q_.pop_front(); + pop_cv_.notify_one(); + } + +#endif + + size_t overrun_counter() { + std::unique_lock lock(queue_mutex_); + return q_.overrun_counter(); + } + + size_t discard_counter() { return discard_counter_.load(std::memory_order_relaxed); } + + size_t size() { + std::unique_lock lock(queue_mutex_); + return q_.size(); + } + + void reset_overrun_counter() { + std::unique_lock lock(queue_mutex_); + q_.reset_overrun_counter(); + } + + void reset_discard_counter() { discard_counter_.store(0, std::memory_order_relaxed); } + +private: + std::mutex queue_mutex_; + std::condition_variable push_cv_; + std::condition_variable pop_cv_; + spdlog::details::circular_q q_; + std::atomic discard_counter_{0}; +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/mpmc_bounded_q.h b/cpp_src/vendor/spdlog/details/mpmc_bounded_q.h deleted file mode 100644 index 6187f3b95..000000000 --- a/cpp_src/vendor/spdlog/details/mpmc_bounded_q.h +++ /dev/null @@ -1,175 +0,0 @@ -/* -A modified version of Bounded MPMC queue by Dmitry Vyukov. - -Original code from: -http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue - -licensed by Dmitry Vyukov under the terms below: - -Simplified BSD license - -Copyright (c) 2010-2011 Dmitry Vyukov. 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 DMITRY VYUKOV "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 DMITRY VYUKOV 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. - -The views and conclusions contained in the software and documentation are those of the authors and -should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. -*/ - -/* -The code in its current form adds the license below: - -Copyright(c) 2015 Gabi Melman. -Distributed under the MIT License (http://opensource.org/licenses/MIT) - -*/ - -#pragma once - -#include "../common.h" - -#include -#include - -namespace spdlog -{ -namespace details -{ - -template -class mpmc_bounded_queue -{ -public: - using item_type = T; - - explicit mpmc_bounded_queue(size_t buffer_size) - :max_size_(buffer_size), - buffer_(new cell_t[buffer_size]), - buffer_mask_(buffer_size - 1) - { - //queue size must be power of two - if (!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) - throw spdlog_ex("async logger queue size must be power of two"); - - for (size_t i = 0; i != buffer_size; i += 1) - buffer_[i].sequence_.store(i, std::memory_order_relaxed); - enqueue_pos_.store(0, std::memory_order_relaxed); - dequeue_pos_.store(0, std::memory_order_relaxed); - } - - ~mpmc_bounded_queue() - { - delete[] buffer_; - } - - mpmc_bounded_queue(mpmc_bounded_queue const&) = delete; - void operator=(mpmc_bounded_queue const&) = delete; - - bool enqueue(T&& data) - { - cell_t* cell; - size_t pos = enqueue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = static_cast(seq) - static_cast(pos); - if (dif == 0) - { - if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - { - return false; - } - else - { - pos = enqueue_pos_.load(std::memory_order_relaxed); - } - } - cell->data_ = std::move(data); - cell->sequence_.store(pos + 1, std::memory_order_release); - return true; - } - - bool dequeue(T& data) - { - cell_t* cell; - size_t pos = dequeue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = - cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = static_cast(seq) - static_cast(pos + 1); - if (dif == 0) - { - if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - return false; - else - pos = dequeue_pos_.load(std::memory_order_relaxed); - } - data = std::move(cell->data_); - cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); - return true; - } - - bool is_empty() - { - size_t front, front1, back; - // try to take a consistent snapshot of front/tail. - do - { - front = enqueue_pos_.load(std::memory_order_acquire); - back = dequeue_pos_.load(std::memory_order_acquire); - front1 = enqueue_pos_.load(std::memory_order_relaxed); - } - while (front != front1); - return back == front; - } - -private: - struct cell_t - { - std::atomic sequence_; - T data_; - }; - - size_t const max_size_; - - static size_t const cacheline_size = 64; - using cacheline_pad_t = char[cacheline_size]; - - cacheline_pad_t pad0_; - cell_t* const buffer_; - size_t const buffer_mask_; - cacheline_pad_t pad1_; - std::atomic enqueue_pos_; - cacheline_pad_t pad2_; - std::atomic dequeue_pos_; - cacheline_pad_t pad3_; -}; - -} // ns details -} // ns spdlog diff --git a/cpp_src/vendor/spdlog/details/null_mutex.h b/cpp_src/vendor/spdlog/details/null_mutex.h index 82b0ed84d..1b263d97c 100644 --- a/cpp_src/vendor/spdlog/details/null_mutex.h +++ b/cpp_src/vendor/spdlog/details/null_mutex.h @@ -1,45 +1,36 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once #include +#include // null, no cost dummy "mutex" and dummy "atomic" int -namespace spdlog -{ -namespace details -{ -struct null_mutex -{ - void lock() {} - void unlock() {} - bool try_lock() - { - return true; - } +namespace spdlog { +namespace details { +struct null_mutex { + void lock() const {} + void lock_shared() const {} + void unlock() const {} }; -struct null_atomic_int -{ +struct null_atomic_int { int value; null_atomic_int() = default; - explicit null_atomic_int(int val) : value(val) - {} + explicit null_atomic_int(int new_value) + : value(new_value) {} - int load(std::memory_order) const - { - return value; - } + int load(std::memory_order = std::memory_order_relaxed) const { return value; } + + void store(int new_value, std::memory_order = std::memory_order_relaxed) { value = new_value; } - void store(int val) - { - value = val; + int exchange(int new_value, std::memory_order = std::memory_order_relaxed) { + std::swap(new_value, value); + return new_value; // return value before the call } }; -} -} +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/os-inl.h b/cpp_src/vendor/spdlog/details/os-inl.h new file mode 100644 index 000000000..e3c80b921 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/os-inl.h @@ -0,0 +1,594 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 + #include + #include // for FlushFileBuffers + #include // for _get_osfhandle, _isatty, _fileno + #include // for _get_pid + + #ifdef __MINGW32__ + #include + #endif + + #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) + #include + #include + #endif + + #include // for _mkdir/_wmkdir + +#else // unix + + #include + #include + + #ifdef __linux__ + #include //Use gettid() syscall under linux to get thread id + + #elif defined(_AIX) + #include // for pthread_getthrds_np + + #elif defined(__DragonFly__) || defined(__FreeBSD__) + #include // for pthread_getthreadid_np + + #elif defined(__NetBSD__) + #include // for _lwp_self + + #elif defined(__sun) + #include // for thr_self + #endif + +#endif // unix + +#if defined __APPLE__ + #include +#endif + +#ifndef __has_feature // Clang - feature checking macros. + #define __has_feature(x) 0 // Compatibility with non-clang compilers. +#endif + +namespace spdlog { +namespace details { +namespace os { + +SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT { +#if defined __linux__ && defined SPDLOG_CLOCK_COARSE + timespec ts; + ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); + return std::chrono::time_point( + std::chrono::duration_cast( + std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); + +#else + return log_clock::now(); +#endif +} +SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT { +#ifdef _WIN32 + std::tm tm; + ::localtime_s(&tm, &time_tt); +#else + std::tm tm; + ::localtime_r(&time_tt, &tm); +#endif + return tm; +} + +SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT { + std::time_t now_t = ::time(nullptr); + return localtime(now_t); +} + +SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT { +#ifdef _WIN32 + std::tm tm; + ::gmtime_s(&tm, &time_tt); +#else + std::tm tm; + ::gmtime_r(&time_tt, &tm); +#endif + return tm; +} + +SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT { + std::time_t now_t = ::time(nullptr); + return gmtime(now_t); +} + +// fopen_s on non windows for writing +SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) { +#ifdef _WIN32 + #ifdef SPDLOG_WCHAR_FILENAMES + *fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); + #else + *fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); + #endif + #if defined(SPDLOG_PREVENT_CHILD_FD) + if (*fp != nullptr) { + auto file_handle = reinterpret_cast(_get_osfhandle(::_fileno(*fp))); + if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) { + ::fclose(*fp); + *fp = nullptr; + } + } + #endif +#else // unix + #if defined(SPDLOG_PREVENT_CHILD_FD) + const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; + const int fd = + ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); + if (fd == -1) { + return true; + } + *fp = ::fdopen(fd, mode.c_str()); + if (*fp == nullptr) { + ::close(fd); + } + #else + *fp = ::fopen((filename.c_str()), mode.c_str()); + #endif +#endif + + return *fp == nullptr; +} + +SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT { +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return ::_wremove(filename.c_str()); +#else + return std::remove(filename.c_str()); +#endif +} + +SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT { + return path_exists(filename) ? remove(filename) : 0; +} + +SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT { +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + return ::_wrename(filename1.c_str(), filename2.c_str()); +#else + return std::rename(filename1.c_str(), filename2.c_str()); +#endif +} + +// Return true if path exists (file or directory) +SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT { +#ifdef _WIN32 + struct _stat buffer; + #ifdef SPDLOG_WCHAR_FILENAMES + return (::_wstat(filename.c_str(), &buffer) == 0); + #else + return (::_stat(filename.c_str(), &buffer) == 0); + #endif +#else // common linux/unix all have the stat system call + struct stat buffer; + return (::stat(filename.c_str(), &buffer) == 0); +#endif +} + +#ifdef _MSC_VER + // avoid warning about unreachable statement at the end of filesize() + #pragma warning(push) + #pragma warning(disable : 4702) +#endif + +// Return file size according to open FILE* object +SPDLOG_INLINE size_t filesize(FILE *f) { + if (f == nullptr) { + throw_spdlog_ex("Failed getting file size. fd is null"); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + int fd = ::_fileno(f); + #if defined(_WIN64) // 64 bits + __int64 ret = ::_filelengthi64(fd); + if (ret >= 0) { + return static_cast(ret); + } + + #else // windows 32 bits + long ret = ::_filelength(fd); + if (ret >= 0) { + return static_cast(ret); + } + #endif + +#else // unix + // OpenBSD and AIX doesn't compile with :: before the fileno(..) + #if defined(__OpenBSD__) || defined(_AIX) + int fd = fileno(f); + #else + int fd = ::fileno(f); + #endif + // 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) + #if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && \ + (defined(__LP64__) || defined(_LP64)) + struct stat64 st; + if (::fstat64(fd, &st) == 0) { + return static_cast(st.st_size); + } + #else // other unix or linux 32 bits or cygwin + struct stat st; + if (::fstat(fd, &st) == 0) { + return static_cast(st.st_size); + } + #endif +#endif + throw_spdlog_ex("Failed getting file size from fd", errno); + return 0; // will not be reached. +} + +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +// Return utc offset in minutes or throw spdlog_ex on failure +SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) { +#ifdef _WIN32 + #if _WIN32_WINNT < _WIN32_WINNT_WS08 + TIME_ZONE_INFORMATION tzinfo; + auto rv = ::GetTimeZoneInformation(&tzinfo); + #else + DYNAMIC_TIME_ZONE_INFORMATION tzinfo; + auto rv = ::GetDynamicTimeZoneInformation(&tzinfo); + #endif + if (rv == TIME_ZONE_ID_INVALID) throw_spdlog_ex("Failed getting timezone info. ", errno); + + int offset = -tzinfo.Bias; + if (tm.tm_isdst) { + offset -= tzinfo.DaylightBias; + } else { + offset -= tzinfo.StandardBias; + } + return offset; +#else + + #if defined(sun) || defined(__sun) || defined(_AIX) || \ + (defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \ + (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) + // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris + struct helper { + static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), + const std::tm &gmtm = details::os::gmtime()) { + int local_year = localtm.tm_year + (1900 - 1); + int gmt_year = gmtm.tm_year + (1900 - 1); + + long int days = ( + // difference in day of year + localtm.tm_yday - + gmtm.tm_yday + + // + intervening leap days + + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) + + // + difference in years * 365 */ + + static_cast(local_year - gmt_year) * 365); + + long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); + long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); + long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); + + return secs; + } + }; + + auto offset_seconds = helper::calculate_gmt_offset(tm); + #else + auto offset_seconds = tm.tm_gmtoff; + #endif + + return static_cast(offset_seconds / 60); +#endif +} + +// Return current thread id as size_t +// It exists because the std::this_thread::get_id() is much slower(especially +// under VS 2013) +SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT { +#ifdef _WIN32 + return static_cast(::GetCurrentThreadId()); +#elif defined(__linux__) + #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) + #define SYS_gettid __NR_gettid + #endif + return static_cast(::syscall(SYS_gettid)); +#elif defined(_AIX) + struct __pthrdsinfo buf; + int reg_size = 0; + pthread_t pt = pthread_self(); + int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size); + int tid = (!retval) ? buf.__pi_tid : 0; + return static_cast(tid); +#elif defined(__DragonFly__) || defined(__FreeBSD__) + return static_cast(::pthread_getthreadid_np()); +#elif defined(__NetBSD__) + return static_cast(::_lwp_self()); +#elif defined(__OpenBSD__) + return static_cast(::getthrid()); +#elif defined(__sun) + return static_cast(::thr_self()); +#elif __APPLE__ + uint64_t tid; + // There is no pthread_threadid_np prior to Mac OS X 10.6, and it is not supported on any PPC, + // including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64. + #ifdef MAC_OS_X_VERSION_MAX_ALLOWED + { + #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__) + tid = pthread_mach_thread_np(pthread_self()); + #elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if (&pthread_threadid_np) { + pthread_threadid_np(nullptr, &tid); + } else { + tid = pthread_mach_thread_np(pthread_self()); + } + #else + pthread_threadid_np(nullptr, &tid); + #endif + } + #else + pthread_threadid_np(nullptr, &tid); + #endif + return static_cast(tid); +#else // Default to standard C++11 (other Unix) + return static_cast(std::hash()(std::this_thread::get_id())); +#endif +} + +// Return current thread id as size_t (from thread local storage) +SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT { +#if defined(SPDLOG_NO_TLS) + return _thread_id(); +#else // cache thread id in tls + static thread_local const size_t tid = _thread_id(); + return tid; +#endif +} + +// This is avoid msvc issue in sleep_for that happens if the clock changes. +// See https://github.com/gabime/spdlog/issues/609 +SPDLOG_INLINE void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT { +#if defined(_WIN32) + ::Sleep(milliseconds); +#else + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); +#endif +} + +// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { + memory_buf_t buf; + wstr_to_utf8buf(filename, buf); + return SPDLOG_BUF_TO_STRING(buf); +} +#else +SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) { return filename; } +#endif + +SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT { +#ifdef _WIN32 + return conditional_static_cast(::GetCurrentProcessId()); +#else + return conditional_static_cast(::getpid()); +#endif +} + +// Determine if the terminal supports colors +// Based on: https://github.com/agauniyal/rang/ +SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT { +#ifdef _WIN32 + return true; +#else + + static const bool result = []() { + const char *env_colorterm_p = std::getenv("COLORTERM"); + if (env_colorterm_p != nullptr) { + return true; + } + + static constexpr std::array terms = { + {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", + "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}}; + + const char *env_term_p = std::getenv("TERM"); + if (env_term_p == nullptr) { + return false; + } + + return std::any_of(terms.begin(), terms.end(), [&](const char *term) { + return std::strstr(env_term_p, term) != nullptr; + }); + }(); + + return result; +#endif +} + +// Determine if the terminal attached +// Source: https://github.com/agauniyal/rang/ +SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT { +#ifdef _WIN32 + return ::_isatty(_fileno(file)) != 0; +#else + return ::isatty(fileno(file)) != 0; +#endif +} + +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target) { + if (wstr.size() > static_cast((std::numeric_limits::max)()) / 4 - 1) { + throw_spdlog_ex("UTF-16 string is too big to be converted to UTF-8"); + } + + int wstr_size = static_cast(wstr.size()); + if (wstr_size == 0) { + target.resize(0); + return; + } + + int result_size = static_cast(target.capacity()); + if ((wstr_size + 1) * 4 > result_size) { + result_size = + ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); + } + + if (result_size > 0) { + target.resize(result_size); + result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), + result_size, NULL, NULL); + + if (result_size > 0) { + target.resize(result_size); + return; + } + } + + throw_spdlog_ex( + fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); +} + +SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) { + if (str.size() > static_cast((std::numeric_limits::max)()) - 1) { + throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); + } + + int str_size = static_cast(str.size()); + if (str_size == 0) { + target.resize(0); + return; + } + + // find the size to allocate for the result buffer + int result_size = + ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); + + if (result_size > 0) { + target.resize(result_size); + result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, + target.data(), result_size); + if (result_size > 0) { + assert(result_size == target.size()); + return; + } + } + + throw_spdlog_ex( + fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); +} +#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && + // defined(_WIN32) + +// return true on success +static SPDLOG_INLINE bool mkdir_(const filename_t &path) { +#ifdef _WIN32 + #ifdef SPDLOG_WCHAR_FILENAMES + return ::_wmkdir(path.c_str()) == 0; + #else + return ::_mkdir(path.c_str()) == 0; + #endif +#else + return ::mkdir(path.c_str(), mode_t(0755)) == 0; +#endif +} + +// create the given directory - and all directories leading to it +// return true on success or if the directory already exists +SPDLOG_INLINE bool create_dir(const filename_t &path) { + if (path_exists(path)) { + return true; + } + + if (path.empty()) { + return false; + } + + size_t search_offset = 0; + do { + auto token_pos = path.find_first_of(folder_seps_filename, search_offset); + // treat the entire path as a folder if no folder separator not found + if (token_pos == filename_t::npos) { + token_pos = path.size(); + } + + auto subdir = path.substr(0, token_pos); +#ifdef _WIN32 + // if subdir is just a drive letter, add a slash e.g. "c:"=>"c:\", + // otherwise path_exists(subdir) returns false (issue #3079) + const bool is_drive = subdir.length() == 2 && subdir[1] == ':'; + if (is_drive) { + subdir += '\\'; + token_pos++; + } +#endif + + if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) { + return false; // return error if failed creating dir + } + search_offset = token_pos + 1; + } while (search_offset < path.size()); + + return true; +} + +// Return directory name from given path or empty string +// "abc/file" => "abc" +// "abc/" => "abc" +// "abc" => "" +// "abc///" => "abc//" +SPDLOG_INLINE filename_t dir_name(const filename_t &path) { + auto pos = path.find_last_of(folder_seps_filename); + return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; +} + +std::string SPDLOG_INLINE getenv(const char *field) { +#if defined(_MSC_VER) + #if defined(__cplusplus_winrt) + return std::string{}; // not supported under uwp + #else + size_t len = 0; + char buf[128]; + bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0; + return ok ? buf : std::string{}; + #endif +#else // revert to getenv + char *buf = ::getenv(field); + return buf ? buf : std::string{}; +#endif +} + +// Do fsync by FILE handlerpointer +// Return true on success +SPDLOG_INLINE bool fsync(FILE *fp) { +#ifdef _WIN32 + return FlushFileBuffers(reinterpret_cast(_get_osfhandle(_fileno(fp)))) != 0; +#else + return ::fsync(fileno(fp)) == 0; +#endif +} + +} // namespace os +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/os.h b/cpp_src/vendor/spdlog/details/os.h index a3f05d782..b1069edce 100644 --- a/cpp_src/vendor/spdlog/details/os.h +++ b/cpp_src/vendor/spdlog/details/os.h @@ -1,489 +1,123 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// -#pragma once - -#include "../common.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 - -#ifndef NOMINMAX -#define NOMINMAX //prevent windows redefining min/max -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include // _get_pid support -#include // _get_osfhandle and _isatty support - -#ifdef __MINGW32__ -#include -#endif - -#else // unix - -#include -#include - -#ifdef __linux__ -#include //Use gettid() syscall under linux to get thread id - -#elif __FreeBSD__ -#include //Use thr_self() syscall under FreeBSD to get thread id -#endif - -#endif //unix - -#ifndef __has_feature // Clang - feature checking macros. -#define __has_feature(x) 0 // Compatibility with non-clang compilers. -#endif +#pragma once -namespace spdlog -{ -namespace details -{ -namespace os -{ +#include // std::time_t +#include -inline spdlog::log_clock::time_point now() -{ +namespace spdlog { +namespace details { +namespace os { -#if defined __linux__ && defined SPDLOG_CLOCK_COARSE - timespec ts; - ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); - return std::chrono::time_point( - std::chrono::duration_cast( - std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); +SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; +SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; -#else - return log_clock::now(); -#endif +SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; -} -inline std::tm localtime(const std::time_t &time_tt) -{ +SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; -#ifdef _WIN32 - std::tm tm; - localtime_s(&tm, &time_tt); -#else - std::tm tm; - localtime_r(&time_tt, &tm); -#endif - return tm; -} - -inline std::tm localtime() -{ - std::time_t now_t = time(nullptr); - return localtime(now_t); -} - -inline std::tm gmtime(const std::time_t &time_tt) -{ - -#ifdef _WIN32 - std::tm tm; - gmtime_s(&tm, &time_tt); -#else - std::tm tm; - gmtime_r(&time_tt, &tm); -#endif - return tm; -} - -inline std::tm gmtime() -{ - std::time_t now_t = time(nullptr); - return gmtime(now_t); -} -inline bool operator==(const std::tm& tm1, const std::tm& tm2) -{ - return (tm1.tm_sec == tm2.tm_sec && - tm1.tm_min == tm2.tm_min && - tm1.tm_hour == tm2.tm_hour && - tm1.tm_mday == tm2.tm_mday && - tm1.tm_mon == tm2.tm_mon && - tm1.tm_year == tm2.tm_year && - tm1.tm_isdst == tm2.tm_isdst); -} - -inline bool operator!=(const std::tm& tm1, const std::tm& tm2) -{ - return !(tm1 == tm2); -} +SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; // eol definition -#if !defined (SPDLOG_EOL) -#ifdef _WIN32 -#define SPDLOG_EOL "\r\n" -#else -#define SPDLOG_EOL "\n" +#if !defined(SPDLOG_EOL) + #ifdef _WIN32 + #define SPDLOG_EOL "\r\n" + #else + #define SPDLOG_EOL "\n" + #endif #endif -#endif - -SPDLOG_CONSTEXPR static const char* default_eol = SPDLOG_EOL; - +SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; // folder separator -#ifdef _WIN32 -SPDLOG_CONSTEXPR static const char folder_sep = '\\'; -#else -SPDLOG_CONSTEXPR static const char folder_sep = '/'; -#endif - - -inline void prevent_child_fd(FILE *f) -{ - -#ifdef _WIN32 -#if !defined(__cplusplus_winrt) - auto file_handle = HANDLE(_get_osfhandle(_fileno(f))); - if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) - throw spdlog_ex("SetHandleInformation failed", errno); -#endif -#else - auto fd = fileno(f); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); -#endif -} - - -//fopen_s on non windows for writing -inline bool fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode) -{ -#ifdef _WIN32 -#ifdef SPDLOG_WCHAR_FILENAMES - *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); -#else - *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR); -#endif -#else //unix - *fp = fopen((filename.c_str()), mode.c_str()); +#if !defined(SPDLOG_FOLDER_SEPS) + #ifdef _WIN32 + #define SPDLOG_FOLDER_SEPS "\\/" + #else + #define SPDLOG_FOLDER_SEPS "/" + #endif #endif -#ifdef SPDLOG_PREVENT_CHILD_FD - if (*fp != nullptr) - prevent_child_fd(*fp); -#endif - return *fp == nullptr; -} +SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS; +SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = + SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS); +// fopen_s on non windows for writing +SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); -inline int remove(const filename_t &filename) -{ -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return _wremove(filename.c_str()); -#else - return std::remove(filename.c_str()); -#endif -} - -inline int rename(const filename_t& filename1, const filename_t& filename2) -{ -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) - return _wrename(filename1.c_str(), filename2.c_str()); -#else - return std::rename(filename1.c_str(), filename2.c_str()); -#endif -} +// Remove filename. return 0 on success +SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT; +// Remove file if exists. return 0 on success +// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) +SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; -//Return if file exists -inline bool file_exists(const filename_t& filename) -{ -#ifdef _WIN32 -#ifdef SPDLOG_WCHAR_FILENAMES - auto attribs = GetFileAttributesW(filename.c_str()); -#else - auto attribs = GetFileAttributesA(filename.c_str()); -#endif - return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); -#else //common linux/unix all have the stat system call - struct stat buffer; - return (stat(filename.c_str(), &buffer) == 0); -#endif -} +SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; +// Return if file exists. +SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; +// Return file size according to open FILE* object +SPDLOG_API size_t filesize(FILE *f); +// Return utc offset in minutes or throw spdlog_ex on failure +SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); -//Return file size according to open FILE* object -inline size_t filesize(FILE *f) -{ - if (f == nullptr) - throw spdlog_ex("Failed getting file size. fd is null"); -#if defined ( _WIN32) && !defined(__CYGWIN__) - int fd = _fileno(f); -#if _WIN64 //64 bits - struct _stat64 st; - if (_fstat64(fd, &st) == 0) - return st.st_size; - -#else //windows 32 bits - long ret = _filelength(fd); - if (ret >= 0) - return static_cast(ret); -#endif - -#else // unix - int fd = fileno(f); - // 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated) -#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && \ - (defined(__LP64__) || defined(_LP64)) - struct stat64 st ; - if (fstat64(fd, &st) == 0) - return static_cast(st.st_size); -#else // unix 32 bits or cygwin - struct stat st; - if (fstat(fd, &st) == 0) - return static_cast(st.st_size); -#endif -#endif - throw spdlog_ex("Failed getting file size from fd", errno); -} - - - - -//Return utc offset in minutes or throw spdlog_ex on failure -inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) -{ - -#ifdef _WIN32 -#if _WIN32_WINNT < _WIN32_WINNT_WS08 - TIME_ZONE_INFORMATION tzinfo; - auto rv = GetTimeZoneInformation(&tzinfo); -#else - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - auto rv = GetDynamicTimeZoneInformation(&tzinfo); -#endif - if (rv == TIME_ZONE_ID_INVALID) - throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); - - int offset = -tzinfo.Bias; - if (tm.tm_isdst) - offset -= tzinfo.DaylightBias; - else - offset -= tzinfo.StandardBias; - return offset; -#else - -#if defined(sun) || defined(__sun) - // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris - struct helper - { - static long int calculate_gmt_offset(const std::tm & localtm = details::os::localtime(), const std::tm & gmtm = details::os::gmtime()) - { - int local_year = localtm.tm_year + (1900 - 1); - int gmt_year = gmtm.tm_year + (1900 - 1); - - long int days = ( - // difference in day of year - localtm.tm_yday - gmtm.tm_yday - - // + intervening leap days - + ((local_year >> 2) - (gmt_year >> 2)) - - (local_year / 100 - gmt_year / 100) - + ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) - - // + difference in years * 365 */ - + (long int)(local_year - gmt_year) * 365 - ); - - long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); - long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); - long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); - - return secs; - } - }; - - auto offset_seconds = helper::calculate_gmt_offset(tm); -#else - auto offset_seconds = tm.tm_gmtoff; -#endif +// Return current thread id as size_t +// It exists because the std::this_thread::get_id() is much slower(especially +// under VS 2013) +SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; - return static_cast(offset_seconds / 60); -#endif -} - -//Return current thread id as size_t -//It exists because the std::this_thread::get_id() is much slower(especially under VS 2013) -inline size_t _thread_id() -{ -#ifdef _WIN32 - return static_cast(::GetCurrentThreadId()); -#elif __linux__ -# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) -# define SYS_gettid __NR_gettid -# endif - return static_cast(syscall(SYS_gettid)); -#elif __FreeBSD__ - long tid; - thr_self(&tid); - return static_cast(tid); -#elif __APPLE__ - uint64_t tid; - pthread_threadid_np(nullptr, &tid); - return static_cast(tid); -#else //Default to standard C++11 (other Unix) - return static_cast(std::hash()(std::this_thread::get_id())); -#endif -} - -//Return current thread id as size_t (from thread local storage) -inline size_t thread_id() -{ -#if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt ) || (defined(__clang__) && !__has_feature(cxx_thread_local)) - return _thread_id(); -#else // cache thread id in tls - static thread_local const size_t tid = _thread_id(); - return tid; -#endif +// Return current thread id as size_t (from thread local storage) +SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; +// This is avoid msvc issue in sleep_for that happens if the clock changes. +// See https://github.com/gabime/spdlog/issues/609 +SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT; -} +SPDLOG_API std::string filename_to_str(const filename_t &filename); +SPDLOG_API int pid() SPDLOG_NOEXCEPT; -// This is avoid msvc issue in sleep_for that happens if the clock changes. -// See https://github.com/gabime/spdlog/issues/609 -inline void sleep_for_millis(int milliseconds) -{ -#if defined(_WIN32) - ::Sleep(milliseconds); -#else - std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); -#endif -} - -// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) -#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) -#define SPDLOG_FILENAME_T(s) L ## s -inline std::string filename_to_str(const filename_t& filename) -{ - std::wstring_convert, wchar_t> c; - return c.to_bytes(filename); -} -#else -#define SPDLOG_FILENAME_T(s) s -inline std::string filename_to_str(const filename_t& filename) -{ - return filename; -} -#endif +// Determine if the terminal supports colors +// Source: https://github.com/agauniyal/rang/ +SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; -inline std::string errno_to_string(char[256], char* res) -{ - return std::string(res); -} - -inline std::string errno_to_string(char buf[256], int res) -{ - if (res == 0) - { - return std::string(buf); - } - return "Unknown error"; -} - -// Return errno string (thread safe) -inline std::string errno_str(int err_num) -{ - char buf[256]; - SPDLOG_CONSTEXPR auto buf_size = sizeof(buf); - -#ifdef _WIN32 - if (strerror_s(buf, buf_size, err_num) == 0) - return std::string(buf); - else - return "Unknown error"; - -#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \ - ((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version - - if (strerror_r(err_num, buf, buf_size) == 0) - return std::string(buf); - else - return "Unknown error"; - -#else // gnu version (might not use the given buf, so its retval pointer must be used) - auto err = strerror_r(err_num, buf, buf_size); // let compiler choose type - return errno_to_string(buf, err); // use overloading to select correct stringify function -#endif -} +// Determine if the terminal attached +// Source: https://github.com/agauniyal/rang/ +SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; -inline int pid() -{ +#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) +SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); -#ifdef _WIN32 - return static_cast(::GetCurrentProcessId()); -#else - return static_cast(::getpid()); +SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); #endif -} +// Return directory name from given path or empty string +// "abc/file" => "abc" +// "abc/" => "abc" +// "abc" => "" +// "abc///" => "abc//" +SPDLOG_API filename_t dir_name(const filename_t &path); +// Create a dir from the given path. +// Return true if succeeded or if this dir already exists. +SPDLOG_API bool create_dir(const filename_t &path); -// Determine if the terminal supports colors -// Source: https://github.com/agauniyal/rang/ -inline bool is_color_terminal() -{ -#ifdef _WIN32 - return true; -#else - static constexpr const char* Terms[] = - { - "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", - "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm" - }; - - const char *env_p = std::getenv("TERM"); - if (env_p == nullptr) - { - return false; - } - - static const bool result = std::any_of( - std::begin(Terms), std::end(Terms), [&](const char* term) - { - return std::strstr(env_p, term) != nullptr; - }); - return result; -#endif -} +// non thread safe, cross platform getenv/getenv_s +// return empty string if field not found +SPDLOG_API std::string getenv(const char *field); +// Do fsync by FILE objectpointer. +// Return true on success. +SPDLOG_API bool fsync(FILE *fp); -// Detrmine if the terminal attached -// Source: https://github.com/agauniyal/rang/ -inline bool in_terminal(FILE* file) -{ +} // namespace os +} // namespace details +} // namespace spdlog -#ifdef _WIN32 - return _isatty(_fileno(file)) != 0; -#else - return isatty(fileno(file)) != 0; +#ifdef SPDLOG_HEADER_ONLY + #include "os-inl.h" #endif -} -} //os -} //details -} //spdlog diff --git a/cpp_src/vendor/spdlog/details/pattern_formatter_impl.h b/cpp_src/vendor/spdlog/details/pattern_formatter_impl.h deleted file mode 100644 index b5ee6d027..000000000 --- a/cpp_src/vendor/spdlog/details/pattern_formatter_impl.h +++ /dev/null @@ -1,672 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include "../formatter.h" -#include "../details/log_msg.h" -#include "../details/os.h" -#include "../fmt/fmt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spdlog -{ -namespace details -{ -class flag_formatter -{ -public: - virtual ~flag_formatter() = default; - virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; -}; - -/////////////////////////////////////////////////////////////////////// -// name & level pattern appenders -/////////////////////////////////////////////////////////////////////// -class name_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << *msg.logger_name; - } -}; - -// log level appender -class level_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << level::to_str(msg.level); - } -}; - -// short log level appender -class short_level_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << level::to_short_str(msg.level); - } -}; - -/////////////////////////////////////////////////////////////////////// -// Date time pattern appenders -/////////////////////////////////////////////////////////////////////// - -static const char* ampm(const tm& t) -{ - return t.tm_hour >= 12 ? "PM" : "AM"; -} - -static int to12h(const tm& t) -{ - return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; -} - -//Abbreviated weekday name -static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -class a_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << days[tm_time.tm_wday]; - } -}; - -//Full weekday name -static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; -class A_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << full_days[tm_time.tm_wday]; - } -}; - -//Abbreviated month -static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" }; -class b_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << months[tm_time.tm_mon]; - } -}; - -//Full month name -static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; -class B_formatter : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << full_months[tm_time.tm_mon]; - } -}; - -//write 2 ints separated by sep with padding of 2 -static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) -{ - w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); - return w; -} - -//write 3 ints separated by sep with padding of 2 -static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) -{ - w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); - return w; -} - -//Date and time representation (Thu Aug 23 15:35:46 2014) -class c_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; - } -}; - -// year - 2 digit -class C_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); - } -}; - -// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 -class D_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); - } -}; - -// year - 4 digit -class Y_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << tm_time.tm_year + 1900; - } -}; - -// month 1-12 -class m_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); - } -}; - -// day of month 1-31 -class d_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); - } -}; - -// hours in 24 format 0-23 -class H_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); - } -}; - -// hours in 12 format 1-12 -class I_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); - } -}; - -// minutes 0-59 -class M_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); - } -}; - -// seconds 0-59 -class S_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); - } -}; - -// milliseconds -class e_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted << fmt::pad(static_cast(millis), 3, '0'); - } -}; - -// microseconds -class f_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto micros = std::chrono::duration_cast(duration).count() % 1000000; - msg.formatted << fmt::pad(static_cast(micros), 6, '0'); - } -}; - -// nanoseconds -class F_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto ns = std::chrono::duration_cast(duration).count() % 1000000000; - msg.formatted << fmt::pad(static_cast(ns), 9, '0'); - } -}; - -class E_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto seconds = std::chrono::duration_cast(duration).count(); - msg.formatted << seconds; - } -}; - -// AM/PM -class p_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << ampm(tm_time); - } -}; - -// 12 hour clock 02:55:02 pm -class r_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); - } -}; - -// 24-hour HH:MM time, equivalent to %H:%M -class R_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); - } -}; - -// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S -class T_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); - } -}; - -// ISO 8601 offset from UTC in timezone (+-HH:MM) -class z_formatter SPDLOG_FINAL : public flag_formatter -{ -public: - const std::chrono::seconds cache_refresh = std::chrono::seconds(5); - - z_formatter() = default; - z_formatter(const z_formatter&) = delete; - z_formatter& operator=(const z_formatter&) = delete; - - void format(details::log_msg& msg, const std::tm& tm_time) override - { -#ifdef _WIN32 - int total_minutes = get_cached_offset(msg, tm_time); -#else - // No need to chache under gcc, - // it is very fast (already stored in tm.tm_gmtoff) - int total_minutes = os::utc_minutes_offset(tm_time); -#endif - bool is_negative = total_minutes < 0; - char sign; - if (is_negative) - { - total_minutes = -total_minutes; - sign = '-'; - } - else - { - sign = '+'; - } - - int h = total_minutes / 60; - int m = total_minutes % 60; - msg.formatted << sign; - pad_n_join(msg.formatted, h, m, ':'); - } -private: - log_clock::time_point _last_update{ std::chrono::seconds(0) }; - int _offset_minutes{ 0 }; - std::mutex _mutex; - - int get_cached_offset(const log_msg& msg, const std::tm& tm_time) - { - std::lock_guard l(_mutex); - if (msg.time - _last_update >= cache_refresh) - { - _offset_minutes = os::utc_minutes_offset(tm_time); - _last_update = msg.time; - } - return _offset_minutes; - } -}; - -// Thread id -class t_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << msg.thread_id; - } -}; - -// Current pid -class pid_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << details::os::pid(); - } -}; - -// message counter formatter -class i_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << fmt::pad(msg.msg_id, 6, '0'); - } -}; - -class v_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); - } -}; - -class ch_formatter SPDLOG_FINAL : public flag_formatter -{ -public: - explicit ch_formatter(char ch): _ch(ch) - {} - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << _ch; - } -private: - char _ch; -}; - - -//aggregate user chars to display as is -class aggregate_formatter SPDLOG_FINAL : public flag_formatter -{ -public: - aggregate_formatter() = default; - - void add_ch(char ch) - { - _str += ch; - } - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << _str; - } -private: - std::string _str; -}; - -// Full info formatter -// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v -class full_formatter SPDLOG_FINAL : public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { -#ifndef SPDLOG_NO_DATETIME - auto duration = msg.time.time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count() % 1000; - - /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), - msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", - tm_time.tm_year + 1900, - tm_time.tm_mon + 1, - tm_time.tm_mday, - tm_time.tm_hour, - tm_time.tm_min, - tm_time.tm_sec, - static_cast(millis), - msg.logger_name, - level::to_str(msg.level), - msg.raw.str());*/ - - - // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) - msg.formatted << '[' << static_cast(tm_time.tm_year + 1900) << '-' - << fmt::pad(static_cast(tm_time.tm_mon + 1), 2, '0') << '-' - << fmt::pad(static_cast(tm_time.tm_mday), 2, '0') << ' ' - << fmt::pad(static_cast(tm_time.tm_hour), 2, '0') << ':' - << fmt::pad(static_cast(tm_time.tm_min), 2, '0') << ':' - << fmt::pad(static_cast(tm_time.tm_sec), 2, '0') << '.' - << fmt::pad(static_cast(millis), 3, '0') << "] "; - - //no datetime needed -#else - (void)tm_time; -#endif - -#ifndef SPDLOG_NO_NAME - msg.formatted << '[' << *msg.logger_name << "] "; -#endif - - msg.formatted << '[' << level::to_str(msg.level) << "] "; - msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); - } -}; - - - -} -} -/////////////////////////////////////////////////////////////////////////////// -// pattern_formatter inline impl -/////////////////////////////////////////////////////////////////////////////// -inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern, pattern_time_type pattern_time, std::string eol) : - _eol(std::move(eol)), - _pattern_time(pattern_time) -{ - compile_pattern(pattern); -} - -inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern) -{ - auto end = pattern.end(); - std::unique_ptr user_chars; - for (auto it = pattern.begin(); it != end; ++it) - { - if (*it == '%') - { - if (user_chars) //append user chars found so far - _formatters.push_back(std::move(user_chars)); - if (++it != end) - handle_flag(*it); - else - break; - } - else // chars not following the % sign should be displayed as is - { - if (!user_chars) - user_chars = std::unique_ptr(new details::aggregate_formatter()); - user_chars->add_ch(*it); - } - } - if (user_chars) //append raw chars found so far - { - _formatters.push_back(std::move(user_chars)); - } - -} -inline void spdlog::pattern_formatter::handle_flag(char flag) -{ - switch (flag) - { - // logger name - case 'n': - _formatters.emplace_back(new details::name_formatter()); - break; - - case 'l': - _formatters.emplace_back(new details::level_formatter()); - break; - - case 'L': - _formatters.emplace_back(new details::short_level_formatter()); - break; - - case('t'): - _formatters.emplace_back(new details::t_formatter()); - break; - - case('v'): - _formatters.emplace_back(new details::v_formatter()); - break; - - case('a'): - _formatters.emplace_back(new details::a_formatter()); - break; - - case('A'): - _formatters.emplace_back(new details::A_formatter()); - break; - - case('b'): - case('h'): - _formatters.emplace_back(new details::b_formatter()); - break; - - case('B'): - _formatters.emplace_back(new details::B_formatter()); - break; - case('c'): - _formatters.emplace_back(new details::c_formatter()); - break; - - case('C'): - _formatters.emplace_back(new details::C_formatter()); - break; - - case('Y'): - _formatters.emplace_back(new details::Y_formatter()); - break; - - case('D'): - case('x'): - - _formatters.emplace_back(new details::D_formatter()); - break; - - case('m'): - _formatters.emplace_back(new details::m_formatter()); - break; - - case('d'): - _formatters.emplace_back(new details::d_formatter()); - break; - - case('H'): - _formatters.emplace_back(new details::H_formatter()); - break; - - case('I'): - _formatters.emplace_back(new details::I_formatter()); - break; - - case('M'): - _formatters.emplace_back(new details::M_formatter()); - break; - - case('S'): - _formatters.emplace_back(new details::S_formatter()); - break; - - case('e'): - _formatters.emplace_back(new details::e_formatter()); - break; - - case('f'): - _formatters.emplace_back(new details::f_formatter()); - break; - case('F'): - _formatters.emplace_back(new details::F_formatter()); - break; - - case('E'): - _formatters.emplace_back(new details::E_formatter()); - break; - - case('p'): - _formatters.emplace_back(new details::p_formatter()); - break; - - case('r'): - _formatters.emplace_back(new details::r_formatter()); - break; - - case('R'): - _formatters.emplace_back(new details::R_formatter()); - break; - - case('T'): - case('X'): - _formatters.emplace_back(new details::T_formatter()); - break; - - case('z'): - _formatters.emplace_back(new details::z_formatter()); - break; - - case ('+'): - _formatters.emplace_back(new details::full_formatter()); - break; - - case ('P'): - _formatters.emplace_back(new details::pid_formatter()); - break; - - - case ('i'): - _formatters.emplace_back(new details::i_formatter()); - break; - - default: //Unknown flag appears as is - _formatters.emplace_back(new details::ch_formatter('%')); - _formatters.emplace_back(new details::ch_formatter(flag)); - break; - } -} - -inline std::tm spdlog::pattern_formatter::get_time(details::log_msg& msg) -{ - if (_pattern_time == pattern_time_type::local) - { - return details::os::localtime(log_clock::to_time_t(msg.time)); - } - return details::os::gmtime(log_clock::to_time_t(msg.time)); -} - -inline void spdlog::pattern_formatter::format(details::log_msg& msg) -{ - -#ifndef SPDLOG_NO_DATETIME - auto tm_time = get_time(msg); -#else - std::tm tm_time; -#endif - for (auto &f : _formatters) - { - f->format(msg, tm_time); - } - //write eol - msg.formatted.write(_eol.data(), _eol.size()); -} diff --git a/cpp_src/vendor/spdlog/details/periodic_worker-inl.h b/cpp_src/vendor/spdlog/details/periodic_worker-inl.h new file mode 100644 index 000000000..18f11fbec --- /dev/null +++ b/cpp_src/vendor/spdlog/details/periodic_worker-inl.h @@ -0,0 +1,26 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +namespace spdlog { +namespace details { + +// stop the worker thread and join it +SPDLOG_INLINE periodic_worker::~periodic_worker() { + if (worker_thread_.joinable()) { + { + std::lock_guard lock(mutex_); + active_ = false; + } + cv_.notify_one(); + worker_thread_.join(); + } +} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/periodic_worker.h b/cpp_src/vendor/spdlog/details/periodic_worker.h new file mode 100644 index 000000000..d647b66ee --- /dev/null +++ b/cpp_src/vendor/spdlog/details/periodic_worker.h @@ -0,0 +1,58 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// periodic worker thread - periodically executes the given callback function. +// +// RAII over the owned thread: +// creates the thread on construction. +// stops and joins the thread on destruction (if the thread is executing a callback, wait for it +// to finish first). + +#include +#include +#include +#include +#include +namespace spdlog { +namespace details { + +class SPDLOG_API periodic_worker { +public: + template + periodic_worker(const std::function &callback_fun, + std::chrono::duration interval) { + active_ = (interval > std::chrono::duration::zero()); + if (!active_) { + return; + } + + worker_thread_ = std::thread([this, callback_fun, interval]() { + for (;;) { + std::unique_lock lock(this->mutex_); + if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) { + return; // active_ == false, so exit this thread + } + callback_fun(); + } + }); + } + std::thread &get_thread() { return worker_thread_; } + periodic_worker(const periodic_worker &) = delete; + periodic_worker &operator=(const periodic_worker &) = delete; + // stop the worker thread and join it + ~periodic_worker(); + +private: + bool active_; + std::thread worker_thread_; + std::mutex mutex_; + std::condition_variable cv_; +}; +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "periodic_worker-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/registry-inl.h b/cpp_src/vendor/spdlog/details/registry-inl.h new file mode 100644 index 000000000..f447848ee --- /dev/null +++ b/cpp_src/vendor/spdlog/details/registry-inl.h @@ -0,0 +1,261 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include +#include +#include + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER + // support for the default stdout color logger + #ifdef _WIN32 + #include + #else + #include + #endif +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE registry::registry() + : formatter_(new pattern_formatter()) { +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER + // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). + #ifdef _WIN32 + auto color_sink = std::make_shared(); + #else + auto color_sink = std::make_shared(); + #endif + + const char *default_logger_name = ""; + default_logger_ = std::make_shared(default_logger_name, std::move(color_sink)); + loggers_[default_logger_name] = default_logger_; + +#endif // SPDLOG_DISABLE_DEFAULT_LOGGER +} + +SPDLOG_INLINE registry::~registry() = default; + +SPDLOG_INLINE void registry::register_logger(std::shared_ptr new_logger) { + std::lock_guard lock(logger_map_mutex_); + register_logger_(std::move(new_logger)); +} + +SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr new_logger) { + std::lock_guard lock(logger_map_mutex_); + new_logger->set_formatter(formatter_->clone()); + + if (err_handler_) { + new_logger->set_error_handler(err_handler_); + } + + // set new level according to previously configured level or default level + auto it = log_levels_.find(new_logger->name()); + auto new_level = it != log_levels_.end() ? it->second : global_log_level_; + new_logger->set_level(new_level); + + new_logger->flush_on(flush_level_); + + if (backtrace_n_messages_ > 0) { + new_logger->enable_backtrace(backtrace_n_messages_); + } + + if (automatic_registration_) { + register_logger_(std::move(new_logger)); + } +} + +SPDLOG_INLINE std::shared_ptr registry::get(const std::string &logger_name) { + std::lock_guard lock(logger_map_mutex_); + auto found = loggers_.find(logger_name); + return found == loggers_.end() ? nullptr : found->second; +} + +SPDLOG_INLINE std::shared_ptr registry::default_logger() { + std::lock_guard lock(logger_map_mutex_); + return default_logger_; +} + +// Return raw ptr to the default logger. +// To be used directly by the spdlog default api (e.g. spdlog::info) +// This make the default API faster, but cannot be used concurrently with set_default_logger(). +// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. +SPDLOG_INLINE logger *registry::get_default_raw() { return default_logger_.get(); } + +// set default logger. +// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. +SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr new_default_logger) { + std::lock_guard lock(logger_map_mutex_); + if (new_default_logger != nullptr) { + loggers_[new_default_logger->name()] = new_default_logger; + } + default_logger_ = std::move(new_default_logger); +} + +SPDLOG_INLINE void registry::set_tp(std::shared_ptr tp) { + std::lock_guard lock(tp_mutex_); + tp_ = std::move(tp); +} + +SPDLOG_INLINE std::shared_ptr registry::get_tp() { + std::lock_guard lock(tp_mutex_); + return tp_; +} + +// Set global formatter. Each sink in each logger will get a clone of this object +SPDLOG_INLINE void registry::set_formatter(std::unique_ptr formatter) { + std::lock_guard lock(logger_map_mutex_); + formatter_ = std::move(formatter); + for (auto &l : loggers_) { + l.second->set_formatter(formatter_->clone()); + } +} + +SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages) { + std::lock_guard lock(logger_map_mutex_); + backtrace_n_messages_ = n_messages; + + for (auto &l : loggers_) { + l.second->enable_backtrace(n_messages); + } +} + +SPDLOG_INLINE void registry::disable_backtrace() { + std::lock_guard lock(logger_map_mutex_); + backtrace_n_messages_ = 0; + for (auto &l : loggers_) { + l.second->disable_backtrace(); + } +} + +SPDLOG_INLINE void registry::set_level(level::level_enum log_level) { + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) { + l.second->set_level(log_level); + } + global_log_level_ = log_level; +} + +SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) { + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) { + l.second->flush_on(log_level); + } + flush_level_ = log_level; +} + +SPDLOG_INLINE void registry::set_error_handler(err_handler handler) { + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) { + l.second->set_error_handler(handler); + } + err_handler_ = std::move(handler); +} + +SPDLOG_INLINE void registry::apply_all( + const std::function)> &fun) { + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) { + fun(l.second); + } +} + +SPDLOG_INLINE void registry::flush_all() { + std::lock_guard lock(logger_map_mutex_); + for (auto &l : loggers_) { + l.second->flush(); + } +} + +SPDLOG_INLINE void registry::drop(const std::string &logger_name) { + std::lock_guard lock(logger_map_mutex_); + auto is_default_logger = default_logger_ && default_logger_->name() == logger_name; + loggers_.erase(logger_name); + if (is_default_logger) { + default_logger_.reset(); + } +} + +SPDLOG_INLINE void registry::drop_all() { + std::lock_guard lock(logger_map_mutex_); + loggers_.clear(); + default_logger_.reset(); +} + +// clean all resources and threads started by the registry +SPDLOG_INLINE void registry::shutdown() { + { + std::lock_guard lock(flusher_mutex_); + periodic_flusher_.reset(); + } + + drop_all(); + + { + std::lock_guard lock(tp_mutex_); + tp_.reset(); + } +} + +SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() { return tp_mutex_; } + +SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration) { + std::lock_guard lock(logger_map_mutex_); + automatic_registration_ = automatic_registration; +} + +SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) { + std::lock_guard lock(logger_map_mutex_); + log_levels_ = std::move(levels); + auto global_level_requested = global_level != nullptr; + global_log_level_ = global_level_requested ? *global_level : global_log_level_; + + for (auto &logger : loggers_) { + auto logger_entry = log_levels_.find(logger.first); + if (logger_entry != log_levels_.end()) { + logger.second->set_level(logger_entry->second); + } else if (global_level_requested) { + logger.second->set_level(*global_level); + } + } +} + +SPDLOG_INLINE registry ®istry::instance() { + static registry s_instance; + return s_instance; +} + +SPDLOG_INLINE void registry::apply_logger_env_levels(std::shared_ptr new_logger) { + std::lock_guard lock(logger_map_mutex_); + auto it = log_levels_.find(new_logger->name()); + auto new_level = it != log_levels_.end() ? it->second : global_log_level_; + new_logger->set_level(new_level); +} + +SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) { + if (loggers_.find(logger_name) != loggers_.end()) { + throw_spdlog_ex("logger with name '" + logger_name + "' already exists"); + } +} + +SPDLOG_INLINE void registry::register_logger_(std::shared_ptr new_logger) { + auto logger_name = new_logger->name(); + throw_if_exists_(logger_name); + loggers_[logger_name] = std::move(new_logger); +} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/registry.h b/cpp_src/vendor/spdlog/details/registry.h index dd9fea848..8afcbd6f5 100644 --- a/cpp_src/vendor/spdlog/details/registry.h +++ b/cpp_src/vendor/spdlog/details/registry.h @@ -1,19 +1,15 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -// Loggers registy of unique name->logger pointer -// An attempt to create a logger with an already existing name will be ignored +// Loggers registry of unique name->logger pointer +// An attempt to create a logger with an already existing name will result with spdlog_ex exception. // If user requests a non existing logger, nullptr will be returned // This class is thread safe -#include "../details/null_mutex.h" -#include "../logger.h" -#include "../async_logger.h" -#include "../common.h" +#include +#include #include #include @@ -22,208 +18,112 @@ #include #include -namespace spdlog -{ -namespace details -{ -template -class registry_t -{ -public: - registry_t(const registry_t&) = delete; - registry_t& operator=(const registry_t&) = delete; - - void register_logger(std::shared_ptr logger) - { - std::lock_guard lock(_mutex); - auto logger_name = logger->name(); - throw_if_exists(logger_name); - _loggers[logger_name] = std::move(logger); - } +namespace spdlog { +class logger; - std::shared_ptr get(const std::string& logger_name) - { - std::lock_guard lock(_mutex); - auto found = _loggers.find(logger_name); - return found == _loggers.end() ? nullptr : found->second; - } +namespace details { +class thread_pool; - template - std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) - { - std::lock_guard lock(_mutex); - throw_if_exists(logger_name); - std::shared_ptr new_logger; - if (_async_mode) - new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb); - else - new_logger = std::make_shared(logger_name, sinks_begin, sinks_end); +class SPDLOG_API registry { +public: + using log_levels = std::unordered_map; + registry(const registry &) = delete; + registry &operator=(const registry &) = delete; - if (_formatter) - new_logger->set_formatter(_formatter); + void register_logger(std::shared_ptr new_logger); + void initialize_logger(std::shared_ptr new_logger); + std::shared_ptr get(const std::string &logger_name); + std::shared_ptr default_logger(); - if (_err_handler) - new_logger->set_error_handler(_err_handler); + // Return raw ptr to the default logger. + // To be used directly by the spdlog default api (e.g. spdlog::info) + // This make the default API faster, but cannot be used concurrently with set_default_logger(). + // e.g do not call set_default_logger() from one thread while calling spdlog::info() from + // another. + logger *get_default_raw(); - new_logger->set_level(_level); - new_logger->flush_on(_flush_level); + // set default logger and add it to the registry if not registered already. + // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. + // Note: Make sure to unregister it when no longer needed or before calling again with a new + // logger. + void set_default_logger(std::shared_ptr new_default_logger); + void set_tp(std::shared_ptr tp); - //Add to registry - _loggers[logger_name] = new_logger; - return new_logger; - } + std::shared_ptr get_tp(); - template - std::shared_ptr create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb, const It& sinks_begin, const It& sinks_end) - { - std::lock_guard lock(_mutex); - throw_if_exists(logger_name); - auto new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb); + // Set global formatter. Each sink in each logger will get a clone of this object + void set_formatter(std::unique_ptr formatter); - if (_formatter) - new_logger->set_formatter(_formatter); + void enable_backtrace(size_t n_messages); - if (_err_handler) - new_logger->set_error_handler(_err_handler); + void disable_backtrace(); - new_logger->set_level(_level); - new_logger->flush_on(_flush_level); + void set_level(level::level_enum log_level); - //Add to registry - _loggers[logger_name] = new_logger; - return new_logger; - } + void flush_on(level::level_enum log_level); - void apply_all(const std::function)>& fun) - { - std::lock_guard lock(_mutex); - for (auto &l : _loggers) - fun(l.second); + template + void flush_every(std::chrono::duration interval) { + std::lock_guard lock(flusher_mutex_); + auto clbk = [this]() { this->flush_all(); }; + periodic_flusher_ = details::make_unique(clbk, interval); } - void drop(const std::string& logger_name) - { - std::lock_guard lock(_mutex); - _loggers.erase(logger_name); + std::unique_ptr &get_flusher() { + std::lock_guard lock(flusher_mutex_); + return periodic_flusher_; } - void drop_all() - { - std::lock_guard lock(_mutex); - _loggers.clear(); - } + void set_error_handler(err_handler handler); - std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks) - { - return create(logger_name, sinks.begin(), sinks.end()); - } - - std::shared_ptr create(const std::string& logger_name, sink_ptr sink) - { - return create(logger_name, { sink }); - } + void apply_all(const std::function)> &fun); - std::shared_ptr create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb, sinks_init_list sinks) - { - return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end()); - } - - std::shared_ptr create_async(const std::string& logger_name, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb, sink_ptr sink) - { - return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, { sink }); - } + void flush_all(); - void formatter(formatter_ptr f) - { - std::lock_guard lock(_mutex); - _formatter = std::move(f); - for (auto& l : _loggers) - l.second->set_formatter(_formatter); - } + void drop(const std::string &logger_name); - void set_pattern(const std::string& pattern) - { - std::lock_guard lock(_mutex); - _formatter = std::make_shared(pattern); - for (auto& l : _loggers) - l.second->set_formatter(_formatter); - } + void drop_all(); - void set_level(level::level_enum log_level) - { - std::lock_guard lock(_mutex); - for (auto& l : _loggers) - l.second->set_level(log_level); - _level = log_level; - } + // clean all resources and threads started by the registry + void shutdown(); - void flush_on(level::level_enum log_level) - { - std::lock_guard lock(_mutex); - for (auto& l : _loggers) - l.second->flush_on(log_level); - _flush_level = log_level; - } + std::recursive_mutex &tp_mutex(); - void set_error_handler(log_err_handler handler) - { - for (auto& l : _loggers) - l.second->set_error_handler(std::move(handler)); - _err_handler = std::move(handler); - } + void set_automatic_registration(bool automatic_registration); - void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) - { - std::lock_guard lock(_mutex); - _async_mode = true; - _async_q_size = q_size; - _overflow_policy = overflow_policy; - _worker_warmup_cb = worker_warmup_cb; - _flush_interval_ms = flush_interval_ms; - _worker_teardown_cb = worker_teardown_cb; - } + // set levels for all existing/future loggers. global_level can be null if should not set. + void set_levels(log_levels levels, level::level_enum *global_level); - void set_sync_mode() - { - std::lock_guard lock(_mutex); - _async_mode = false; - } + static registry &instance(); - static registry_t& instance() - { - static registry_t s_instance; - return s_instance; - } + void apply_logger_env_levels(std::shared_ptr new_logger); private: - registry_t() = default; - - void throw_if_exists(const std::string &logger_name) - { - if (_loggers.find(logger_name) != _loggers.end()) - throw spdlog_ex("logger with name '" + logger_name + "' already exists"); - } - - Mutex _mutex; - std::unordered_map > _loggers; - formatter_ptr _formatter; - level::level_enum _level = level::info; - level::level_enum _flush_level = level::off; - log_err_handler _err_handler; - bool _async_mode = false; - size_t _async_q_size = 0; - async_overflow_policy _overflow_policy = async_overflow_policy::block_retry; - std::function _worker_warmup_cb; - std::chrono::milliseconds _flush_interval_ms; - std::function _worker_teardown_cb; + registry(); + ~registry(); + + void throw_if_exists_(const std::string &logger_name); + void register_logger_(std::shared_ptr new_logger); + bool set_level_from_cfg_(logger *logger); + std::mutex logger_map_mutex_, flusher_mutex_; + std::recursive_mutex tp_mutex_; + std::unordered_map> loggers_; + log_levels log_levels_; + std::unique_ptr formatter_; + spdlog::level::level_enum global_log_level_ = level::info; + level::level_enum flush_level_ = level::off; + err_handler err_handler_; + std::shared_ptr tp_; + std::unique_ptr periodic_flusher_; + std::shared_ptr default_logger_; + bool automatic_registration_ = true; + size_t backtrace_n_messages_ = 0; }; -#ifdef SPDLOG_NO_REGISTRY_MUTEX -using registry = registry_t; -#else -using registry = registry_t; -#endif +} // namespace details +} // namespace spdlog -} -} +#ifdef SPDLOG_HEADER_ONLY + #include "registry-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/spdlog_impl.h b/cpp_src/vendor/spdlog/details/spdlog_impl.h deleted file mode 100644 index dde9a7731..000000000 --- a/cpp_src/vendor/spdlog/details/spdlog_impl.h +++ /dev/null @@ -1,265 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// -// Global registry functions -// -#include "../spdlog.h" -#include "../details/registry.h" -#include "../sinks/file_sinks.h" -#include "../sinks/stdout_sinks.h" -#ifdef SPDLOG_ENABLE_SYSLOG -#include "../sinks/syslog_sink.h" -#endif - -#if defined _WIN32 && !defined(__cplusplus_winrt) -#include "../sinks/wincolor_sink.h" -#else -#include "../sinks/ansicolor_sink.h" -#endif - - -#ifdef __ANDROID__ -#include "../sinks/android_sink.h" -#endif - -#include -#include -#include -#include - -inline void spdlog::register_logger(std::shared_ptr logger) -{ - return details::registry::instance().register_logger(std::move(logger)); -} - -inline std::shared_ptr spdlog::get(const std::string& name) -{ - return details::registry::instance().get(name); -} - -inline void spdlog::drop(const std::string &name) -{ - details::registry::instance().drop(name); -} - -// Create multi/single threaded simple file logger -inline std::shared_ptr spdlog::basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate) -{ - return create(logger_name, filename, truncate); -} - -inline std::shared_ptr spdlog::basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate) -{ - return create(logger_name, filename, truncate); -} - -// Create multi/single threaded rotating file logger -inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) -{ - return create(logger_name, filename, max_file_size, max_files); -} - -inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files) -{ - return create(logger_name, filename, max_file_size, max_files); -} - -// Create file logger which creates new file at midnight): -inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour, int minute) -{ - return create(logger_name, filename, hour, minute); -} - -inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour, int minute) -{ - return create(logger_name, filename, hour, minute); -} - - -// -// stdout/stderr loggers -// -inline std::shared_ptr spdlog::stdout_logger_mt(const std::string& logger_name) -{ - return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance()); -} - -inline std::shared_ptr spdlog::stdout_logger_st(const std::string& logger_name) -{ - return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance()); -} - -inline std::shared_ptr spdlog::stderr_logger_mt(const std::string& logger_name) -{ - return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance()); -} - -inline std::shared_ptr spdlog::stderr_logger_st(const std::string& logger_name) -{ - return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance()); -} - -// -// stdout/stderr color loggers -// -#if defined _WIN32 && !defined(__cplusplus_winrt) - -inline std::shared_ptr spdlog::stdout_color_mt(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -inline std::shared_ptr spdlog::stdout_color_st(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -inline std::shared_ptr spdlog::stderr_color_mt(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - - -inline std::shared_ptr spdlog::stderr_color_st(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -#else //ansi terminal colors - -inline std::shared_ptr spdlog::stdout_color_mt(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -inline std::shared_ptr spdlog::stdout_color_st(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -inline std::shared_ptr spdlog::stderr_color_mt(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} - -inline std::shared_ptr spdlog::stderr_color_st(const std::string& logger_name) -{ - auto sink = std::make_shared(); - return spdlog::details::registry::instance().create(logger_name, sink); -} -#endif - -#ifdef SPDLOG_ENABLE_SYSLOG -// Create syslog logger -inline std::shared_ptr spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option, int syslog_facility) -{ - return create(logger_name, syslog_ident, syslog_option, syslog_facility); -} -#endif - -#ifdef __ANDROID__ -inline std::shared_ptr spdlog::android_logger(const std::string& logger_name, const std::string& tag) -{ - return create(logger_name, tag); -} -#endif - -// Create and register a logger a single sink -inline std::shared_ptr spdlog::create(const std::string& logger_name, const spdlog::sink_ptr& sink) -{ - return details::registry::instance().create(logger_name, sink); -} - -//Create logger with multiple sinks -inline std::shared_ptr spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks) -{ - return details::registry::instance().create(logger_name, sinks); -} - -template -inline std::shared_ptr spdlog::create(const std::string& logger_name, Args... args) -{ - sink_ptr sink = std::make_shared(args...); - return details::registry::instance().create(logger_name, { sink }); -} - -template -inline std::shared_ptr spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) -{ - return details::registry::instance().create(logger_name, sinks_begin, sinks_end); -} - -// Create and register an async logger with a single sink -inline std::shared_ptr spdlog::create_async(const std::string& logger_name, const sink_ptr& sink, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) -{ - return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sink); -} - -// Create and register an async logger with multiple sinks -inline std::shared_ptr spdlog::create_async(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb ) -{ - return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks); -} - -template -inline std::shared_ptr spdlog::create_async(const std::string& logger_name, const It& sinks_begin, const It& sinks_end, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) -{ - return details::registry::instance().create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks_begin, sinks_end); -} - -inline void spdlog::set_formatter(spdlog::formatter_ptr f) -{ - details::registry::instance().formatter(std::move(f)); -} - -inline void spdlog::set_pattern(const std::string& format_string) -{ - return details::registry::instance().set_pattern(format_string); -} - -inline void spdlog::set_level(level::level_enum log_level) -{ - return details::registry::instance().set_level(log_level); -} - -inline void spdlog::flush_on(level::level_enum log_level) -{ - return details::registry::instance().flush_on(log_level); -} - -inline void spdlog::set_error_handler(log_err_handler handler) -{ - return details::registry::instance().set_error_handler(std::move(handler)); -} - -inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms, const std::function& worker_teardown_cb) -{ - details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb); -} - -inline void spdlog::set_sync_mode() -{ - details::registry::instance().set_sync_mode(); -} - -inline void spdlog::apply_all(const std::function)>& fun) -{ - details::registry::instance().apply_all(fun); -} - -inline void spdlog::drop_all() -{ - details::registry::instance().drop_all(); -} diff --git a/cpp_src/vendor/spdlog/details/synchronous_factory.h b/cpp_src/vendor/spdlog/details/synchronous_factory.h new file mode 100644 index 000000000..4bd5a51c8 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/synchronous_factory.h @@ -0,0 +1,22 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "registry.h" + +namespace spdlog { + +// Default logger factory- creates synchronous loggers +class logger; + +struct synchronous_factory { + template + static std::shared_ptr create(std::string logger_name, SinkArgs &&...args) { + auto sink = std::make_shared(std::forward(args)...); + auto new_logger = std::make_shared(std::move(logger_name), std::move(sink)); + details::registry::instance().initialize_logger(new_logger); + return new_logger; + } +}; +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/tcp_client-windows.h b/cpp_src/vendor/spdlog/details/tcp_client-windows.h new file mode 100644 index 000000000..bf8f7b879 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/tcp_client-windows.h @@ -0,0 +1,135 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#define WIN32_LEAN_AND_MEAN +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "Ws2_32.lib") +#pragma comment(lib, "Mswsock.lib") +#pragma comment(lib, "AdvApi32.lib") + +namespace spdlog { +namespace details { +class tcp_client { + SOCKET socket_ = INVALID_SOCKET; + + static void init_winsock_() { + WSADATA wsaData; + auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rv != 0) { + throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); + } + } + + static void throw_winsock_error_(const std::string &msg, int last_error) { + char buf[512]; + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, + (sizeof(buf) / sizeof(char)), NULL); + + throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); + } + +public: + tcp_client() { init_winsock_(); } + + ~tcp_client() { + close(); + ::WSACleanup(); + } + + bool is_connected() const { return socket_ != INVALID_SOCKET; } + + void close() { + ::closesocket(socket_); + socket_ = INVALID_SOCKET; + } + + SOCKET fd() const { return socket_; } + + // try to connect or throw on failure + void connect(const std::string &host, int port) { + if (is_connected()) { + close(); + } + struct addrinfo hints {}; + ZeroMemory(&hints, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + int last_error = 0; + if (rv != 0) { + last_error = ::WSAGetLastError(); + WSACleanup(); + throw_winsock_error_("getaddrinfo failed", last_error); + } + + // Try each address until we successfully connect(2). + + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) { + socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (socket_ == INVALID_SOCKET) { + last_error = ::WSAGetLastError(); + WSACleanup(); + continue; + } + if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) { + break; + } else { + last_error = ::WSAGetLastError(); + close(); + } + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == INVALID_SOCKET) { + WSACleanup(); + throw_winsock_error_("connect failed", last_error); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), + sizeof(enable_flag)); + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) { + const int send_flags = 0; + auto write_result = + ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); + if (write_result == SOCKET_ERROR) { + int last_error = ::WSAGetLastError(); + close(); + throw_winsock_error_("send failed", last_error); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/tcp_client.h b/cpp_src/vendor/spdlog/details/tcp_client.h new file mode 100644 index 000000000..9d3c40d52 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/tcp_client.h @@ -0,0 +1,127 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 + #error include tcp_client-windows.h instead +#endif + +// tcp client helper +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { +class tcp_client { + int socket_ = -1; + +public: + bool is_connected() const { return socket_ != -1; } + + void close() { + if (is_connected()) { + ::close(socket_); + socket_ = -1; + } + } + + int fd() const { return socket_; } + + ~tcp_client() { close(); } + + // try to connect or throw on failure + void connect(const std::string &host, int port) { + close(); + struct addrinfo hints {}; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; // To work with IPv4, IPv6, and so on + hints.ai_socktype = SOCK_STREAM; // TCP + hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value + hints.ai_protocol = 0; + + auto port_str = std::to_string(port); + struct addrinfo *addrinfo_result; + auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); + if (rv != 0) { + throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); + } + + // Try each address until we successfully connect(2). + int last_errno = 0; + for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) { +#if defined(SOCK_CLOEXEC) + const int flags = SOCK_CLOEXEC; +#else + const int flags = 0; +#endif + socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); + if (socket_ == -1) { + last_errno = errno; + continue; + } + rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); + if (rv == 0) { + break; + } + last_errno = errno; + ::close(socket_); + socket_ = -1; + } + ::freeaddrinfo(addrinfo_result); + if (socket_ == -1) { + throw_spdlog_ex("::connect failed", last_errno); + } + + // set TCP_NODELAY + int enable_flag = 1; + ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&enable_flag), + sizeof(enable_flag)); + + // prevent sigpipe on systems where MSG_NOSIGNAL is not available +#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) + ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast(&enable_flag), + sizeof(enable_flag)); +#endif + +#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) + #error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available" +#endif + } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) { + size_t bytes_sent = 0; + while (bytes_sent < n_bytes) { +#if defined(MSG_NOSIGNAL) + const int send_flags = MSG_NOSIGNAL; +#else + const int send_flags = 0; +#endif + auto write_result = + ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); + if (write_result < 0) { + close(); + throw_spdlog_ex("write(2) failed", errno); + } + + if (write_result == 0) // (probably should not happen but in any case..) + { + break; + } + bytes_sent += static_cast(write_result); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/thread_pool-inl.h b/cpp_src/vendor/spdlog/details/thread_pool-inl.h new file mode 100644 index 000000000..7c0dde551 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/thread_pool-inl.h @@ -0,0 +1,142 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +namespace spdlog { +namespace details { + +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, + size_t threads_n, + std::function on_thread_start, + std::function on_thread_stop) + : q_(q_max_items) { + if (threads_n == 0 || threads_n > 1000) { + throw_spdlog_ex( + "spdlog::thread_pool(): invalid threads_n param (valid " + "range is 1-1000)"); + } + for (size_t i = 0; i < threads_n; i++) { + threads_.emplace_back([this, on_thread_start, on_thread_stop] { + on_thread_start(); + this->thread_pool::worker_loop_(); + on_thread_stop(); + }); + } +} + +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, + size_t threads_n, + std::function on_thread_start) + : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) {} + +SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) + : thread_pool( + q_max_items, threads_n, [] {}, [] {}) {} + +// message all threads to terminate gracefully join them +SPDLOG_INLINE thread_pool::~thread_pool() { + SPDLOG_TRY { + for (size_t i = 0; i < threads_.size(); i++) { + post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); + } + + for (auto &t : threads_) { + t.join(); + } + } + SPDLOG_CATCH_STD +} + +void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, + const details::log_msg &msg, + async_overflow_policy overflow_policy) { + async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); + post_async_msg_(std::move(async_m), overflow_policy); +} + +std::future SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, + async_overflow_policy overflow_policy) { + std::promise promise; + std::future future = promise.get_future(); + post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush, std::move(promise)), + overflow_policy); + return future; +} + +size_t SPDLOG_INLINE thread_pool::overrun_counter() { return q_.overrun_counter(); } + +void SPDLOG_INLINE thread_pool::reset_overrun_counter() { q_.reset_overrun_counter(); } + +size_t SPDLOG_INLINE thread_pool::discard_counter() { return q_.discard_counter(); } + +void SPDLOG_INLINE thread_pool::reset_discard_counter() { q_.reset_discard_counter(); } + +size_t SPDLOG_INLINE thread_pool::queue_size() { return q_.size(); } + +void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, + async_overflow_policy overflow_policy) { + switch(overflow_policy) { + case async_overflow_policy::block: + q_.enqueue(std::move(new_msg)); + break; + case async_overflow_policy::overrun_oldest: + q_.enqueue_nowait(std::move(new_msg)); + break; + case async_overflow_policy::discard_new: + // This check is essential to avoid deadlock on termination + if (new_msg.msg_type != async_msg_type::terminate && new_msg.msg_type != async_msg_type::flush) { + q_.enqueue_if_have_room(std::move(new_msg)); + } else { + q_.enqueue(std::move(new_msg)); + } + break; + default: + assert(false); + } +} + +void SPDLOG_INLINE thread_pool::worker_loop_() { + while (process_next_msg_()) { + } +} + +// process next message in the queue +// return true if this thread should still be active (while no terminate msg +// was received) +bool SPDLOG_INLINE thread_pool::process_next_msg_() { + async_msg incoming_async_msg; + q_.dequeue(incoming_async_msg); + + switch (incoming_async_msg.msg_type) { + case async_msg_type::log: { + incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); + return true; + } + case async_msg_type::flush: { + incoming_async_msg.worker_ptr->backend_flush_(); + incoming_async_msg.flush_promise.set_value(); + return true; + } + + case async_msg_type::terminate: { + return false; + } + + default: { + assert(false); + } + } + + return true; +} + +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/thread_pool.h b/cpp_src/vendor/spdlog/details/thread_pool.h new file mode 100644 index 000000000..0d56a091c --- /dev/null +++ b/cpp_src/vendor/spdlog/details/thread_pool.h @@ -0,0 +1,128 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +class async_logger; + +namespace details { + +using async_logger_ptr = std::shared_ptr; + +enum class async_msg_type { log, flush, terminate }; + +// Async msg to move to/from the queue +// Movable only. should never be copied +struct async_msg : log_msg_buffer { + async_msg_type msg_type{async_msg_type::log}; + async_logger_ptr worker_ptr; + std::promise flush_promise; + + async_msg() = default; + ~async_msg() = default; + + // should only be moved in or out of the queue.. + async_msg(const async_msg &) = delete; + +// support for vs2013 move +#if defined(_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&other) + : log_msg_buffer(std::move(other)), + msg_type(other.msg_type), + worker_ptr(std::move(other.worker_ptr)) {} + + async_msg &operator=(async_msg &&other) { + *static_cast(this) = std::move(other); + msg_type = other.msg_type; + worker_ptr = std::move(other.worker_ptr); + return *this; + } +#else // (_MSC_VER) && _MSC_VER <= 1800 + async_msg(async_msg &&) = default; + async_msg &operator=(async_msg &&) = default; +#endif + + // construct from log_msg with given type + async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) + : log_msg_buffer{m}, + msg_type{the_type}, + worker_ptr{std::move(worker)}, + flush_promise{} {} + + async_msg(async_logger_ptr &&worker, async_msg_type the_type) + : log_msg_buffer{}, + msg_type{the_type}, + worker_ptr{std::move(worker)}, + flush_promise{} {} + + async_msg(async_logger_ptr &&worker, async_msg_type the_type, std::promise &&promise) + : log_msg_buffer{}, + msg_type{the_type}, + worker_ptr{std::move(worker)}, + flush_promise{std::move(promise)} {} + + explicit async_msg(async_msg_type the_type) + : async_msg{nullptr, the_type} {} +}; + +class SPDLOG_API thread_pool { +public: + using item_type = async_msg; + using q_type = details::mpmc_blocking_queue; + + thread_pool(size_t q_max_items, + size_t threads_n, + std::function on_thread_start, + std::function on_thread_stop); + thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start); + thread_pool(size_t q_max_items, size_t threads_n); + + // message all threads to terminate gracefully and join them + ~thread_pool(); + + thread_pool(const thread_pool &) = delete; + thread_pool &operator=(thread_pool &&) = delete; + + void post_log(async_logger_ptr &&worker_ptr, + const details::log_msg &msg, + async_overflow_policy overflow_policy); + std::future post_flush(async_logger_ptr &&worker_ptr, + async_overflow_policy overflow_policy); + size_t overrun_counter(); + void reset_overrun_counter(); + size_t discard_counter(); + void reset_discard_counter(); + size_t queue_size(); + +private: + q_type q_; + + std::vector threads_; + + void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); + void worker_loop_(); + + // process next message in the queue + // return true if this thread should still be active (while no terminate msg + // was received) + bool process_next_msg_(); +}; + +} // namespace details +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "thread_pool-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/details/udp_client-windows.h b/cpp_src/vendor/spdlog/details/udp_client-windows.h new file mode 100644 index 000000000..8b7c22324 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/udp_client-windows.h @@ -0,0 +1,98 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over winsock udp client socket. +// Will throw on construction if socket creation failed. + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) + #pragma comment(lib, "Ws2_32.lib") + #pragma comment(lib, "Mswsock.lib") + #pragma comment(lib, "AdvApi32.lib") +#endif + +namespace spdlog { +namespace details { +class udp_client { + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + SOCKET socket_ = INVALID_SOCKET; + sockaddr_in addr_ = {}; + + static void init_winsock_() { + WSADATA wsaData; + auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); + if (rv != 0) { + throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); + } + } + + static void throw_winsock_error_(const std::string &msg, int last_error) { + char buf[512]; + ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, + last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, + (sizeof(buf) / sizeof(char)), NULL); + + throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); + } + + void cleanup_() { + if (socket_ != INVALID_SOCKET) { + ::closesocket(socket_); + } + socket_ = INVALID_SOCKET; + ::WSACleanup(); + } + +public: + udp_client(const std::string &host, uint16_t port) { + init_winsock_(); + + addr_.sin_family = PF_INET; + addr_.sin_port = htons(port); + addr_.sin_addr.s_addr = INADDR_ANY; + if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Invalid address!", last_error); + } + + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ == INVALID_SOCKET) { + int last_error = ::WSAGetLastError(); + ::WSACleanup(); + throw_winsock_error_("error: Create Socket failed", last_error); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, + reinterpret_cast(&option_value), sizeof(option_value)) < 0) { + int last_error = ::WSAGetLastError(); + cleanup_(); + throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); + } + } + + ~udp_client() { cleanup_(); } + + SOCKET fd() const { return socket_; } + + void send(const char *data, size_t n_bytes) { + socklen_t tolen = sizeof(struct sockaddr); + if (::sendto(socket_, data, static_cast(n_bytes), 0, (struct sockaddr *)&addr_, + tolen) == -1) { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/udp_client.h b/cpp_src/vendor/spdlog/details/udp_client.h new file mode 100644 index 000000000..95826f5d9 --- /dev/null +++ b/cpp_src/vendor/spdlog/details/udp_client.h @@ -0,0 +1,81 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Helper RAII over unix udp client socket. +// Will throw on construction if the socket creation failed. + +#ifdef _WIN32 + #error "include udp_client-windows.h instead" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace spdlog { +namespace details { + +class udp_client { + static constexpr int TX_BUFFER_SIZE = 1024 * 10; + int socket_ = -1; + struct sockaddr_in sockAddr_; + + void cleanup_() { + if (socket_ != -1) { + ::close(socket_); + socket_ = -1; + } + } + +public: + udp_client(const std::string &host, uint16_t port) { + socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); + if (socket_ < 0) { + throw_spdlog_ex("error: Create Socket Failed!"); + } + + int option_value = TX_BUFFER_SIZE; + if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, + reinterpret_cast(&option_value), sizeof(option_value)) < 0) { + cleanup_(); + throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); + } + + sockAddr_.sin_family = AF_INET; + sockAddr_.sin_port = htons(port); + + if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) { + cleanup_(); + throw_spdlog_ex("error: Invalid address!"); + } + + ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); + } + + ~udp_client() { cleanup_(); } + + int fd() const { return socket_; } + + // Send exactly n_bytes of the given data. + // On error close the connection and throw. + void send(const char *data, size_t n_bytes) { + ssize_t toslen = 0; + socklen_t tolen = sizeof(struct sockaddr); + if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == + -1) { + throw_spdlog_ex("sendto(2) failed", errno); + } + } +}; +} // namespace details +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/details/windows_include.h b/cpp_src/vendor/spdlog/details/windows_include.h new file mode 100644 index 000000000..bbab59b1c --- /dev/null +++ b/cpp_src/vendor/spdlog/details/windows_include.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef NOMINMAX + #define NOMINMAX // prevent windows redefining min/max +#endif + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif + +#include diff --git a/cpp_src/vendor/spdlog/fmt/bin_to_hex.h b/cpp_src/vendor/spdlog/fmt/bin_to_hex.h new file mode 100644 index 000000000..c2998d57a --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/bin_to_hex.h @@ -0,0 +1,224 @@ +// +// Copyright(c) 2015 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once + +#include +#include + +#if defined(__has_include) + #if __has_include() + #include + #endif +#endif + +#if __cpp_lib_span >= 202002L + #include +#endif + +// +// Support for logging binary data as hex +// format flags, any combination of the following: +// {:X} - print in uppercase. +// {:s} - don't separate each byte with space. +// {:p} - don't print the position on each line start. +// {:n} - don't split the output to lines. +// {:a} - show ASCII if :n is not set + +// +// Examples: +// +// std::vector v(200, 0x0b); +// logger->info("Some buffer {}", spdlog::to_hex(v)); +// char buf[128]; +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf))); +// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16)); + +namespace spdlog { +namespace details { + +template +class dump_info { +public: + dump_info(It range_begin, It range_end, size_t size_per_line) + : begin_(range_begin), + end_(range_end), + size_per_line_(size_per_line) {} + + // do not use begin() and end() to avoid collision with fmt/ranges + It get_begin() const { return begin_; } + It get_end() const { return end_; } + size_t size_per_line() const { return size_per_line_; } + +private: + It begin_, end_; + size_t size_per_line_; +}; +} // namespace details + +// create a dump_info that wraps the given container +template +inline details::dump_info to_hex(const Container &container, + size_t size_per_line = 32) { + static_assert(sizeof(typename Container::value_type) == 1, + "sizeof(Container::value_type) != 1"); + using Iter = typename Container::const_iterator; + return details::dump_info(std::begin(container), std::end(container), size_per_line); +} + +#if __cpp_lib_span >= 202002L + +template +inline details::dump_info::iterator> to_hex( + const std::span &container, size_t size_per_line = 32) { + using Container = std::span; + static_assert(sizeof(typename Container::value_type) == 1, + "sizeof(Container::value_type) != 1"); + using Iter = typename Container::iterator; + return details::dump_info(std::begin(container), std::end(container), size_per_line); +} + +#endif + +// create dump_info from ranges +template +inline details::dump_info to_hex(const It range_begin, + const It range_end, + size_t size_per_line = 32) { + return details::dump_info(range_begin, range_end, size_per_line); +} + +} // namespace spdlog + +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ + +template +struct formatter, char> { + const char delimiter = ' '; + bool put_newlines = true; + bool put_delimiters = true; + bool use_uppercase = false; + bool put_positions = true; // position on start of each line + bool show_ascii = false; + + // parse the format string flags + template + SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + while (it != ctx.end() && *it != '}') { + switch (*it) { + case 'X': + use_uppercase = true; + break; + case 's': + put_delimiters = false; + break; + case 'p': + put_positions = false; + break; + case 'n': + put_newlines = false; + show_ascii = false; + break; + case 'a': + if (put_newlines) { + show_ascii = true; + } + break; + } + + ++it; + } + return it; + } + + // format the given bytes range as hex + template + auto format(const spdlog::details::dump_info &the_range, FormatContext &ctx) const + -> decltype(ctx.out()) { + SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; + SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; + const char *hex_chars = use_uppercase ? hex_upper : hex_lower; + +#if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000 + auto inserter = ctx.begin(); +#else + auto inserter = ctx.out(); +#endif + + int size_per_line = static_cast(the_range.size_per_line()); + auto start_of_line = the_range.get_begin(); + for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) { + auto ch = static_cast(*i); + + if (put_newlines && + (i == the_range.get_begin() || i - start_of_line >= size_per_line)) { + if (show_ascii && i != the_range.get_begin()) { + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j < i; j++) { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } + } + + put_newline(inserter, static_cast(i - the_range.get_begin())); + + // put first byte without delimiter in front of it + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + start_of_line = i; + continue; + } + + if (put_delimiters && i != the_range.get_begin()) { + *inserter++ = delimiter; + } + + *inserter++ = hex_chars[(ch >> 4) & 0x0f]; + *inserter++ = hex_chars[ch & 0x0f]; + } + if (show_ascii) // add ascii to last line + { + if (the_range.get_end() - the_range.get_begin() > size_per_line) { + auto blank_num = size_per_line - (the_range.get_end() - start_of_line); + while (blank_num-- > 0) { + *inserter++ = delimiter; + *inserter++ = delimiter; + if (put_delimiters) { + *inserter++ = delimiter; + } + } + } + *inserter++ = delimiter; + *inserter++ = delimiter; + for (auto j = start_of_line; j != the_range.get_end(); j++) { + auto pc = static_cast(*j); + *inserter++ = std::isprint(pc) ? static_cast(*j) : '.'; + } + } + return inserter; + } + + // put newline(and position header) + template + void put_newline(It inserter, std::size_t pos) const { +#ifdef _WIN32 + *inserter++ = '\r'; +#endif + *inserter++ = '\n'; + + if (put_positions) { + spdlog::fmt_lib::format_to(inserter, SPDLOG_FMT_STRING("{:04X}: "), pos); + } + } +}; +} // namespace std diff --git a/cpp_src/vendor/spdlog/fmt/bundled/LICENSE.rst b/cpp_src/vendor/spdlog/fmt/bundled/LICENSE.rst deleted file mode 100644 index eb6be6503..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/LICENSE.rst +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2012 - 2016, 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. diff --git a/cpp_src/vendor/spdlog/fmt/bundled/format.cc b/cpp_src/vendor/spdlog/fmt/bundled/format.cc deleted file mode 100644 index 452cb5507..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/format.cc +++ /dev/null @@ -1,431 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, 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. - */ - -#include "format.h" - -#include - -#include -#include -#include -#include -#include -#include // for std::ptrdiff_t - -#if defined(_WIN32) && defined(__MINGW32__) -#include -#endif - -#if FMT_USE_WINDOWS_H -#if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) -#define WIN32_LEAN_AND_MEAN -#endif -#if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -#include -#else -#define NOMINMAX -#include -#undef NOMINMAX -#endif -#endif - -#if FMT_EXCEPTIONS -#define FMT_TRY try -#define FMT_CATCH(x) catch (x) -#else -#define FMT_TRY if (true) -#define FMT_CATCH(x) if (false) -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -#pragma warning(disable : 4996) -#endif - -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_r(int, char *, ...) { return fmt::internal::Null<>(); } -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { return fmt::internal::Null<>(); } - -namespace fmt { - -FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} -FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} - -namespace { - -#ifndef _MSC_VER -#define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -#define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -#define FMT_SWPRINTF snwprintf -#else -#define FMT_SWPRINTF swprintf -#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(Writer &, int, StringRef); - -// 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 safe_strerror(int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char *&buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int handle(char *message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(internal::Null<>) { return fallback(strerror_s(buffer_, buffer_size_, error_code_)); } - - // Fallback to strerror_s when strerror_r is not available. - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result; - } - -#ifdef __c2__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(internal::Null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - -#ifdef __c2__ -#pragma clang diagnostic pop -#endif - - public: - StrError(int err_code, char *&buf, std::size_t buf_size) : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); } - }; - return StrError(error_code, buffer, buffer_size).run(); -} - -void format_error_code(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - typedef internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(error_code); - if (internal::is_negative(error_code)) { - abs_value = 0 - abs_value; - ++error_code_size; - } - error_code_size += internal::count_digits(abs_value); - if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; - out << ERROR_STR << error_code; - assert(out.size() <= internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, int error_code, StringRef message) FMT_NOEXCEPT { - MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} -} // namespace - -FMT_FUNC void SystemError::init(int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - format_system_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -template -int internal::CharTraits::format_float(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 internal::CharTraits::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, - T value) { - if (width == 0) { - return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value) : FMT_SWPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? FMT_SWPRINTF(buffer, size, format, width, value) : FMT_SWPRINTF(buffer, size, format, width, precision, value); -} - -template -const char internal::BasicData::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 - -template -const uint32_t internal::BasicData::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)}; - -template -const uint64_t internal::BasicData::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 constant - // to avoid warnings about C++98 not supporting long long. - ULongLong(1000000000) * ULongLong(1000000000) * 10}; - -#if FMT_USE_WINDOWS_H - -FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); - int s_size = static_cast(s.size()); - int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); - if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); - length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); - if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; -} - -FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { - if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; - int s_size = static_cast(s.size()); - int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); - if (length == 0) return GetLastError(); - buffer_.resize(length + 1); - length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); - if (length == 0) return GetLastError(); - buffer_[length] = 0; - return 0; -} - -FMT_FUNC void WindowsError::init(int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -FMT_FUNC void internal::format_windows_error(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - wchar_t *system_message = &buffer[0]; - int result = - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL, error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast(buffer.size()), FMT_NULL); - if (result != 0) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - break; - } - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } - FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void format_system_error(Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - internal::MemoryBuffer buffer; - buffer.resize(internal::INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } - FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -template -void internal::FixedBuffer::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(unsigned arg_index, const char *&error) { - internal::Arg arg = args_[arg_index]; - switch (arg.type) { - case internal::Arg::NONE: - error = "argument index out of range"; - break; - case internal::Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - break; - case internal::Arg::INT: - case internal::Arg::UINT: - case internal::Arg::LONG_LONG: - case internal::Arg::ULONG_LONG: - case internal::Arg::BOOL: - case internal::Arg::CHAR: - case internal::Arg::DOUBLE: - case internal::Arg::LONG_DOUBLE: - case internal::Arg::CSTRING: - case internal::Arg::STRING: - case internal::Arg::WSTRING: - case internal::Arg::POINTER: - case internal::Arg::CUSTOM: - /*nothing*/; - } - return arg; -} - -FMT_FUNC void report_system_error(int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(format_system_error, error_code, message); -} - -#if FMT_USE_WINDOWS_H -FMT_FUNC void report_windows_error(int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } - -FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = static_cast('0' + c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -#ifndef FMT_HEADER_ONLY - -template struct internal::BasicData; - -// Explicit instantiations for char. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float(char *buffer, std::size_t size, const char *format, unsigned width, - int precision, double value); - -template FMT_API int internal::CharTraits::format_float(char *buffer, std::size_t size, const char *format, unsigned width, - int precision, long double value); - -// Explicit instantiations for wchar_t. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, - int precision, double value); - -template FMT_API int internal::CharTraits::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, - int precision, long double value); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/cpp_src/vendor/spdlog/fmt/bundled/format.h b/cpp_src/vendor/spdlog/fmt/bundled/format.h deleted file mode 100644 index f4959cf00..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/format.h +++ /dev/null @@ -1,3972 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, 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_ - -#define FMT_INCLUDE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for std::pair -#include -#undef FMT_INCLUDE - -// The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 40100 - -#if defined(__has_include) -#define FMT_HAS_INCLUDE(x) __has_include(x) -#else -#define FMT_HAS_INCLUDE(x) 0 -#endif - -#if (FMT_HAS_INCLUDE() && __cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) -#include -#define FMT_HAS_STRING_VIEW 1 -#else -#define FMT_HAS_STRING_VIEW 0 -#endif - -#if defined _SECURE_SCL && _SECURE_SCL -#define FMT_SECURE_SCL _SECURE_SCL -#else -#define FMT_SECURE_SCL 0 -#endif - -#if FMT_SECURE_SCL -#include -#endif - -#ifdef _MSC_VER -#define FMT_MSC_VER _MSC_VER -#else -#define FMT_MSC_VER 0 -#endif - -#if FMT_MSC_VER && FMT_MSC_VER <= 1500 -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int64 intmax_t; -#else -#include -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -#ifdef FMT_EXPORT -#define FMT_API __declspec(dllexport) -#elif defined(FMT_SHARED) -#define FMT_API __declspec(dllimport) -#endif -#endif -#ifndef FMT_API -#define FMT_API -#endif - -#ifdef __GNUC__ -#define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#define FMT_GCC_EXTENSION __extension__ -#if FMT_GCC_VERSION >= 406 -#pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -#pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -#pragma GCC diagnostic ignored "-Wshadow" -// Disable the warning about implicit conversions that may change the sign of -// an integer; silencing it otherwise would require many explicit casts. -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif -#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -#define FMT_HAS_GXX_CXX11 1 -#endif -#else -#define FMT_GCC_VERSION 0 -#define FMT_GCC_EXTENSION -#define FMT_HAS_GXX_CXX11 0 -#endif - -#if defined(__INTEL_COMPILER) -#define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -#define FMT_ICC_VERSION __ICL -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -#define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -#pragma clang diagnostic ignored "-Wpadded" -#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 - -#ifdef __has_cpp_attribute -#define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -#define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused) -#define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -// VC++ 1910 support /std: option and that will set _MSVC_LANG macro -// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro -#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910 -#define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -#endif - -#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -#define FMT_MAYBE_UNUSED [[maybe_unused]] -// g++/clang++ also support [[gnu::unused]]. However, we don't use it. -#elif defined(__GNUC__) -#define FMT_MAYBE_UNUSED __attribute__((unused)) -#else -#define FMT_MAYBE_UNUSED -#endif - -// Use the compiler's attribute noreturn -#define FMT_NORETURN [[noreturn]] - -#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 && FMT_HAS_GXX_CXX11) || FMT_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 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) -#endif -#endif - -#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 -#define FMT_USE_ALLOCATOR_TRAITS 1 -#else -#define FMT_USE_ALLOCATOR_TRAITS 0 -#endif - -// Check if exceptions are disabled. -#if defined(__GNUC__) && !defined(__EXCEPTIONS) -#define FMT_EXCEPTIONS 0 -#endif -#if FMT_MSC_VER && !_HAS_EXCEPTIONS -#define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -#define FMT_EXCEPTIONS 1 -#endif - -#ifndef FMT_THROW -#if FMT_EXCEPTIONS -#define FMT_THROW(x) throw x -#else -#define FMT_THROW(x) assert(false) -#endif -#endif - -// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -#define FMT_USE_NOEXCEPT 0 -#endif - -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 -#define FMT_DETECTED_NOEXCEPT noexcept -#else -#define FMT_DETECTED_NOEXCEPT throw() -#endif - -#ifndef FMT_NOEXCEPT -#if FMT_EXCEPTIONS -#define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT -#else -#define FMT_NOEXCEPT -#endif -#endif - -// This is needed because GCC still uses throw() in its headers when exceptions -// are disabled. -#if FMT_GCC_VERSION -#define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT -#else -#define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT -#endif - -#ifndef FMT_OVERRIDE -#if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 -#define FMT_OVERRIDE override -#else -#define FMT_OVERRIDE -#endif -#endif - -#ifndef FMT_NULL -#if FMT_HAS_FEATURE(cxx_nullptr) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 -#define FMT_NULL nullptr -#else -#define FMT_NULL NULL -#endif -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef FMT_USE_DELETED_FUNCTIONS -#define FMT_USE_DELETED_FUNCTIONS 0 -#endif - -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1800 -#define FMT_DELETED_OR_UNDEFINED = delete -#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &) = delete; \ - TypeName &operator=(const TypeName &) = delete -#else -#define FMT_DELETED_OR_UNDEFINED -#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName &); \ - TypeName &operator=(const TypeName &) -#endif - -#ifndef FMT_USE_DEFAULTED_FUNCTIONS -#define FMT_USE_DEFAULTED_FUNCTIONS 0 -#endif - -#ifndef FMT_DEFAULTED_COPY_CTOR -#if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1800 -#define FMT_DEFAULTED_COPY_CTOR(TypeName) TypeName(const TypeName &) = default; -#else -#define FMT_DEFAULTED_COPY_CTOR(TypeName) -#endif -#endif - -#ifndef FMT_USE_USER_DEFINED_LITERALS -// All compilers which support UDLs also support variadic templates. This -// makes the fmt::literals implementation easier. However, an explicit check -// for variadic templates is added here just in case. -// For Intel's compiler both it and the system gcc/msc must support UDLs. -#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ - (FMT_HAS_FEATURE(cxx_user_literals) || (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ - (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) -#define FMT_USE_USER_DEFINED_LITERALS 1 -#else -#define FMT_USE_USER_DEFINED_LITERALS 0 -#endif -#endif - -#ifndef FMT_USE_EXTERN_TEMPLATES -#define FMT_USE_EXTERN_TEMPLATES (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) -#endif - -#ifdef FMT_HEADER_ONLY -// If header only do not use extern templates. -#undef FMT_USE_EXTERN_TEMPLATES -#define FMT_USE_EXTERN_TEMPLATES 0 -#endif - -#ifndef FMT_ASSERT -#define FMT_ASSERT(condition, message) assert((condition) && message) -#endif - -// __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#ifndef _MSC_VER -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -#define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -#define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif -#endif - -// Some compilers masquerade as both MSVC and GCC-likes or -// otherwise support __builtin_clz and __builtin_clzll, so -// only define FMT_BUILTIN_CLZ using the MSVC intrinsics -// if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) -#include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -#ifndef __clang__ -#pragma intrinsic(_BitScanReverse) -#endif -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -#pragma warning(suppress : 6102) - return 31 - r; -} -#define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -#if defined(_WIN64) && !defined(__clang__) -#pragma intrinsic(_BitScanReverse64) -#endif - -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -#ifdef _WIN64 - _BitScanReverse64(&r, x); -#else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -#endif - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -#pragma warning(suppress : 6102) - return 63 - r; -} -#define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} // namespace internal -} // namespace fmt -#endif - -namespace fmt { -namespace internal { -struct DummyInt { - int data[2]; - operator int() const { return 0; } -}; -typedef std::numeric_limits FPUtil; - -// Dummy implementations of system functions such as signbit and ecvt called -// if the latter are not available. -inline DummyInt signbit(...) { return DummyInt(); } -inline DummyInt _ecvt_s(...) { return DummyInt(); } -inline DummyInt isinf(...) { return DummyInt(); } -inline DummyInt _finite(...) { return DummyInt(); } -inline DummyInt isnan(...) { return DummyInt(); } -inline DummyInt _isnan(...) { return DummyInt(); } - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -template -inline T const_check(T value) { - return value; -} -} // namespace internal -} // namespace fmt - -namespace std { // -V1061 -// Standard permits specialization of std::numeric_limits. This specialization -// is used to resolve ambiguity between isinf and std::isinf in glibc: -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 -// and the same for isnan and signbit. -template <> -class numeric_limits : public std::numeric_limits { -public: - // Portable version of isinf. - template - static bool isinfinity(T x) { - using namespace fmt::internal; - // The resolution "priority" is: - // isinf macro > std::isinf > ::isinf > fmt::internal::isinf - if (const_check(sizeof(isinf(x)) == sizeof(bool) || sizeof(isinf(x)) == sizeof(int))) { - return isinf(x) != 0; - } - return !_finite(static_cast(x)); - } - - // Portable version of isnan. - template - static bool isnotanumber(T x) { - using namespace fmt::internal; - if (const_check(sizeof(isnan(x)) == sizeof(bool) || sizeof(isnan(x)) == sizeof(int))) { - return isnan(x) != 0; - } - return _isnan(static_cast(x)) != 0; - } - - // Portable version of signbit. - static bool isnegative(double x) { - using namespace fmt::internal; - if (const_check(sizeof(signbit(x)) == sizeof(bool) || sizeof(signbit(x)) == sizeof(int))) { - return signbit(x) != 0; - } - if (x < 0) return true; - if (!isnotanumber(x)) return false; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); - return sign != 0; - } -}; -} // namespace std - -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 ArgFormatter; - -struct FormatSpec; - -template -class BasicPrintfArgFormatter; - -template > -class BasicFormatter; - -/** - \rst - A string reference. It can be constructed from a C string or - ``std::basic_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_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicStringRef { -private: - const Char *data_; - std::size_t size_; - -public: - /** Constructs a string reference object from a C string and a size. */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ - BasicStringRef(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicStringRef(const std::basic_string, Allocator> &s) : data_(s.c_str()), size_(s.size()) {} - -#if FMT_HAS_STRING_VIEW - /** - \rst - Constructs a string reference from a ``std::basic_string_view`` object. - \endrst - */ - BasicStringRef(const std::basic_string_view> &s) : data_(s.data()), size_(s.size()) {} - - /** - \rst - Converts a string reference to an ``std::string_view`` object. - \endrst - */ - explicit operator std::basic_string_view() const FMT_NOEXCEPT { return std::basic_string_view(data_, size_); } -#endif - - /** - \rst - Converts a string reference to an ``std::string`` object. - \endrst - */ - std::basic_string to_string() const { return std::basic_string(data_, size_); } - - /** Returns a pointer to the string data. */ - const Char *data() const { return data_; } - - /** Returns the string size. */ - std::size_t size() const { return size_; } - - // Lexicographically compare this string reference to other. - int compare(BasicStringRef other) const { - std::size_t size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, size); - if (result == 0) result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) == 0; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) != 0; } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) < 0; } - friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) <= 0; } - friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) > 0; } - friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) >= 0; } -}; - -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; - -/** - \rst - A reference to a null terminated string. It can be constructed from a C - string or ``std::basic_string``. - - You can use one of the following typedefs for common character types: - - +-------------+--------------------------+ - | Type | Definition | - +=============+==========================+ - | CStringRef | BasicCStringRef | - +-------------+--------------------------+ - | WCStringRef | BasicCStringRef | - +-------------+--------------------------+ - - 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(CStringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicCStringRef { -private: - const Char *data_; - -public: - /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char *s) : data_(s) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicCStringRef(const std::basic_string, Allocator> &s) : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char *c_str() const { return data_; } -}; - -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; - -/** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { -public: - explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} - FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} - ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE {} -}; - -namespace internal { - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. -template -struct MakeUnsigned { - typedef T Type; -}; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { \ - typedef U Type; \ - } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -// Casts nonnegative integer to unsigned. -template -inline typename MakeUnsigned::Type to_unsigned(Int value) { - FMT_ASSERT(value >= 0, "negative value"); - return static_cast::Type>(value); -} - -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. -enum { INLINE_BUFFER_SIZE = 500 }; - -#if FMT_SECURE_SCL -// Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else -template -inline T *make_ptr(T *ptr, std::size_t) { - return ptr; -} -#endif -} // namespace internal - -/** - \rst - A buffer supporting a subset of ``std::vector``'s operations. - \endrst - */ -template -class Buffer { -private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - -protected: - T *ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} - - /** - \rst - Increases the buffer capacity to hold at least *size* elements updating - ``ptr_`` and ``capacity_``. - \endrst - */ - virtual void grow(std::size_t size) = 0; - -public: - virtual ~Buffer() {} - - /** Returns the size of this buffer. */ - std::size_t size() const { return size_; } - - /** Returns the capacity of this buffer. */ - std::size_t capacity() const { return capacity_; } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void resize(std::size_t new_size) { - if (new_size > capacity_) grow(new_size); - size_ = new_size; - } - - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ - void reserve(std::size_t capacity) { - if (capacity > capacity_) grow(capacity); - } - - void clear() FMT_NOEXCEPT { size_ = 0; } - - void push_back(const T &value) { - if (size_ == capacity_) grow(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template - void append(const U *begin, const U *end); - - T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const { return ptr_[index]; } -}; - -template -template -void Buffer::append(const U *begin, const U *end) { - FMT_ASSERT(end >= begin, "negative value"); - std::size_t new_size = size_ + static_cast(end - begin); - if (new_size > capacity_) grow(new_size); - std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); - size_ = new_size; -} - -namespace internal { - -// A memory buffer for trivially copyable/constructible types with the first -// SIZE elements stored in the object itself. -template > -class MemoryBuffer : private Allocator, public Buffer { -private: - T data_[SIZE]; - - // Deallocate memory allocated by the buffer. - void deallocate() { - if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); - } - -protected: - void grow(std::size_t size) FMT_OVERRIDE; - -public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() FMT_OVERRIDE { deallocate(); } - -#if FMT_USE_RVALUE_REFERENCES -private: - // Move data from other to this buffer. - void move(MemoryBuffer &other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::uninitialized_copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.ptr_ = other.data_; - } - } - -public: - MemoryBuffer(MemoryBuffer &&other) { move(other); } - - MemoryBuffer &operator=(MemoryBuffer &&other) { - assert(this != &other); - deallocate(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return *this; } -}; - -template -void MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; - if (size > new_capacity) new_capacity = size; -#if FMT_USE_ALLOCATOR_TRAITS - T *new_ptr = std::allocator_traits::allocate(*this, new_capacity, FMT_NULL); -#else - T *new_ptr = this->allocate(new_capacity, FMT_NULL); -#endif - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) Allocator::deallocate(old_ptr, old_capacity); -} - -// A fixed-size buffer. -template -class FixedBuffer : public fmt::Buffer { -public: - FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} - -protected: - FMT_API void grow(std::size_t size) FMT_OVERRIDE; -}; - -template -class BasicCharTraits { -public: -#if FMT_SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif - static Char cast(int value) { return static_cast(value); } -}; - -template -class CharTraits; - -template <> -class CharTraits : public BasicCharTraits { -private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - -public: - static char convert(char value) { return value; } - - // Formats a floating-point number. - template - FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float(char *buffer, std::size_t size, const char *format, unsigned width, - int precision, double value); -extern template int CharTraits::format_float(char *buffer, std::size_t size, const char *format, unsigned width, - int precision, long double value); -#endif - -template <> -class CharTraits : public BasicCharTraits { -public: - static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) { return value; } - - template - FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, - int precision, double value); -extern template int CharTraits::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, - int precision, long double value); -#endif - -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool is_negative(T value) { - return value < 0; - } -}; - -template <> -struct SignChecker { - template - static bool is_negative(T) { - return false; - } -}; - -// 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 is_negative(T value) { - return SignChecker::is_signed>::is_negative(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; -}; - -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; -}; - -FMT_NORETURN static void report_unknown_type(char code, const char *type); - -// Static data is placed in this class template to allow header-only -// configuration. -template -struct FMT_API BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template struct BasicData; -#endif - -typedef BasicData<> Data; - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(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 - -#ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { - int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// A functor that doesn't add a thousands separator. -struct NoThousandsSep { - template - void operator()(Char *) {} -}; - -// A functor that adds a thousands separator. -class ThousandsSep { -private: - fmt::StringRef sep_; - - // Index of a decimal digit with the least significant digit having index 0. - unsigned digit_index_; - -public: - explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} - - template - void operator()(Char *&buffer) { - if (++digit_index_ % 3 != 0) return; - buffer -= sep_.size(); - std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), internal::make_ptr(buffer, sep_.size())); - } -}; - -// Formats a decimal unsigned integer value writing into buffer. -// thousands_sep is a functor that is called after writing each char to -// add a thousands separator if necessary. -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, ThousandsSep thousands_sep) { - buffer += 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 = static_cast((value % 100) * 2); - value /= 100; - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; - thousands_sep(buffer); - } - if (value < 10) { - *--buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; -} - -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - format_decimal(buffer, value, num_digits, NoThousandsSep()); - return; -} - -#ifndef _WIN32 -#define FMT_USE_WINDOWS_H 0 -#elif !defined(FMT_USE_WINDOWS_H) -#define FMT_USE_WINDOWS_H 1 -#endif - -// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. -// All the functionality that relies on it will be disabled too. -#if FMT_USE_WINDOWS_H -// A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { -private: - MemoryBuffer buffer_; - -public: - FMT_API 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 support UTF-8 natively. -class UTF16ToUTF8 { -private: - MemoryBuffer buffer_; - -public: - UTF16ToUTF8() {} - FMT_API 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 conversion error. This method may still throw - // in case of memory allocation error. - FMT_API int convert(WStringRef s); -}; - -FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; -#endif - -// A formatting argument value. -struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)(void *formatter, const void *arg, void *format_str_ptr); - - 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; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; - - enum Type { - NONE, - NAMED_ARG, - // Integer types should go first, - INT, - UINT, - LONG_LONG, - ULONG_LONG, - BOOL, - CHAR, - LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, - LONG_DOUBLE, - LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, - STRING, - WSTRING, - POINTER, - CUSTOM - }; -}; - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in internal::MemoryBuffer. -struct Arg : Value { - Type type; -}; - -template -struct NamedArg; -template -struct NamedArgWithType; - -template -struct Null {}; - -// A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. -template -struct WCharHelper { - typedef Null Supported; - typedef T Unsupported; -}; - -template -struct WCharHelper { - typedef T Supported; - typedef Null Unsupported; -}; - -typedef char Yes[1]; -typedef char No[2]; - -template -T &get(); - -// These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ULongLong); -No &convert(...); - -template -struct ConvertToIntImpl { - enum { value = ENABLE_CONVERSION }; -}; - -template -struct ConvertToIntImpl2 { - enum { value = false }; -}; - -template -struct ConvertToIntImpl2 { - enum { - // Don't convert numeric types. - value = ConvertToIntImpl::is_specialized>::value - }; -}; - -template -struct ConvertToInt { - enum { enable_conversion = sizeof(fmt::internal::convert(get())) == sizeof(Yes) }; - enum { value = ConvertToIntImpl2::value }; -}; - -#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ - template <> \ - struct ConvertToInt { \ - enum { value = 0 }; \ - } - -// Silence warnings about convering float to int. -FMT_DISABLE_CONVERSION_TO_INT(float); -FMT_DISABLE_CONVERSION_TO_INT(double); -FMT_DISABLE_CONVERSION_TO_INT(long double); - -template -struct EnableIf {}; - -template -struct EnableIf { - typedef T type; -}; - -template -struct Conditional { - typedef T type; -}; - -template -struct Conditional { - typedef F type; -}; - -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { - enum { value = 0 }; -}; - -template <> -struct Not { - enum { value = 1 }; -}; - -template -struct FalseType { - enum { value = 0 }; -}; - -template -struct LConvCheck { - LConvCheck(int) {} -}; - -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline StringRef thousands_sep(LConv *lc, LConvCheck = 0) { - return lc->thousands_sep; -} - -inline fmt::StringRef thousands_sep(...) { return ""; } - -#define FMT_CONCAT(a, b) a##b - -#if FMT_GCC_VERSION >= 303 -#define FMT_UNUSED __attribute__((unused)) -#else -#define FMT_UNUSED -#endif - -#ifndef FMT_USE_STATIC_ASSERT -#define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -#define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -#define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -#define FMT_STATIC_ASSERT(cond, message) typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - -template -void format_arg(Formatter &, ...) { - FMT_STATIC_ASSERT(FalseType::value, - "Cannot format argument. To enable the use of ostream " - "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_arg."); -} - -// Makes an Arg object from any type. -template -class MakeValue : public Arg { -public: - typedef typename Formatter::Char Char; - -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 - MakeValue(const T *value); - template - MakeValue(T *value); - - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); -#if FMT_HAS_STRING_VIEW - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - - void set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - wstring.value = str.data(); - 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, void *format_str_ptr) { - format_arg(*static_cast(formatter), *static_cast(format_str_ptr), *static_cast(arg)); - } - -public: - MakeValue() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ - static uint64_t type(Type) { return Arg::TYPE; } - -#define FMT_MAKE_VALUE(Type, field, TYPE) FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(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 (const_check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t type(long) { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } - - MakeValue(unsigned long value) { - if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t type(unsigned long) { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if __cplusplus >= 201103L - template ::value && ConvertToInt::value>::type> - MakeValue(T value) { - int_value = value; - } - - template ::value && ConvertToInt::value>::type> - static uint64_t type(T) { - return Arg::INT; - } -#endif - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Supported value) { int_value = value; } - static uint64_t type(wchar_t) { return Arg::CHAR; } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_STR_VALUE(const std::string_view &, STRING) -#endif - FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING) -#endif - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { - custom.value = &value; - custom.format = &format_custom_arg; - } - - template - static typename EnableIf::value>::value, uint64_t>::type type(const T &) { - return Arg::CUSTOM; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - MakeValue(const NamedArg &value) { - pointer = &value; - } - template - MakeValue(const NamedArgWithType &value) { - pointer = &value; - } - - template - static uint64_t type(const NamedArg &) { - return Arg::NAMED_ARG; - } - template - static uint64_t type(const NamedArgWithType &) { - return Arg::NAMED_ARG; - } -}; - -template -class MakeArg : public Arg { -public: - MakeArg() { type = Arg::NONE; } - - template - MakeArg(const T &value) : Arg(MakeValue(value)) { - type = static_cast(MakeValue::type(value)); - } -}; - -template -struct NamedArg : Arg { - BasicStringRef name; - - template - NamedArg(BasicStringRef argname, const T &value) : Arg(MakeArg>(value)), name(argname) {} -}; - -template -struct NamedArgWithType : NamedArg { - NamedArgWithType(BasicStringRef argname, const T &value) : NamedArg(argname, value) {} -}; - -class RuntimeError : public std::runtime_error { -protected: - RuntimeError() : std::runtime_error("") {} - RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} - FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; -}; - -template -class ArgMap; -} // namespace internal - -/** An argument list. */ -class ArgList { -private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. - uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; - const internal::Arg *args_; - }; - - internal::Arg::Type type(unsigned index) const { return type(types_, index); } - - template - friend class internal::ArgMap; - -public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; - - ArgList() : types_(0) {} - - ArgList(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} - - uint64_t types() const { return types_; } - - /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != Arg::NONE) val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type = Arg::NONE; - return arg; - } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) return args_[i]; - } - return args_[index]; - } - - static internal::Arg::Type type(uint64_t types, unsigned index) { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast((types & (mask << shift)) >> shift); - } -}; - -#define FMT_DISPATCH(call) static_cast(this)->call - -/** - \rst - An argument visitor based on the `curiously recurring template pattern - `_. - - To use `~fmt::ArgVisitor` define a subclass that implements some or all of the - visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, - for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. Then calling - `~fmt::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 the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::ArgVisitor` will be called. - - **Example**:: - - class MyArgVisitor : public fmt::ArgVisitor { - public: - void visit_int(int value) { fmt::print("{}", value); } - void visit_double(double value) { fmt::print("{}", value ); } - }; - \endrst - */ -template -class ArgVisitor { -private: - typedef internal::Arg Arg; - -public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - /** Visits an ``int`` argument. **/ - Result visit_int(int value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits a ``long long`` argument. **/ - Result visit_long_long(LongLong value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits an ``unsigned`` argument. **/ - Result visit_uint(unsigned value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits an ``unsigned long long`` argument. **/ - Result visit_ulong_long(ULongLong value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits a ``bool`` argument. **/ - Result visit_bool(bool value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits a ``char`` or ``wchar_t`` argument. **/ - Result visit_char(int value) { return FMT_DISPATCH(visit_any_int(value)); } - - /** Visits an argument of any integral type. **/ - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a ``double`` argument. **/ - Result visit_double(double value) { return FMT_DISPATCH(visit_any_double(value)); } - - /** Visits a ``long double`` argument. **/ - Result visit_long_double(long double value) { return FMT_DISPATCH(visit_any_double(value)); } - - /** Visits a ``double`` or ``long double`` argument. **/ - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a null-terminated C string (``const char *``) argument. **/ - Result visit_cstring(const char *) { return FMT_DISPATCH(visit_unhandled_arg()); } - - /** Visits a string argument. **/ - Result visit_string(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - - /** Visits a wide string argument. **/ - Result visit_wstring(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - - /** Visits a pointer argument. **/ - Result visit_pointer(const void *) { return FMT_DISPATCH(visit_unhandled_arg()); } - - /** Visits an argument of a custom (user-defined) type. **/ - Result visit_custom(Arg::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - - /** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be - called. - \endrst - */ - Result visit(const Arg &arg) { - switch (arg.type) { - case Arg::NONE: - case Arg::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - 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::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_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::CSTRING: - return FMT_DISPATCH(visit_cstring(arg.string.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)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - return Result(); - } -}; - -enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; - -// Flags. -enum { - SIGN_FLAG = 1, - PLUS_FLAG = 2, - MINUS_FLAG = 4, - HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. -}; - -// 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 flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() 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 flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() 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 flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - char type() const { return type_; } - char type_prefix() const { return type_; } -}; - -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { -private: - T value_; - -public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) : SpecT(spec), value_(val) {} - - T value() const { return value_; } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { -private: - const Char *str_; - -public: - template - StrFormatSpec(const Char *str, unsigned width, FillChar fill) : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } - - const Char *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**:: - - MemoryWriter 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(MemoryWriter() << 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); } - -namespace internal { - -template -class ArgMap { -private: - typedef std::vector, internal::Arg>> MapType; - typedef typename MapType::value_type Pair; - - MapType map_; - -public: - void init(const ArgList &args); - - const internal::Arg *find(const fmt::BasicStringRef &name) const { - // The list is unsorted, so just return the first matching name. - for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { - if (it->first == name) return &it->second; - } - return FMT_NULL; - } -}; - -template -void ArgMap::init(const ArgList &args) { - if (!map_.empty()) return; - typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = FMT_NULL; - bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0; /*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - case internal::Arg::INT: - case internal::Arg::UINT: - case internal::Arg::LONG_LONG: - case internal::Arg::ULONG_LONG: - case internal::Arg::BOOL: - case internal::Arg::CHAR: - case internal::Arg::DOUBLE: - case internal::Arg::LONG_DOUBLE: - case internal::Arg::CSTRING: - case internal::Arg::STRING: - case internal::Arg::WSTRING: - case internal::Arg::POINTER: - case internal::Arg::CUSTOM: - /*nothing*/ - ; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS; /*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - case internal::Arg::INT: - case internal::Arg::UINT: - case internal::Arg::LONG_LONG: - case internal::Arg::ULONG_LONG: - case internal::Arg::BOOL: - case internal::Arg::CHAR: - case internal::Arg::DOUBLE: - case internal::Arg::LONG_DOUBLE: - case internal::Arg::CSTRING: - case internal::Arg::STRING: - case internal::Arg::WSTRING: - case internal::Arg::POINTER: - case internal::Arg::CUSTOM: - /*nothing*/ - ; - } - } -} - -template -class ArgFormatterBase : public ArgVisitor { -private: - BasicWriter &writer_; - Spec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); - - void write_pointer(const void *p) { - spec_.flags_ = HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(p), spec_); - } - - // workaround MSVC two-phase lookup issue - typedef internal::Arg Arg; - -protected: - BasicWriter &writer() { return writer_; } - Spec &spec() { return spec_; } - - void write(bool value) { - const char *str_value = value ? "true" : "false"; - Arg::StringValue str = {str_value, std::strlen(str_value)}; - writer_.write_str(str, spec_); - } - - void write(const char *value) { - Arg::StringValue str = {value, value ? std::strlen(value) : 0}; - writer_.write_str(str, spec_); - } - -public: - typedef Spec SpecType; - - ArgFormatterBase(BasicWriter &w, Spec &s) : writer_(w), spec_(s) {} - - template - void visit_any_int(T value) { - writer_.write_int(value, spec_); - } - - template - void visit_any_double(T value) { - writer_.write_double(value, spec_); - } - - void visit_bool(bool value) { - if (spec_.type_) { - visit_any_int(value); - return; - } - write(value); - } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); - CharPtr out = CharPtr(); - const unsigned CHAR_SIZE = 1; - if (spec_.width_ > CHAR_SIZE) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); - out += spec_.width_ - CHAR_SIZE; - } else if (spec_.align_ == ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, internal::const_check(CHAR_SIZE), fill); - } else { - std::uninitialized_fill_n(out + CHAR_SIZE, spec_.width_ - CHAR_SIZE, fill); - } - } else { - out = writer_.grow_buffer(CHAR_SIZE); - } - *out = internal::CharTraits::cast(value); - } - - void visit_cstring(const char *value) { - if (spec_.type_ == 'p') return write_pointer(value); - write(value); - } - - // Qualification with "internal" here and below is a workaround for nvcc. - void visit_string(internal::Arg::StringValue value) { writer_.write_str(value, spec_); } - - using ArgVisitor::visit_wstring; - - void visit_wstring(internal::Arg::StringValue value) { writer_.write_str(value, spec_); } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); - write_pointer(value); - } -}; - -class FormatterBase { -private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); - -protected: - const ArgList &args() const { return args_; } - - explicit FormatterBase(const ArgList &args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg next_arg(const char *&error) { - if (next_arg_index_ >= 0) return do_get_arg(internal::to_unsigned(next_arg_index_++), error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); - } - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg get_arg(unsigned arg_index, const char *&error) { return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); } - - bool check_no_auto_index(const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; - } - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) w << BasicStringRef(start, internal::to_unsigned(end - start)); - } -}; -} // namespace internal - -/** - \rst - An argument formatter based on the `curiously recurring template pattern - `_. - - To use `~fmt::BasicArgFormatter` define a subclass that implements some or - all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicArgFormatter` or its superclass - will be called. - \endrst - */ -template -class BasicArgFormatter : public internal::ArgFormatterBase { -private: - BasicFormatter &formatter_; - const Char *format_; - -public: - /** - \rst - Constructs an argument formatter object. - *formatter* is a reference to the main formatter object, *spec* contains - format specifier information for standard argument types, and *fmt* points - to the part of the format string being parsed for custom argument types. - \endrst - */ - BasicArgFormatter(BasicFormatter &formatter, Spec &spec, const Char *fmt) - : internal::ArgFormatterBase(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } -}; - -/** The default argument formatter. */ -template -class ArgFormatter : public BasicArgFormatter, Char, FormatSpec> { -public: - /** Constructs an argument formatter object. */ - ArgFormatter(BasicFormatter &formatter, FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, Char, FormatSpec>(formatter, spec, fmt) {} -}; - -/** This template formats data and writes the output to a writer. */ -template -class BasicFormatter : private internal::FormatterBase { -public: - /** The character type for the output. */ - typedef CharType Char; - -private: - BasicWriter &writer_; - internal::ArgMap map_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - using internal::FormatterBase::get_arg; - - // Checks if manual indexing is used and returns the argument with - // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char *&error); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); - -public: - /** - \rst - Constructs a ``BasicFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - BasicFormatter(const ArgList &args, BasicWriter &w) : internal::FormatterBase(args), writer_(w) {} - - /** Returns a reference to the writer associated with this formatter. */ - BasicWriter &writer() { return writer_; } - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); - - // Formats a single argument and advances format_str, a format string pointer. - const Char *format(const Char *&format_str, const internal::Arg &arg); -}; - -// 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_GEN11(f) FMT_GEN10(f), f(10) -#define FMT_GEN12(f) FMT_GEN11(f), f(11) -#define FMT_GEN13(f) FMT_GEN12(f), f(12) -#define FMT_GEN14(f) FMT_GEN13(f), f(13) -#define FMT_GEN15(f) FMT_GEN14(f), f(14) - -namespace internal { -inline uint64_t make_type() { return 0; } - -template -inline uint64_t make_type(const T &arg) { - return MakeValue>::type(arg); -} - -template -struct ArgArray; - -template -struct ArgArray { - // '+' is used to silence GCC -Wduplicated-branches warning. - typedef Value Type[N > 0 ? N : +1]; - - template - static Value make(const T &value) { -#ifdef __clang__ - Value result = MakeValue(value); - // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: - // https://github.com/fmtlib/fmt/issues/276 - (void)result.custom.format; - return result; -#else - return MakeValue(value); -#endif - } -}; - -template -struct ArgArray { - typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE - - template - static Arg make(const T &value) { - return MakeArg(value); - } -}; - -#if FMT_USE_VARIADIC_TEMPLATES -template -inline uint64_t make_type(const Arg &first, const Args &...tail) { - return make_type(first) | (make_type(tail...) << 4); -} - -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} -}; - -#define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | - (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | (t12.type << 48) | (t13.type << 52) | - (t14.type << 56); -} -#endif -} // namespace internal - -#define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -#define FMT_MAKE_ARG_TYPE(n) T##n -#define FMT_MAKE_ARG(n) const T##n &v##n -#define FMT_ASSIGN_char(n) arr[n] = fmt::internal::MakeValue>(v##n) -#define FMT_ASSIGN_wchar_t(n) arr[n] = fmt::internal::MakeValue>(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 arg0, const Args &...args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ArgArray::template make>(args)...}; \ - func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -// 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) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ArgArray::template make>(args)...}; \ - func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -#else - -#define FMT_MAKE_REF(n) fmt::internal::MakeValue>(v##n) -#define FMT_MAKE_REF2(n) 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::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -#define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - 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::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// 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: - FMT_API void init(int err_code, CStringRef format_str, ArgList args); - -protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - -public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with a description - formatted with `fmt::format_system_error`. *message* and additional - arguments passed into the constructor are formatted similarly to - `fmt::format`. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } - FMT_DEFAULTED_COPY_CTOR(SystemError) - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) // -V1067 - - FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; - - int error_code() const { return error_code_; } -}; - -/** - \rst - Formats an error returned by an operating system or a language runtime, - for example a file opening error, and writes it to *out* in the following - form: - - .. parsed-literal:: - **: ** - - where ** is the passed message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - \endrst - */ -FMT_API void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. - - You can use one of the following typedefs for common character types: - - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ - - \endrst - */ -template -class BasicWriter { -private: - // Output buffer. - Buffer &buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if FMT_SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } -#else - static Char *get(Char *p) { return p; } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr fill_padding(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 grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Writes an unsigned decimal integer. - template - Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { - unsigned num_digits = internal::count_digits(value); - Char *ptr = get(grow_buffer(prefix_size + num_digits)); - internal::format_decimal(ptr + prefix_size, value, num_digits); - return ptr; - } - - // Writes a decimal integer. - template - void write_decimal(Int value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(value)) { - abs_value = 0 - abs_value; - *write_unsigned_decimal(abs_value, 1) = '-'; - } else { - write_unsigned_decimal(abs_value, 0); - } - } - - // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, const EmptySpec &, const char *prefix, unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const Spec &spec); - - // Writes a formatted string. - template - CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); - - template - void write_str(const internal::Arg::StringValue &str, const Spec &spec); - - // This following methods are private to disallow writing wide characters - // and strings to a char stream. 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::WCharHelper::Unsupported); - void operator<<(typename internal::WCharHelper::Unsupported); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void append_float_length(Char *&format_ptr, long double) { *format_ptr++ = 'L'; } - - template - void append_float_length(Char *&, T) {} - - template - friend class internal::ArgFormatterBase; - - template - friend class BasicPrintfArgFormatter; - -protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(Buffer &b) : buffer_(b) {} - -public: - /** - \rst - Destroys a ``BasicWriter`` object. - \endrst - */ - virtual ~BasicWriter() {} - - /** - 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 FMT_NOEXCEPT { 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]; - } - - /** - \rst - Returns the content of the output buffer as an `std::string`. - \endrst - */ - 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**:: - - MemoryWriter 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 :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void write(BasicCStringRef format, ArgList args) { BasicFormatter(args, *this).format(format); } - FMT_VARIADIC_VOID(write, BasicCStringRef) - - BasicWriter &operator<<(int value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(long value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned long value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(LongLong value) { - write_decimal(value); - return *this; - } - - /** - \rst - Formats *value* and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(ULongLong value) { return *this << IntFormatSpec(value); } - - BasicWriter &operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - \rst - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter &operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter &operator<<(typename internal::WCharHelper::Supported value) { - buffer_.push_back(value); - return *this; - } - - /** - \rst - Writes *value* to the stream. - \endrst - */ - BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - BasicWriter &operator<<(typename internal::WCharHelper::Supported value) { - const char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void clear() FMT_NOEXCEPT { buffer_.clear(); } - - Buffer &buffer() FMT_NOEXCEPT { return buffer_; } -}; - -template -template -typename BasicWriter::CharPtr BasicWriter::write_str(const StrChar *s, std::size_t size, const AlignSpec &spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::uninitialized_fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::uninitialized_copy(s, s + size, out); - return out; -} - -template -constexpr const Char *EmptyStr() noexcept; -template <> -constexpr const char *EmptyStr() noexcept { - return ""; -} -template <> -constexpr const wchar_t *EmptyStr() noexcept { - return L""; -} - -template -template -void BasicWriter::write_str(const internal::Arg::StringValue &s, const Spec &spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (!str_value && str_size == 0) { - str_value = EmptyStr(); - } - std::size_t precision = static_cast(spec.precision_); - if (spec.precision_ >= 0 && precision < str_size) str_size = precision; - write_str(str_value, str_size, spec); -} - -template -typename BasicWriter::CharPtr BasicWriter::fill_padding(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 = internal::CharTraits::cast(fill); - std::uninitialized_fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char); - return content; -} - -template -template -typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, - unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = internal::CharTraits::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 + internal::to_unsigned(spec.precision()); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - std::uninitialized_fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::uninitialized_copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::uninitialized_copy(prefix, prefix + prefix_size, end - size); - } - std::uninitialized_fill(p, end - size, fill); - p = end; - } - return p - 1; -} - -template -template -void BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = static_cast(value); - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: - case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0); - break; - } - case 'x': - case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 4) != 0); - Char *p = get(prepare_int_buffer(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.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 1) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 1)); - } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 3) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 7)); - } while ((n >>= 3) != 0); - break; - } - case 'n': { - unsigned num_digits = internal::count_digits(abs_value); - fmt::StringRef sep = ""; -#if !(defined(ANDROID) || defined(__ANDROID__)) - sep = internal::thousands_sep(std::localeconv()); -#endif - unsigned size = static_cast(num_digits + sep.size() * ((num_digits - 1) / 3)); - CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); - break; - } - default: - internal::report_unknown_type(spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } -} - -template -template -void BasicWriter::write_double(T value, const Spec &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': -#if FMT_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::report_unknown_type(type, "double"); - break; - } - - char sign = 0; - // Use isnegative instead of value < 0 because the latter is always - // false for NaN. - if (internal::FPUtil::isnegative(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (internal::FPUtil::isnotanumber(value)) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char *nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) *out = sign; - return; - } - - if (internal::FPUtil::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char *inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (width > 1u ? 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.flag(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++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); - unsigned n = 0; - Char *start = FMT_NULL; - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#if FMT_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 (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - start = &buffer_[offset]; - int result = internal::CharTraits::format_float(start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (result >= 0) { - n = internal::to_unsigned(result); - if (offset + n < buffer_.capacity()) break; // The buffer is large enough - continue with formatting. - buffer_.reserve(offset + n + 1); - } else { - // If result is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(buffer_.capacity() + 1); - } - } - 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() > n) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') *start++ = fill; - if (sign) *(start - 1) = sign; - } - grow_buffer(n); -} - -/** - \rst - This class 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 - and the standard allocator: - - +---------------+-----------------------------------------------------+ - | Type | Definition | - +===============+=====================================================+ - | MemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - | WMemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - - **Example**:: - - MemoryWriter 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 BasicMemoryWriter : public BasicWriter { -private: - internal::MemoryBuffer buffer_; - -public: - explicit BasicMemoryWriter(const Allocator &alloc = Allocator()) : BasicWriter(buffer_), buffer_(alloc) {} // -V1050 - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter &&other) : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) {} - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -/** - \rst - This class template provides operations for formatting and writing data - into a fixed-size array. For writing into a dynamically growing buffer - use :class:`fmt::BasicMemoryWriter`. - - Any write method will throw ``std::runtime_error`` if the output doesn't fit - into the array. - - You can use one of the following typedefs for common character types: - - +--------------+---------------------------+ - | Type | Definition | - +==============+===========================+ - | ArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - | WArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - \endrst - */ -template -class BasicArrayWriter : public BasicWriter { -private: - internal::FixedBuffer buffer_; - -public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ - BasicArrayWriter(Char *array, std::size_t size) : BasicWriter(buffer_), buffer_(array, size) {} // -V1050 - - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit BasicArrayWriter(Char (&array)[SIZE]) : BasicWriter(buffer_), buffer_(array, SIZE) {} -}; - -typedef BasicArrayWriter ArrayWriter; -typedef BasicArrayWriter WArrayWriter; - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#if FMT_USE_WINDOWS_H - -/** A Windows error. */ -class WindowsError : public SystemError { -private: - FMT_API void init(int error_code, CStringRef format_str, ArgList args); - -public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - 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``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); - } - \endrst - */ - WindowsError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#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: - print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); - */ -FMT_API void print_colored(Color c, CStringRef format, ArgList args); - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = format("The answer is {}", 42); - \endrst -*/ -inline std::string format(CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -inline std::wstring format(WCStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - print(stderr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -FMT_API void print(CStringRef format_str, 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 *format_decimal(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 = static_cast((value % 100) * 2); - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) *--str_ = '-'; - } - -public: - explicit FormatInt(int value) { FormatSigned(value); } // -V730 - explicit FormatInt(long value) { FormatSigned(value); } // -V730 - explicit FormatInt(LongLong value) { FormatSigned(value); } // -V730 - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} // -V730 - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} // -V730 - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} // -V730 - - /** Returns the number of characters written to the output buffer. */ - std::size_t size() const { return internal::to_unsigned(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_; - } - - /** - \rst - Returns the content of the output buffer as an ``std::string``. - \endrst - */ - 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 format_decimal(char *&buffer, T value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(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::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; -} - -/** - \rst - Returns a named argument for formatting functions. - - **Example**:: - - print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); - - \endrst - */ -template -inline internal::NamedArgWithType arg(StringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -template -inline internal::NamedArgWithType arg(WStringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg &) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg &) FMT_DELETED_OR_UNDEFINED; -} // namespace fmt - -#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_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_(Const, Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), const Args &...args) Const { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ArgArray::template make>(args)...}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -#define FMT_WRAP(Const, 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::ArgArray::Type arr; \ - FMT_GEN(n, FMT_ASSIGN_##Char); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ - } - -#define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 15, __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, - fmt::ArgList args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST(ReturnType, func, ...) FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L## #id, id) - -/** - \rst - Convenient macro to capture the arguments' names and values into several - ``fmt::arg(name, value)``. - - **Example**:: - - int x = 1, y = 2; - print("point: ({x}, {y})", FMT_CAPTURE(x, y)); - // same as: - // print("point: ({x}, {y})", arg("x", x), arg("y", y)); - - \endrst - */ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - -namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE *, CStringRef) -FMT_VARIADIC(void, print_colored, Color, CStringRef) - -namespace internal { -template -inline bool is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -} - -// 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 -unsigned parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - // Convert to unsigned to prevent a warning. - unsigned max_int = (std::numeric_limits::max)(); - unsigned big = max_int / 10; - do { - // Check for overflow. - if (value > big) { - value = max_int + 1; - break; - } - value = value * 10 + (*s - '0'); - ++s; - } while ('0' <= *s && *s <= '9'); - // Convert to unsigned to prevent a warning. - if (value > max_int) FMT_THROW(FormatError("number is too big")); - return value; -} - -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void check_sign(const Char *&s, const Arg &arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(FormatError(fmt::format("format specifier '{}' requires signed argument", sign))); - } - ++s; -} -} // namespace internal - -template -inline internal::Arg BasicFormatter::get_arg(BasicStringRef arg_name, const char *&error) { - if (check_no_auto_index(error)) { - map_.init(args()); - const internal::Arg *arg = map_.find(arg_name); - if (arg) return *arg; - error = "argument not found"; - } - return internal::Arg(); -} - -template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = FMT_NULL; - internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(FormatError(*s != '}' && *s != ':' ? "invalid format string" : error)); - } - return arg; -} - -template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { - assert(internal::is_name_start(*s)); - const Char *start = s; - Char c; - do { - c = *++s; - } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = FMT_NULL; - internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); - if (error) FMT_THROW(FormatError(error)); - return arg; -} - -template -const Char *BasicFormatter::format(const Char *&format_str, const internal::Arg &arg) { - using internal::Arg; - const Char *s = format_str; - typename ArgFormatter::SpecType spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++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 == '{') FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else - ++s; - if (spec.align_ == ALIGN_NUMERIC) require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse zero flag. - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++s; - } - - // Parse width. - if ('0' <= *s && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case Arg::INT: - if (width_arg.int_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; - break; - case Arg::UINT: - value = width_arg.uint_value; - break; - case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = width_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("width is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) FMT_THROW(FormatError("number is too big")); - spec.width_ = static_cast(value); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg precision_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) FMT_THROW(FormatError("negative precision")); - 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) FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("precision is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( - fmt::format("precision not allowed in {} format specifier", arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') FMT_THROW(FormatError("missing '}' in format string")); - - // Format argument. - ArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void BasicFormatter::format(BasicCStringRef format_str) { - const Char *s = format_str.c_str(); - const Char *start = s; - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start, s - 1); - internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - start = s = format(s, arg); - } - write(writer_, start, s); -} - -template -struct ArgJoin { - It first; - It last; - BasicCStringRef sep; - - ArgJoin(It first, It last, const BasicCStringRef &sep) : first(first), last(last), sep(sep) {} -}; - -template -ArgJoin join(It first, It last, const BasicCStringRef &sep) { - return ArgJoin(first, last, sep); -} - -template -ArgJoin join(It first, It last, const BasicCStringRef &sep) { - return ArgJoin(first, last, sep); -} - -#if FMT_HAS_GXX_CXX11 -template -auto join(const Range &range, const BasicCStringRef &sep) -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} - -template -auto join(const Range &range, const BasicCStringRef &sep) -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} -#endif - -template -void format_arg(fmt::BasicFormatter &f, const Char *&format_str, const ArgJoin &e) { - const Char *end = format_str; - if (*end == ':') ++end; - while (*end && *end != '}') ++end; - if (*end != '}') FMT_THROW(FormatError("missing '}' in format string")); - - It it = e.first; - if (it != e.last) { - const Char *save = format_str; - f.format(format_str, internal::MakeArg>(*it++)); - while (it != e.last) { - f.writer().write(e.sep); - format_str = save; - f.format(format_str, internal::MakeArg>(*it++)); - } - } - format_str = end + 1; -} - -namespace internal { - -// This function was moved to the h-file to avoid GCC 12 LTO build error -FMT_NORETURN static void report_unknown_type(char code, const char *type) { - (void)type; - if (std::isprint(static_cast(code))) { - FMT_THROW(FormatError(format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(FormatError(format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); -} - -} // namespace internal - -} // namespace fmt - -#if FMT_USE_USER_DEFINED_LITERALS -namespace fmt { -namespace internal { - -template -struct UdlFormat { - const Char *str; - - template - auto operator()(Args &&...args) const -> decltype(format(str, std::forward(args)...)) { - return format(str, std::forward(args)...); - } -}; - -template -struct UdlArg { - const Char *str; - - template - NamedArgWithType operator=(T &&value) const { - return {str, std::forward(value)}; - } -}; - -} // namespace internal - -inline namespace literals { - -/** - \rst - C++11 literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - \endrst - */ -inline internal::UdlFormat operator"" _format(const char *s, std::size_t) { return {s}; } -inline internal::UdlFormat operator"" _format(const wchar_t * s, std::size_t) { return {s}; } - -/** - \rst - C++11 literal equivalent of :func:`fmt::arg`. - - **Example**:: - - using namespace fmt::literals; - print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); - \endrst - */ -inline internal::UdlArg operator"" _a(const char *s, std::size_t) { return {s}; } -inline internal::UdlArg operator"" _a(const wchar_t * s, std::size_t) { return {s}; } - -} // namespace literals -} // namespace fmt -#endif // FMT_USE_USER_DEFINED_LITERALS - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -#pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -#define FMT_FUNC inline -#include "format.cc" -#else -#define FMT_FUNC -#endif - -#endif // FMT_FORMAT_H_ diff --git a/cpp_src/vendor/spdlog/fmt/bundled/ostream.cc b/cpp_src/vendor/spdlog/fmt/bundled/ostream.cc deleted file mode 100644 index 2d443f730..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/ostream.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "ostream.h" - -namespace fmt { - -namespace internal { -FMT_FUNC void write(std::ostream &os, Writer &w) { - const char *data = w.data(); - typedef internal::MakeUnsigned::Type UnsignedStreamSize; - UnsignedStreamSize size = w.size(); - UnsignedStreamSize max_size = - internal::to_unsigned((std::numeric_limits::max)()); - do { - UnsignedStreamSize n = size <= max_size ? size : max_size; - os.write(data, static_cast(n)); - data += n; - size -= n; - } while (size != 0); -} -} - -FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - internal::write(os, w); -} -} // namespace fmt diff --git a/cpp_src/vendor/spdlog/fmt/bundled/ostream.h b/cpp_src/vendor/spdlog/fmt/bundled/ostream.h deleted file mode 100644 index f1b09dfc0..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/ostream.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_OSTREAM_H_ -#define FMT_OSTREAM_H_ - -#include "format.h" -#include - -namespace fmt -{ - -namespace internal -{ - -template -class FormatBuf : public std::basic_streambuf -{ -private: - typedef typename std::basic_streambuf::int_type int_type; - typedef typename std::basic_streambuf::traits_type traits_type; - - Buffer &buffer_; - -public: - FormatBuf(Buffer &buffer) : buffer_(buffer) {} - -protected: - // The put-area is actually always empty. This makes the implementation - // simpler and has the advantage that the streambuf and the buffer are always - // in sync and sputc never writes into uninitialized memory. The obvious - // disadvantage is that each call to sputc always results in a (virtual) call - // to overflow. There is no disadvantage here for sputn since this always - // results in a call to xsputn. - - int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE - { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE - { - buffer_.append(s, s + count); - return count; - } -}; - -Yes &convert(std::ostream &); - -struct DummyStream : std::ostream -{ - DummyStream(); // Suppress a bogus warning in MSVC. - - // Hide all operator<< overloads from std::ostream. - template - typename EnableIf::type operator<<(const T &); -}; - -No &operator<<(std::ostream &, int); - -template -struct ConvertToIntImpl -{ - // Convert to int only if T doesn't have an overloaded operator<<. - enum - { - value = sizeof(convert(get() << get())) == sizeof(No) - }; -}; - -// Write the content of w to os. -FMT_API void write(std::ostream &os, Writer &w); -} // namespace internal - -// Formats a value. -template -void format_arg(BasicFormatter &f, - const Char *&format_str, const T &value) -{ - internal::MemoryBuffer buffer; - - internal::FormatBuf format_buf(buffer); - std::basic_ostream output(&format_buf); - output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - output << value; - - BasicStringRef str(&buffer[0], buffer.size()); - typedef internal::MakeArg< BasicFormatter > MakeArg; - format_str = f.format(format_str, MakeArg(str)); -} - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(void, print, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "ostream.cc" -#endif - -#endif // FMT_OSTREAM_H_ diff --git a/cpp_src/vendor/spdlog/fmt/bundled/posix.cc b/cpp_src/vendor/spdlog/fmt/bundled/posix.cc deleted file mode 100644 index 356668c13..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/posix.cc +++ /dev/null @@ -1,241 +0,0 @@ -/* - A C++ interface to POSIX functions. - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -// Disable bogus MSVC warnings. -#ifndef _CRT_SECURE_NO_WARNINGS -# define _CRT_SECURE_NO_WARNINGS -#endif - -#include "posix.h" - -#include -#include -#include - -#ifndef _WIN32 -# include -#else -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include - -# define O_CREAT _O_CREAT -# define O_TRUNC _O_TRUNC - -# ifndef S_IRUSR -# define S_IRUSR _S_IREAD -# endif - -# ifndef S_IWUSR -# define S_IWUSR _S_IWRITE -# endif - -# ifdef __MINGW32__ -# define _SH_DENYNO 0x40 -# endif - -#endif // _WIN32 - -#ifdef fileno -# undef fileno -#endif - -namespace { -#ifdef _WIN32 -// Return type of read and write functions. -typedef int RWResult; - -// On Windows the count argument to read and write is unsigned, so convert -// it from size_t preventing integer overflow. -inline unsigned convert_rwcount(std::size_t count) { - return count <= UINT_MAX ? static_cast(count) : UINT_MAX; -} -#else -// Return type of read and write functions. -typedef ssize_t RWResult; - -inline std::size_t convert_rwcount(std::size_t count) { return count; } -#endif -} - -fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { - if (file_ && FMT_SYSTEM(fclose(file_)) != 0) - fmt::report_system_error(errno, "cannot close file"); -} - -fmt::BufferedFile::BufferedFile( - fmt::CStringRef filename, fmt::CStringRef mode) { - FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); - if (!file_) - FMT_THROW(SystemError(errno, "cannot open file {}", filename)); -} - -void fmt::BufferedFile::close() { - if (!file_) - return; - int result = FMT_SYSTEM(fclose(file_)); - file_ = FMT_NULL; - if (result != 0) - FMT_THROW(SystemError(errno, "cannot close file")); -} - -// A macro used to prevent expansion of fileno on broken versions of MinGW. -#define FMT_ARGS - -int fmt::BufferedFile::fileno() const { - int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); - if (fd == -1) - FMT_THROW(SystemError(errno, "cannot get file descriptor")); - return fd; -} - -fmt::File::File(fmt::CStringRef path, int oflag) { - int mode = S_IRUSR | S_IWUSR; -#if defined(_WIN32) && !defined(__MINGW32__) - fd_ = -1; - FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); -#else - FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); -#endif - if (fd_ == -1) - FMT_THROW(SystemError(errno, "cannot open file {}", path)); -} - -fmt::File::~File() FMT_NOEXCEPT { - // Don't retry close in case of EINTR! - // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html - if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) - fmt::report_system_error(errno, "cannot close file"); -} - -void fmt::File::close() { - if (fd_ == -1) - return; - // Don't retry close in case of EINTR! - // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html - int result = FMT_POSIX_CALL(close(fd_)); - fd_ = -1; - if (result != 0) - FMT_THROW(SystemError(errno, "cannot close file")); -} - -fmt::LongLong fmt::File::size() const { -#ifdef _WIN32 - // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT - // is less than 0x0500 as is the case with some default MinGW builds. - // Both functions support large file sizes. - DWORD size_upper = 0; - HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); - DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); - if (size_lower == INVALID_FILE_SIZE) { - DWORD error = GetLastError(); - if (error != NO_ERROR) - FMT_THROW(WindowsError(GetLastError(), "cannot get file size")); - } - fmt::ULongLong long_size = size_upper; - return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; -#else - typedef struct stat Stat; - Stat file_stat = Stat(); - if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) - FMT_THROW(SystemError(errno, "cannot get file attributes")); - FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size), - "return type of File::size is not large enough"); - return file_stat.st_size; -#endif -} - -std::size_t fmt::File::read(void *buffer, std::size_t count) { - RWResult result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); - if (result < 0) - FMT_THROW(SystemError(errno, "cannot read from file")); - return internal::to_unsigned(result); -} - -std::size_t fmt::File::write(const void *buffer, std::size_t count) { - RWResult result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); - if (result < 0) - FMT_THROW(SystemError(errno, "cannot write to file")); - return internal::to_unsigned(result); -} - -fmt::File fmt::File::dup(int fd) { - // Don't retry as dup doesn't return EINTR. - // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html - int new_fd = FMT_POSIX_CALL(dup(fd)); - if (new_fd == -1) - FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd)); - return File(new_fd); -} - -void fmt::File::dup2(int fd) { - int result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); - if (result == -1) { - FMT_THROW(SystemError(errno, - "cannot duplicate file descriptor {} to {}", fd_, fd)); - } -} - -void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT { - int result = 0; - FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); - if (result == -1) - ec = ErrorCode(errno); -} - -void fmt::File::pipe(File &read_end, File &write_end) { - // Close the descriptors first to make sure that assignments don't throw - // and there are no leaks. - read_end.close(); - write_end.close(); - int fds[2] = {}; -#ifdef _WIN32 - // Make the default pipe capacity same as on Linux 2.6.11+. - enum { DEFAULT_CAPACITY = 65536 }; - int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); -#else - // Don't retry as the pipe function doesn't return EINTR. - // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html - int result = FMT_POSIX_CALL(pipe(fds)); -#endif - if (result != 0) - FMT_THROW(SystemError(errno, "cannot create pipe")); - // The following assignments don't throw because read_fd and write_fd - // are closed. - read_end = File(fds[0]); - write_end = File(fds[1]); -} - -fmt::BufferedFile fmt::File::fdopen(const char *mode) { - // Don't retry as fdopen doesn't return EINTR. - FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); - if (!f) - FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor")); - BufferedFile file(f); - fd_ = -1; - return file; -} - -long fmt::getpagesize() { -#ifdef _WIN32 - SYSTEM_INFO si; - GetSystemInfo(&si); - return si.dwPageSize; -#else - long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); - if (size < 0) - FMT_THROW(SystemError(errno, "cannot get memory page size")); - return size; -#endif -} diff --git a/cpp_src/vendor/spdlog/fmt/bundled/posix.h b/cpp_src/vendor/spdlog/fmt/bundled/posix.h deleted file mode 100644 index 693272500..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/posix.h +++ /dev/null @@ -1,424 +0,0 @@ -/* - A C++ interface to POSIX functions. - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_POSIX_H_ -#define FMT_POSIX_H_ - -#if defined(__MINGW32__) || defined(__CYGWIN__) -// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. -# undef __STRICT_ANSI__ -#endif - -#include -#include // for O_RDONLY -#include // for locale_t -#include -#include // for strtod_l - -#include - -#if defined __APPLE__ || defined(__FreeBSD__) -# include // for LC_NUMERIC_MASK on OS X -#endif - -#include "format.h" - -#ifndef FMT_POSIX -# if defined(_WIN32) && !defined(__MINGW32__) -// Fix warnings about deprecated symbols. -# define FMT_POSIX(call) _##call -# else -# define FMT_POSIX(call) call -# endif -#endif - -// Calls to system functions are wrapped in FMT_SYSTEM for testability. -#ifdef FMT_SYSTEM -# define FMT_POSIX_CALL(call) FMT_SYSTEM(call) -#else -# define FMT_SYSTEM(call) call -# ifdef _WIN32 -// Fix warnings about deprecated symbols. -# define FMT_POSIX_CALL(call) ::_##call -# else -# define FMT_POSIX_CALL(call) ::call -# endif -#endif - -// Retries the expression while it evaluates to error_result and errno -// equals to EINTR. -#ifndef _WIN32 -# define FMT_RETRY_VAL(result, expression, error_result) \ - do { \ - result = (expression); \ - } while (result == error_result && errno == EINTR) -#else -# define FMT_RETRY_VAL(result, expression, error_result) result = (expression) -#endif - -#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) - -namespace fmt -{ - -// An error code. -class ErrorCode -{ -private: - int value_; - -public: -explicit ErrorCode(int value = 0) FMT_NOEXCEPT : - value_(value) {} - - int get() const FMT_NOEXCEPT - { - return value_; - } -}; - -// A buffered file. -class BufferedFile -{ -private: - FILE *file_; - - friend class File; - - explicit BufferedFile(FILE *f) : file_(f) {} - -public: - // Constructs a BufferedFile object which doesn't represent any file. -BufferedFile() FMT_NOEXCEPT : - file_(FMT_NULL) {} - - // Destroys the object closing the file it represents if any. - FMT_API ~BufferedFile() FMT_NOEXCEPT; - -#if !FMT_USE_RVALUE_REFERENCES - // Emulate a move constructor and a move assignment operator if rvalue - // references are not supported. - -private: - // A proxy object to emulate a move constructor. - // It is private to make it impossible call operator Proxy directly. - struct Proxy - { - FILE *file; - }; - -public: - // A "move constructor" for moving from a temporary. -BufferedFile(Proxy p) FMT_NOEXCEPT : - file_(p.file) {} - - // A "move constructor" for moving from an lvalue. -BufferedFile(BufferedFile &f) FMT_NOEXCEPT : - file_(f.file_) - { - f.file_ = FMT_NULL; - } - - // A "move assignment operator" for moving from a temporary. - BufferedFile &operator=(Proxy p) - { - close(); - file_ = p.file; - return *this; - } - - // A "move assignment operator" for moving from an lvalue. - BufferedFile &operator=(BufferedFile &other) - { - close(); - file_ = other.file_; - other.file_ = FMT_NULL; - return *this; - } - - // Returns a proxy object for moving from a temporary: - // BufferedFile file = BufferedFile(...); - operator Proxy() FMT_NOEXCEPT - { - Proxy p = {file_}; - file_ = FMT_NULL; - return p; - } - -#else -private: - FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); - -public: -BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : - file_(other.file_) - { - other.file_ = FMT_NULL; - } - - BufferedFile& operator=(BufferedFile &&other) - { - close(); - file_ = other.file_; - other.file_ = FMT_NULL; - return *this; - } -#endif - - // Opens a file. - FMT_API BufferedFile(CStringRef filename, CStringRef mode); - - // Closes the file. - FMT_API void close(); - - // Returns the pointer to a FILE object representing this file. - FILE *get() const FMT_NOEXCEPT - { - return file_; - } - - // We place parentheses around fileno to workaround a bug in some versions - // of MinGW that define fileno as a macro. - FMT_API int (fileno)() const; - - void print(CStringRef format_str, const ArgList &args) - { - fmt::print(file_, format_str, args); - } - FMT_VARIADIC(void, print, CStringRef) -}; - -// A file. Closed file is represented by a File object with descriptor -1. -// Methods that are not declared with FMT_NOEXCEPT may throw -// fmt::SystemError in case of failure. Note that some errors such as -// closing the file multiple times will cause a crash on Windows rather -// than an exception. You can get standard behavior by overriding the -// invalid parameter handler with _set_invalid_parameter_handler. -class File -{ -private: - int fd_; // File descriptor. - - // Constructs a File object with a given descriptor. - explicit File(int fd) : fd_(fd) {} - -public: - // Possible values for the oflag argument to the constructor. - enum - { - RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. - WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. - RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. - }; - - // Constructs a File object which doesn't represent any file. -File() FMT_NOEXCEPT : - fd_(-1) {} - - // Opens a file and constructs a File object representing this file. - FMT_API File(CStringRef path, int oflag); - -#if !FMT_USE_RVALUE_REFERENCES - // Emulate a move constructor and a move assignment operator if rvalue - // references are not supported. - -private: - // A proxy object to emulate a move constructor. - // It is private to make it impossible call operator Proxy directly. - struct Proxy - { - int fd; - }; - -public: - // A "move constructor" for moving from a temporary. -File(Proxy p) FMT_NOEXCEPT : - fd_(p.fd) {} - - // A "move constructor" for moving from an lvalue. -File(File &other) FMT_NOEXCEPT : - fd_(other.fd_) - { - other.fd_ = -1; - } - - // A "move assignment operator" for moving from a temporary. - File &operator=(Proxy p) - { - close(); - fd_ = p.fd; - return *this; - } - - // A "move assignment operator" for moving from an lvalue. - File &operator=(File &other) - { - close(); - fd_ = other.fd_; - other.fd_ = -1; - return *this; - } - - // Returns a proxy object for moving from a temporary: - // File file = File(...); - operator Proxy() FMT_NOEXCEPT - { - Proxy p = {fd_}; - fd_ = -1; - return p; - } - -#else -private: - FMT_DISALLOW_COPY_AND_ASSIGN(File); - -public: -File(File &&other) FMT_NOEXCEPT : - fd_(other.fd_) - { - other.fd_ = -1; - } - - File& operator=(File &&other) - { - close(); - fd_ = other.fd_; - other.fd_ = -1; - return *this; - } -#endif - - // Destroys the object closing the file it represents if any. - FMT_API ~File() FMT_NOEXCEPT; - - // Returns the file descriptor. - int descriptor() const FMT_NOEXCEPT - { - return fd_; - } - - // Closes the file. - FMT_API void close(); - - // Returns the file size. The size has signed type for consistency with - // stat::st_size. - FMT_API LongLong size() const; - - // Attempts to read count bytes from the file into the specified buffer. - FMT_API std::size_t read(void *buffer, std::size_t count); - - // Attempts to write count bytes from the specified buffer to the file. - FMT_API std::size_t write(const void *buffer, std::size_t count); - - // Duplicates a file descriptor with the dup function and returns - // the duplicate as a file object. - FMT_API static File dup(int fd); - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - FMT_API void dup2(int fd); - - // Makes fd be the copy of this file descriptor, closing fd first if - // necessary. - FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; - - // Creates a pipe setting up read_end and write_end file objects for reading - // and writing respectively. - FMT_API static void pipe(File &read_end, File &write_end); - - // Creates a BufferedFile object associated with this file and detaches - // this File object from the file. - FMT_API BufferedFile fdopen(const char *mode); -}; - -// Returns the memory page size. -long getpagesize(); - -#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ - !defined(__ANDROID__) && !defined(__CYGWIN__) -# define FMT_LOCALE -#endif - -#ifdef FMT_LOCALE -// A "C" numeric locale. -class Locale -{ -private: -# ifdef _MSC_VER - typedef _locale_t locale_t; - - enum { LC_NUMERIC_MASK = LC_NUMERIC }; - - static locale_t newlocale(int category_mask, const char *locale, locale_t) - { - return _create_locale(category_mask, locale); - } - - static void freelocale(locale_t locale) - { - _free_locale(locale); - } - - static double strtod_l(const char *nptr, char **endptr, _locale_t locale) - { - return _strtod_l(nptr, endptr, locale); - } -# endif - - locale_t locale_; - - FMT_DISALLOW_COPY_AND_ASSIGN(Locale); - -public: - typedef locale_t Type; - - Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) - { - if (!locale_) - FMT_THROW(fmt::SystemError(errno, "cannot create locale")); - } - ~Locale() - { - freelocale(locale_); - } - - Type get() const - { - return locale_; - } - - // Converts string to floating-point number and advances str past the end - // of the parsed input. - double strtod(const char *&str) const - { - char *end = FMT_NULL; - double result = strtod_l(str, &end, locale_); - str = end; - return result; - } -}; -#endif // FMT_LOCALE -} // namespace fmt - -#if !FMT_USE_RVALUE_REFERENCES -namespace std -{ -// For compatibility with C++98. -inline fmt::BufferedFile &move(fmt::BufferedFile &f) -{ - return f; -} -inline fmt::File &move(fmt::File &f) -{ - return f; -} -} -#endif - -#endif // FMT_POSIX_H_ diff --git a/cpp_src/vendor/spdlog/fmt/bundled/printf.cc b/cpp_src/vendor/spdlog/fmt/bundled/printf.cc deleted file mode 100644 index 95d7a36ab..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/printf.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "format.h" -#include "printf.h" - -namespace fmt { - -template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args); - -FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - -#ifndef FMT_HEADER_ONLY - -template void PrintfFormatter::format(CStringRef format); -template void PrintfFormatter::format(WCStringRef format); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt diff --git a/cpp_src/vendor/spdlog/fmt/bundled/printf.h b/cpp_src/vendor/spdlog/fmt/bundled/printf.h deleted file mode 100644 index 14242143f..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/printf.h +++ /dev/null @@ -1,712 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_PRINTF_H_ -#define FMT_PRINTF_H_ - -#include // std::fill_n -#include // std::numeric_limits - -#include "ostream.h" - -namespace fmt -{ -namespace internal -{ - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker -{ - template - static bool fits_in_int(T value) - { - unsigned max = std::numeric_limits::max(); - return value <= max; - } - static bool fits_in_int(bool) - { - return true; - } -}; - -template <> -struct IntChecker -{ - template - static bool fits_in_int(T value) - { - return value >= std::numeric_limits::min() && - value <= std::numeric_limits::max(); - } - static bool fits_in_int(int) - { - return true; - } -}; - -class PrecisionHandler : public ArgVisitor -{ -public: - void report_unhandled_arg() - { - FMT_THROW(FormatError("precision is not integer")); - } - - template - int visit_any_int(T value) - { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast(value); - } -}; - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor -{ -public: - template - bool visit_any_int(T value) - { - return value == 0; - } -}; - -// returns the default type for format specific "%s" -class DefaultType : public ArgVisitor -{ -public: - char visit_char(int) - { - return 'c'; - } - - char visit_bool(bool) - { - return 's'; - } - - char visit_pointer(const void *) - { - return 'p'; - } - - template - char visit_any_int(T) - { - return 'd'; - } - - template - char visit_any_double(T) - { - return 'g'; - } - - char visit_unhandled_arg() - { - return 's'; - } -}; - -template -struct is_same -{ - enum { value = 0 }; -}; - -template -struct is_same -{ - enum { value = 1 }; -}; - -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template -class ArgConverter : public ArgVisitor, void> -{ -private: - internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - -public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - void visit_bool(bool value) - { - if (type_ != 's') - visit_any_int(value); - } - - void visit_char(int value) - { - if (type_ != 's') - visit_any_int(value); - } - - template - void visit_any_int(U value) - { - bool is_signed = type_ == 'd' || type_ == 'i'; - if (type_ == 's') - { - is_signed = std::numeric_limits::is_signed; - } - - using internal::Arg; - typedef typename internal::Conditional< - is_same::value, U, T>::type TargetType; - if (const_check(sizeof(TargetType) <= sizeof(int))) - { - // Extra casts are used to silence warnings. - if (is_signed) - { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } - else - { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); - } - } - else - { - if (is_signed) - { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast(value); - } - else - { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor -{ -private: - internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - -public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) - { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public ArgVisitor -{ -private: - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - -public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - - void report_unhandled_arg() - { - FMT_THROW(FormatError("width is not integer")); - } - - template - unsigned visit_any_int(T value) - { - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType width = static_cast(value); - if (internal::is_negative(value)) - { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - unsigned int_max = std::numeric_limits::max(); - if (width > int_max) - FMT_THROW(FormatError("number is too big")); - return static_cast(width); - } -}; -} // namespace internal - -/** - \rst - A ``printf`` argument formatter based on the `curiously recurring template - pattern `_. - - To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some - or all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its - superclass will be called. - \endrst - */ -template -class BasicPrintfArgFormatter : - public internal::ArgFormatterBase -{ -private: - void write_null_pointer() - { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef internal::ArgFormatterBase Base; - -public: - /** - \rst - Constructs an argument formatter object. - *writer* is a reference to the output writer and *spec* contains format - specifier information for standard argument types. - \endrst - */ - BasicPrintfArgFormatter(BasicWriter &w, Spec &s) - : internal::ArgFormatterBase(w, s) {} - - /** Formats an argument of type ``bool``. */ - void visit_bool(bool value) - { - Spec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - /** Formats a character. */ - void visit_char(int value) - { - const Spec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) - { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) - { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } - else - { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } - else - { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } - - /** Formats a null-terminated C string. */ - void visit_cstring(const char *value) - { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - /** Formats a pointer. */ - void visit_pointer(const void *value) - { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) - { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } -}; - -/** The default printf argument formatter. */ -template -class PrintfArgFormatter : - public BasicPrintfArgFormatter, Char, FormatSpec> -{ -public: - /** Constructs an argument formatter object. */ - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicPrintfArgFormatter, Char, FormatSpec>(w, s) {} -}; - -/** This template formats data and writes the output to a writer. */ -template > -class PrintfFormatter : private internal::FormatterBase -{ -private: - BasicWriter &writer_; - - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - internal::Arg get_arg( - const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - -public: - /** - \rst - Constructs a ``PrintfFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - explicit PrintfFormatter(const ArgList &al, BasicWriter &w) - : FormatterBase(al), writer_(w) {} - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); -}; - -template -void PrintfFormatter::parse_flags(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 -internal::Arg PrintfFormatter::get_arg(const Char *s, - unsigned arg_index) -{ - (void)s; - const char *error = FMT_NULL; - internal::Arg arg = arg_index == std::numeric_limits::max() ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) -{ - unsigned arg_index = std::numeric_limits::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 = internal::parse_nonnegative_int(s); - 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; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') - { - spec.width_ = internal::parse_nonnegative_int(s); - } - else if (*s == '*') - { - ++s; - spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void PrintfFormatter::format(BasicCStringRef format_str) -{ - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) - { - Char c = *s++; - if (c != '%') continue; - if (*s == c) - { - write(writer_, start, s); - start = ++s; - continue; - } - write(writer_, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') - { - ++s; - if ('0' <= *s && *s <= '9') - { - spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); - } - else if (*s == '*') - { - ++s; - spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); - } - else - { - spec.precision_ = 0; - } - } - - using internal::Arg; - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) - spec.flags_ &= ~internal::to_unsigned(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 and convert the argument to the required type. - using internal::ArgConverter; - switch (*s++) - { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - - if (spec.type_ == 's') - { - // set the format type to the default if 's' is specified - spec.type_ = internal::DefaultType().visit(arg); - } - - if (arg.type <= Arg::LAST_INTEGER_TYPE) - { - // Normalize type. - switch (spec.type_) - { - case 'i': - case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - internal::CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - AF(writer_, spec).visit(arg); - } - write(writer_, start, s); -} - -inline void printf(Writer &w, CStringRef format, ArgList args) -{ - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, Writer &, CStringRef) - -inline void printf(WWriter &w, WCStringRef format, ArgList args) -{ - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, WWriter &, WCStringRef) - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(CStringRef format, ArgList args) -{ - MemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC(std::string, sprintf, CStringRef) - -inline std::wstring sprintf(WCStringRef format, ArgList args) -{ - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(CStringRef format, ArgList args) -{ - return fprintf(stdout, format, args); -} -FMT_VARIADIC(int, printf, CStringRef) - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - fprintf(cerr, "Don't %s!", "panic"); - \endrst - */ -inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) -{ - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); -} -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "printf.cc" -#endif - -#endif // FMT_PRINTF_H_ diff --git a/cpp_src/vendor/spdlog/fmt/bundled/time.h b/cpp_src/vendor/spdlog/fmt/bundled/time.h deleted file mode 100644 index 206d09209..000000000 --- a/cpp_src/vendor/spdlog/fmt/bundled/time.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - Formatting library for C++ - time formatting - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_TIME_H_ -#define FMT_TIME_H_ - -#include "format.h" -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // "deprecated" functions -#endif - -namespace fmt -{ -template -void format_arg(BasicFormatter &f, - const char *&format_str, const std::tm &tm) -{ - if (*format_str == ':') - ++format_str; - const char *end = format_str; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - internal::MemoryBuffer format; - format.append(format_str, end + 1); - format[format.size() - 1] = '\0'; - Buffer &buffer = f.writer().buffer(); - std::size_t start = buffer.size(); - for (;;) - { - std::size_t size = buffer.capacity() - start; - std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); - if (count != 0) - { - buffer.resize(start + count); - break; - } - if (size >= format.size() * 256) - { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - format_str = end + 1; -} - -namespace internal -{ -inline Null<> localtime_r(...) -{ - return Null<>(); -} -inline Null<> localtime_s(...) -{ - return Null<>(); -} -inline Null<> gmtime_r(...) -{ - return Null<>(); -} -inline Null<> gmtime_s(...) -{ - return Null<>(); -} -} - -// Thread-safe replacement for std::localtime -inline std::tm localtime(std::time_t time) -{ - struct LocalTime - { - std::time_t time_; - std::tm tm_; - - LocalTime(std::time_t t): time_(t) {} - - bool run() - { - using namespace fmt::internal; - return handle(localtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) - { - return tm != FMT_NULL; - } - - bool handle(internal::Null<>) - { - using namespace fmt::internal; - return fallback(localtime_s(&tm_, &time_)); - } - - bool fallback(int res) - { - return res == 0; - } - - bool fallback(internal::Null<>) - { - using namespace fmt::internal; - std::tm *tm = std::localtime(&time_); - if (tm) tm_ = *tm; - return tm != FMT_NULL; - } - }; - LocalTime lt(time); - if (lt.run()) - return lt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} - -// Thread-safe replacement for std::gmtime -inline std::tm gmtime(std::time_t time) -{ - struct GMTime - { - std::time_t time_; - std::tm tm_; - - GMTime(std::time_t t): time_(t) {} - - bool run() - { - using namespace fmt::internal; - return handle(gmtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) - { - return tm != FMT_NULL; - } - - bool handle(internal::Null<>) - { - using namespace fmt::internal; - return fallback(gmtime_s(&tm_, &time_)); - } - - bool fallback(int res) - { - return res == 0; - } - - bool fallback(internal::Null<>) - { - std::tm *tm = std::gmtime(&time_); - if (tm != FMT_NULL) tm_ = *tm; - return tm != FMT_NULL; - } - }; - GMTime gt(time); - if (gt.run()) - return gt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} -} //namespace fmt - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#endif // FMT_TIME_H_ diff --git a/cpp_src/vendor/spdlog/fmt/chrono.h b/cpp_src/vendor/spdlog/fmt/chrono.h new file mode 100644 index 000000000..a72a5bd64 --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/chrono.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's chrono support +// +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/fmt/compile.h b/cpp_src/vendor/spdlog/fmt/compile.h new file mode 100644 index 000000000..3c9c25d8b --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/compile.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's compile-time support +// +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/fmt/fmt.h b/cpp_src/vendor/spdlog/fmt/fmt.h index 92ca4e50f..7fa6b0933 100644 --- a/cpp_src/vendor/spdlog/fmt/fmt.h +++ b/cpp_src/vendor/spdlog/fmt/fmt.h @@ -1,5 +1,5 @@ // -// Copyright(c) 2016 Gabi Melman. +// Copyright(c) 2016-2018 Gabi Melman. // Distributed under the MIT License (http://opensource.org/licenses/MIT) // @@ -9,26 +9,22 @@ // Include a bundled header-only copy of fmtlib or an external one. // By default spdlog include its own copy. // - -#if !defined(SPDLOG_FMT_EXTERNAL) - -#ifndef FMT_HEADER_ONLY -#define FMT_HEADER_ONLY -#endif -#ifndef FMT_USE_WINDOWS_H -#define FMT_USE_WINDOWS_H 0 -#endif -#include "bundled/format.h" -#if defined(SPDLOG_FMT_PRINTF) -#include "bundled/printf.h" -#endif - -#else //external fmtlib - -#include -#if defined(SPDLOG_FMT_PRINTF) -#include +#include + +#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format + #include +#elif !defined(SPDLOG_FMT_EXTERNAL) + #if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) + #define FMT_HEADER_ONLY + #endif + #ifndef FMT_USE_WINDOWS_H + #define FMT_USE_WINDOWS_H 0 + #endif + + #include + #include + +#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib + #include + #include #endif - -#endif - diff --git a/cpp_src/vendor/spdlog/fmt/ostr.h b/cpp_src/vendor/spdlog/fmt/ostr.h index 5cdd5cd00..2b901055f 100644 --- a/cpp_src/vendor/spdlog/fmt/ostr.h +++ b/cpp_src/vendor/spdlog/fmt/ostr.h @@ -4,14 +4,20 @@ // #pragma once - -// include external or bundled copy of fmtlib's ostream support // -#if !defined(SPDLOG_FMT_EXTERNAL) -#include "fmt.h" -#include "bundled/ostream.h" -#else -#include -#endif - +// include bundled or external copy of fmtlib's ostream support +// +#include +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/fmt/ranges.h b/cpp_src/vendor/spdlog/fmt/ranges.h new file mode 100644 index 000000000..5bb91e9ac --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/ranges.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's ranges support +// +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/fmt/std.h b/cpp_src/vendor/spdlog/fmt/std.h new file mode 100644 index 000000000..dabe6f69d --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/std.h @@ -0,0 +1,24 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's std support (for formatting e.g. +// std::filesystem::path, std::thread::id, std::monostate, std::variant, ...) +// +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/fmt/xchar.h b/cpp_src/vendor/spdlog/fmt/xchar.h new file mode 100644 index 000000000..2525f0586 --- /dev/null +++ b/cpp_src/vendor/spdlog/fmt/xchar.h @@ -0,0 +1,23 @@ +// +// Copyright(c) 2016 Gabi Melman. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) +// + +#pragma once +// +// include bundled or external copy of fmtlib's xchar support +// +#include + +#if !defined(SPDLOG_USE_STD_FORMAT) + #if !defined(SPDLOG_FMT_EXTERNAL) + #ifdef SPDLOG_HEADER_ONLY + #ifndef FMT_HEADER_ONLY + #define FMT_HEADER_ONLY + #endif + #endif + #include + #else + #include + #endif +#endif diff --git a/cpp_src/vendor/spdlog/formatter.h b/cpp_src/vendor/spdlog/formatter.h index 203dc31a7..4d482f827 100644 --- a/cpp_src/vendor/spdlog/formatter.h +++ b/cpp_src/vendor/spdlog/formatter.h @@ -1,47 +1,17 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "details/log_msg.h" +#include +#include -#include -#include -#include +namespace spdlog { -namespace spdlog -{ -namespace details -{ -class flag_formatter; -} - -class formatter -{ +class formatter { public: virtual ~formatter() = default; - virtual void format(details::log_msg& msg) = 0; -}; - -class pattern_formatter SPDLOG_FINAL : public formatter -{ -public: - explicit pattern_formatter(const std::string& pattern, pattern_time_type pattern_time = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); - pattern_formatter(const pattern_formatter&) = delete; - pattern_formatter& operator=(const pattern_formatter&) = delete; - void format(details::log_msg& msg) override; - -private: - const std::string _eol; - const std::string _pattern; - const pattern_time_type _pattern_time; - std::vector> _formatters; - std::tm get_time(details::log_msg& msg); - void handle_flag(char flag); - void compile_pattern(const std::string& pattern); + virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; + virtual std::unique_ptr clone() const = 0; }; -} - -#include "details/pattern_formatter_impl.h" +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/fwd.h b/cpp_src/vendor/spdlog/fwd.h new file mode 100644 index 000000000..647b16bf0 --- /dev/null +++ b/cpp_src/vendor/spdlog/fwd.h @@ -0,0 +1,18 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +namespace spdlog { +class logger; +class formatter; + +namespace sinks { +class sink; +} + +namespace level { +enum level_enum : int; +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/logger-inl.h b/cpp_src/vendor/spdlog/logger-inl.h new file mode 100644 index 000000000..8ca193242 --- /dev/null +++ b/cpp_src/vendor/spdlog/logger-inl.h @@ -0,0 +1,200 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include +#include + +#include + +#include + +namespace spdlog { + +// public methods +SPDLOG_INLINE logger::logger(const logger &other) + : name_(other.name_), + sinks_(other.sinks_), + level_(other.level_.load(std::memory_order_relaxed)), + flush_level_(other.flush_level_.load(std::memory_order_relaxed)), + custom_err_handler_(other.custom_err_handler_), + tracer_(other.tracer_) {} + +SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT + : name_(std::move(other.name_)), + sinks_(std::move(other.sinks_)), + level_(other.level_.load(std::memory_order_relaxed)), + flush_level_(other.flush_level_.load(std::memory_order_relaxed)), + custom_err_handler_(std::move(other.custom_err_handler_)), + tracer_(std::move(other.tracer_)) + +{} + +SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT { + this->swap(other); + return *this; +} + +SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT { + name_.swap(other.name_); + sinks_.swap(other.sinks_); + + // swap level_ + auto other_level = other.level_.load(); + auto my_level = level_.exchange(other_level); + other.level_.store(my_level); + + // swap flush level_ + other_level = other.flush_level_.load(); + my_level = flush_level_.exchange(other_level); + other.flush_level_.store(my_level); + + custom_err_handler_.swap(other.custom_err_handler_); + std::swap(tracer_, other.tracer_); +} + +SPDLOG_INLINE void swap(logger &a, logger &b) { a.swap(b); } + +SPDLOG_INLINE void logger::set_level(level::level_enum log_level) { level_.store(log_level); } + +SPDLOG_INLINE level::level_enum logger::level() const { + return static_cast(level_.load(std::memory_order_relaxed)); +} + +SPDLOG_INLINE const std::string &logger::name() const { return name_; } + +// set formatting for the sinks in this logger. +// each sink will get a separate instance of the formatter object. +SPDLOG_INLINE void logger::set_formatter(std::unique_ptr f) { + for (auto it = sinks_.begin(); it != sinks_.end(); ++it) { + if (std::next(it) == sinks_.end()) { + // last element - we can be move it. + (*it)->set_formatter(std::move(f)); + break; // to prevent clang-tidy warning + } else { + (*it)->set_formatter(f->clone()); + } + } +} + +SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type) { + auto new_formatter = details::make_unique(std::move(pattern), time_type); + set_formatter(std::move(new_formatter)); +} + +// create new backtrace sink and move to it all our child sinks +SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages) { tracer_.enable(n_messages); } + +// restore orig sinks and level and delete the backtrace sink +SPDLOG_INLINE void logger::disable_backtrace() { tracer_.disable(); } + +SPDLOG_INLINE void logger::dump_backtrace() { dump_backtrace_(); } + +// flush functions +SPDLOG_INLINE void logger::flush() { flush_(); } + +SPDLOG_INLINE void logger::flush_on(level::level_enum log_level) { flush_level_.store(log_level); } + +SPDLOG_INLINE level::level_enum logger::flush_level() const { + return static_cast(flush_level_.load(std::memory_order_relaxed)); +} + +// sinks +SPDLOG_INLINE const std::vector &logger::sinks() const { return sinks_; } + +SPDLOG_INLINE std::vector &logger::sinks() { return sinks_; } + +// error handler +SPDLOG_INLINE void logger::set_error_handler(err_handler handler) { + custom_err_handler_ = std::move(handler); +} + +// create new logger with same sinks and configuration. +SPDLOG_INLINE std::shared_ptr logger::clone(std::string logger_name) { + auto cloned = std::make_shared(*this); + cloned->name_ = std::move(logger_name); + return cloned; +} + +// protected methods +SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, + bool log_enabled, + bool traceback_enabled) { + if (log_enabled) { + sink_it_(log_msg); + } + if (traceback_enabled) { + tracer_.push_back(log_msg); + } +} + +SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) { + for (auto &sink : sinks_) { + if (sink->should_log(msg.level)) { + SPDLOG_TRY { sink->log(msg); } + SPDLOG_LOGGER_CATCH(msg.source) + } + } + + if (should_flush_(msg)) { + flush_(); + } +} + +SPDLOG_INLINE void logger::flush_() { + for (auto &sink : sinks_) { + SPDLOG_TRY { sink->flush(); } + SPDLOG_LOGGER_CATCH(source_loc()) + } +} + +SPDLOG_INLINE void logger::dump_backtrace_() { + using details::log_msg; + if (tracer_.enabled() && !tracer_.empty()) { + sink_it_( + log_msg{name(), level::info, "****************** Backtrace Start ******************"}); + tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); }); + sink_it_( + log_msg{name(), level::info, "****************** Backtrace End ********************"}); + } +} + +SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) { + auto flush_level = flush_level_.load(std::memory_order_relaxed); + return (msg.level >= flush_level) && (msg.level != level::off); +} + +SPDLOG_INLINE void logger::err_handler_(const std::string &msg) { + if (custom_err_handler_) { + custom_err_handler_(msg); + } else { + using reindexer::system_clock_w; // Using alternative clocks to avoid vDSO issues on some systems + static std::mutex mutex; + static system_clock_w::time_point last_report_time; + static size_t err_counter = 0; + std::lock_guard lk{mutex}; + auto now = system_clock_w::now(); + err_counter++; + if (now - last_report_time < std::chrono::seconds(1)) { + return; + } + last_report_time = now; + auto tm_time = details::os::localtime(system_clock_w::to_time_t(now)); + char date_buf[64]; + std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); +#if defined(USING_R) && defined(R_R_H) // if in R environment + REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, name().c_str(), + msg.c_str()); +#else + std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] %s\n", err_counter, date_buf, + name().c_str(), msg.c_str()); +#endif + } +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/logger.h b/cpp_src/vendor/spdlog/logger.h index 5502d273b..f49bdc009 100644 --- a/cpp_src/vendor/spdlog/logger.h +++ b/cpp_src/vendor/spdlog/logger.h @@ -1,110 +1,379 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -// Thread safe logger (except for set_pattern(..), set_formatter(..) and set_error_handler()) +// Thread safe logger (except for set_error_handler()) // Has name, log level, vector of std::shared sink pointers and formatter // Upon each log write the logger: -// 1. Checks if its log level is enough to log the message -// 2. Format the message using the formatter function -// 3. Pass the formatted message to its sinks to performa the actual logging +// 1. Checks if its log level is enough to log the message and if yes: +// 2. Call the underlying sinks to do the job. +// 3. Each sink use its own private copy of a formatter to format the message +// and send to its destination. +// +// The use of private formatter per sink provides the opportunity to cache some +// formatted data, and support for different format per sink. + +#include +#include +#include -#include "sinks/base_sink.h" -#include "common.h" +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + #ifndef _WIN32 + #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows + #endif + #include +#endif #include -#include -#include -namespace spdlog -{ +#ifndef SPDLOG_NO_EXCEPTIONS + #define SPDLOG_LOGGER_CATCH(location) \ + catch (const std::exception &ex) { \ + if (location.filename) { \ + err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), \ + location.filename, location.line)); \ + } else { \ + err_handler_(ex.what()); \ + } \ + } \ + catch (...) { \ + err_handler_("Rethrowing unknown exception in logger"); \ + throw; \ + } +#else + #define SPDLOG_LOGGER_CATCH(location) +#endif + +namespace spdlog { -class logger -{ +class SPDLOG_API logger { public: - logger(const std::string& name, sink_ptr single_sink); - logger(const std::string& name, sinks_init_list sinks); + // Empty logger + explicit logger(std::string name) + : name_(std::move(name)), + sinks_() {} + + // Logger with range on sinks + template + logger(std::string name, It begin, It end) + : name_(std::move(name)), + sinks_(begin, end) {} + + // Logger with single sink + logger(std::string name, sink_ptr single_sink) + : logger(std::move(name), {std::move(single_sink)}) {} + + // Logger with sinks init list + logger(std::string name, sinks_init_list sinks) + : logger(std::move(name), sinks.begin(), sinks.end()) {} + + virtual ~logger() = default; + + logger(const logger &other); + logger(logger &&other) SPDLOG_NOEXCEPT; + logger &operator=(logger other) SPDLOG_NOEXCEPT; + void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; + + template + void log(source_loc loc, level::level_enum lvl, format_string_t fmt, Args &&...args) { + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); + } + + template + void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { + log(source_loc{}, lvl, fmt, std::forward(args)...); + } + + template + void log(level::level_enum lvl, const T &msg) { + log(source_loc{}, lvl, msg); + } + + // T cannot be statically converted to format string (including string_view/wstring_view) + template ::value, + int>::type = 0> + void log(source_loc loc, level::level_enum lvl, const T &msg) { + log(loc, lvl, "{}", msg); + } - template - logger(std::string name, const It& begin, const It& end); + void log(log_clock::time_point log_time, + source_loc loc, + level::level_enum lvl, + string_view_t msg) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } - virtual ~logger(); + details::log_msg log_msg(log_time, loc, name_, lvl, msg); + log_it_(log_msg, log_enabled, traceback_enabled); + } - logger(const logger&) = delete; - logger& operator=(const logger&) = delete; + void log(source_loc loc, level::level_enum lvl, string_view_t msg) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } - template void log(level::level_enum lvl, const char* fmt, const Args&... args); - template void log(level::level_enum lvl, const char* msg); - template void trace(const char* fmt, const Arg1&, const Args&... args); - template void debug(const char* fmt, const Arg1&, const Args&... args); - template void info(const char* fmt, const Arg1&, const Args&... args); - template void warn(const char* fmt, const Arg1&, const Args&... args); - template void error(const char* fmt, const Arg1&, const Args&... args); - template void critical(const char* fmt, const Arg1&, const Args&... args); + details::log_msg log_msg(loc, name_, lvl, msg); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(level::level_enum lvl, string_view_t msg) { log(source_loc{}, lvl, msg); } + + template + void trace(format_string_t fmt, Args &&...args) { + log(level::trace, fmt, std::forward(args)...); + } + + template + void debug(format_string_t fmt, Args &&...args) { + log(level::debug, fmt, std::forward(args)...); + } + + template + void info(format_string_t fmt, Args &&...args) { + log(level::info, fmt, std::forward(args)...); + } + + template + void warn(format_string_t fmt, Args &&...args) { + log(level::warn, fmt, std::forward(args)...); + } + + template + void error(format_string_t fmt, Args &&...args) { + log(level::err, fmt, std::forward(args)...); + } + + template + void critical(format_string_t fmt, Args &&...args) { + log(level::critical, fmt, std::forward(args)...); + } #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT - template void log(level::level_enum lvl, const wchar_t* msg); - template void log(level::level_enum lvl, const wchar_t* fmt, const Args&... args); - template void trace(const wchar_t* fmt, const Args&... args); - template void debug(const wchar_t* fmt, const Args&... args); - template void info(const wchar_t* fmt, const Args&... args); - template void warn(const wchar_t* fmt, const Args&... args); - template void error(const wchar_t* fmt, const Args&... args); - template void critical(const wchar_t* fmt, const Args&... args); -#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT - - template void log(level::level_enum lvl, const T&); - template void trace(const T& msg); - template void debug(const T& msg); - template void info(const T& msg); - template void warn(const T& msg); - template void error(const T& msg); - template void critical(const T& msg); - - bool should_log(level::level_enum msg_level) const; + template + void log(source_loc loc, level::level_enum lvl, wformat_string_t fmt, Args &&...args) { + log_(loc, lvl, details::to_string_view(fmt), std::forward(args)...); + } + + template + void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { + log(source_loc{}, lvl, fmt, std::forward(args)...); + } + + void log(log_clock::time_point log_time, + source_loc loc, + level::level_enum lvl, + wstring_view_t msg) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + + void log(level::level_enum lvl, wstring_view_t msg) { log(source_loc{}, lvl, msg); } + + template + void trace(wformat_string_t fmt, Args &&...args) { + log(level::trace, fmt, std::forward(args)...); + } + + template + void debug(wformat_string_t fmt, Args &&...args) { + log(level::debug, fmt, std::forward(args)...); + } + + template + void info(wformat_string_t fmt, Args &&...args) { + log(level::info, fmt, std::forward(args)...); + } + + template + void warn(wformat_string_t fmt, Args &&...args) { + log(level::warn, fmt, std::forward(args)...); + } + + template + void error(wformat_string_t fmt, Args &&...args) { + log(level::err, fmt, std::forward(args)...); + } + + template + void critical(wformat_string_t fmt, Args &&...args) { + log(level::critical, fmt, std::forward(args)...); + } +#endif + + template + void trace(const T &msg) { + log(level::trace, msg); + } + + template + void debug(const T &msg) { + log(level::debug, msg); + } + + template + void info(const T &msg) { + log(level::info, msg); + } + + template + void warn(const T &msg) { + log(level::warn, msg); + } + + template + void error(const T &msg) { + log(level::err, msg); + } + + template + void critical(const T &msg) { + log(level::critical, msg); + } + + // return true logging is enabled for the given level. + bool should_log(level::level_enum msg_level) const { + return msg_level >= level_.load(std::memory_order_relaxed); + } + + // return true if backtrace logging is enabled. + bool should_backtrace() const { return tracer_.enabled(); } + void set_level(level::level_enum log_level); + level::level_enum level() const; - const std::string& name() const; - void set_pattern(const std::string& pattern, pattern_time_type pattern_time = pattern_time_type::local); - void set_formatter(formatter_ptr msg_formatter); - // automatically call flush() if message level >= log_level + const std::string &name() const; + + // set formatting for the sinks in this logger. + // each sink will get a separate instance of the formatter object. + void set_formatter(std::unique_ptr f); + + // set formatting for the sinks in this logger. + // equivalent to + // set_formatter(make_unique(pattern, time_type)) + // Note: each sink will get a new instance of a formatter object, replacing the old one. + void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local); + + // backtrace support. + // efficiently store all debug/trace messages in a circular buffer until needed for debugging. + void enable_backtrace(size_t n_messages); + void disable_backtrace(); + void dump_backtrace(); + + // flush functions + void flush(); void flush_on(level::level_enum log_level); + level::level_enum flush_level() const; - virtual void flush(); + // sinks + const std::vector &sinks() const; - const std::vector& sinks() const; + std::vector &sinks(); // error handler - virtual void set_error_handler(log_err_handler err_handler); - virtual log_err_handler error_handler(); + void set_error_handler(err_handler); + + // create new logger with same sinks and configuration. + virtual std::shared_ptr clone(std::string logger_name); protected: - virtual void _sink_it(details::log_msg& msg); - virtual void _set_pattern(const std::string& pattern, pattern_time_type pattern_time); - virtual void _set_formatter(formatter_ptr msg_formatter); - - // default error handler: print the error to stderr with the max rate of 1 message/minute - virtual void _default_err_handler(const std::string &msg); - - // return true if the given message level should trigger a flush - bool _should_flush_on(const details::log_msg& msg); - - // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)) - void _incr_msg_counter(details::log_msg& msg); - - const std::string _name; - std::vector _sinks; - formatter_ptr _formatter; - spdlog::level_t _level; - spdlog::level_t _flush_level; - log_err_handler _err_handler; - std::atomic _last_err_time; - std::atomic _msg_counter; + std::string name_; + std::vector sinks_; + spdlog::level_t level_{level::info}; + spdlog::level_t flush_level_{level::off}; + err_handler custom_err_handler_{nullptr}; + details::backtracer tracer_; + + // common implementation for after templated public api has been resolved + template + void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } + SPDLOG_TRY { + memory_buf_t buf; +#ifdef SPDLOG_USE_STD_FORMAT + fmt_lib::vformat_to(std::back_inserter(buf), fmt, fmt_lib::make_format_args(args...)); +#else + fmt::vformat_to(fmt::appender(buf), fmt, fmt::make_format_args(args...)); +#endif + + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + SPDLOG_LOGGER_CATCH(loc) + } + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + template + void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args) { + bool log_enabled = should_log(lvl); + bool traceback_enabled = tracer_.enabled(); + if (!log_enabled && !traceback_enabled) { + return; + } + SPDLOG_TRY { + // format to wmemory_buffer and convert to utf8 + wmemory_buf_t wbuf; + fmt_lib::vformat_to(std::back_inserter(wbuf), fmt, + fmt_lib::make_format_args(args...)); + + memory_buf_t buf; + details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf); + details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); + log_it_(log_msg, log_enabled, traceback_enabled); + } + SPDLOG_LOGGER_CATCH(loc) + } +#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT + + // log the given message (if the given log level is high enough), + // and save backtrace (if backtrace is enabled). + void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled); + virtual void sink_it_(const details::log_msg &msg); + virtual void flush_(); + void dump_backtrace_(); + bool should_flush_(const details::log_msg &msg); + + // handle errors during logging. + // default handler prints the error to stderr at max rate of 1 message/sec. + void err_handler_(const std::string &msg); }; -} -#include "details/logger_impl.h" +void swap(logger &a, logger &b); + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "logger-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/mdc.h b/cpp_src/vendor/spdlog/mdc.h new file mode 100644 index 000000000..41f0c1f3f --- /dev/null +++ b/cpp_src/vendor/spdlog/mdc.h @@ -0,0 +1,46 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include + +#include + +// MDC is a simple map of key->string values stored in thread local storage whose content will be printed by the loggers. +// Note: Not supported in async mode (thread local storage - so the async thread pool have different copy). +// +// Usage example: +// spdlog::mdc::put("mdc_key_1", "mdc_value_1"); +// spdlog::info("Hello, {}", "World!"); // => [2024-04-26 02:08:05.040] [info] [mdc_key_1:mdc_value_1] Hello, World! + +namespace spdlog { +class SPDLOG_API mdc { +public: + using mdc_map_t = std::map; + + static void put(const std::string &key, const std::string &value) { + get_context()[key] = value; + } + + static std::string get(const std::string &key) { + auto &context = get_context(); + auto it = context.find(key); + if (it != context.end()) { + return it->second; + } + return ""; + } + + static void remove(const std::string &key) { get_context().erase(key); } + + static void clear() { get_context().clear(); } + + static mdc_map_t &get_context() { + static thread_local mdc_map_t context; + return context; + } +}; + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/pattern_formatter-inl.h b/cpp_src/vendor/spdlog/pattern_formatter-inl.h new file mode 100644 index 000000000..756e59415 --- /dev/null +++ b/cpp_src/vendor/spdlog/pattern_formatter-inl.h @@ -0,0 +1,1324 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace details { + +/////////////////////////////////////////////////////////////////////// +// name & level pattern appender +/////////////////////////////////////////////////////////////////////// + +class scoped_padder { +public: + scoped_padder(size_t wrapped_size, const padding_info &padinfo, memory_buf_t &dest) + : padinfo_(padinfo), + dest_(dest) { + remaining_pad_ = static_cast(padinfo.width_) - static_cast(wrapped_size); + if (remaining_pad_ <= 0) { + return; + } + + if (padinfo_.side_ == padding_info::pad_side::left) { + pad_it(remaining_pad_); + remaining_pad_ = 0; + } else if (padinfo_.side_ == padding_info::pad_side::center) { + auto half_pad = remaining_pad_ / 2; + auto reminder = remaining_pad_ & 1; + pad_it(half_pad); + remaining_pad_ = half_pad + reminder; // for the right side + } + } + + template + static unsigned int count_digits(T n) { + return fmt_helper::count_digits(n); + } + + ~scoped_padder() { + if (remaining_pad_ >= 0) { + pad_it(remaining_pad_); + } else if (padinfo_.truncate_) { + long new_size = static_cast(dest_.size()) + remaining_pad_; + dest_.resize(static_cast(new_size)); + } + } + +private: + void pad_it(long count) { + fmt_helper::append_string_view(string_view_t(spaces_.data(), static_cast(count)), + dest_); + } + + const padding_info &padinfo_; + memory_buf_t &dest_; + long remaining_pad_; + string_view_t spaces_{" ", 64}; +}; + +struct null_scoped_padder { + null_scoped_padder(size_t /*wrapped_size*/, + const padding_info & /*padinfo*/, + memory_buf_t & /*dest*/) {} + + template + static unsigned int count_digits(T /* number */) { + return 0; + } +}; + +template +class name_formatter final : public flag_formatter { +public: + explicit name_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + ScopedPadder p(msg.logger_name.size(), padinfo_, dest); + fmt_helper::append_string_view(msg.logger_name, dest); + } +}; + +// log level appender +template +class level_formatter final : public flag_formatter { +public: + explicit level_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + const string_view_t &level_name = level::to_string_view(msg.level); + ScopedPadder p(level_name.size(), padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } +}; + +// short log level appender +template +class short_level_formatter final : public flag_formatter { +public: + explicit short_level_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + string_view_t level_name{level::to_short_c_str(msg.level)}; + ScopedPadder p(level_name.size(), padinfo_, dest); + fmt_helper::append_string_view(level_name, dest); + } +}; + +/////////////////////////////////////////////////////////////////////// +// Date time pattern appenders +/////////////////////////////////////////////////////////////////////// + +static const char *ampm(const tm &t) { return t.tm_hour >= 12 ? "PM" : "AM"; } + +static int to12h(const tm &t) { return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; } + +// Abbreviated weekday name +static std::array days{{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}}; + +template +class a_formatter final : public flag_formatter { +public: + explicit a_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + string_view_t field_value{days[static_cast(tm_time.tm_wday)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full weekday name +static std::array full_days{ + {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}}; + +template +class A_formatter : public flag_formatter { +public: + explicit A_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + string_view_t field_value{full_days[static_cast(tm_time.tm_wday)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Abbreviated month +static const std::array months{ + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"}}; + +template +class b_formatter final : public flag_formatter { +public: + explicit b_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + string_view_t field_value{months[static_cast(tm_time.tm_mon)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Full month name +static const std::array full_months{{"January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December"}}; + +template +class B_formatter final : public flag_formatter { +public: + explicit B_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + string_view_t field_value{full_months[static_cast(tm_time.tm_mon)]}; + ScopedPadder p(field_value.size(), padinfo_, dest); + fmt_helper::append_string_view(field_value, dest); + } +}; + +// Date and time representation (Thu Aug 23 15:35:46 2014) +template +class c_formatter final : public flag_formatter { +public: + explicit c_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 24; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::append_string_view(days[static_cast(tm_time.tm_wday)], dest); + dest.push_back(' '); + fmt_helper::append_string_view(months[static_cast(tm_time.tm_mon)], dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_mday, dest); + dest.push_back(' '); + // time + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// year - 2 digit +template +class C_formatter final : public flag_formatter { +public: + explicit C_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 +template +class D_formatter final : public flag_formatter { +public: + explicit D_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 10; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_mday, dest); + dest.push_back('/'); + fmt_helper::pad2(tm_time.tm_year % 100, dest); + } +}; + +// year - 4 digit +template +class Y_formatter final : public flag_formatter { +public: + explicit Y_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 4; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(tm_time.tm_year + 1900, dest); + } +}; + +// month 1-12 +template +class m_formatter final : public flag_formatter { +public: + explicit m_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mon + 1, dest); + } +}; + +// day of month 1-31 +template +class d_formatter final : public flag_formatter { +public: + explicit d_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_mday, dest); + } +}; + +// hours in 24 format 0-23 +template +class H_formatter final : public flag_formatter { +public: + explicit H_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_hour, dest); + } +}; + +// hours in 12 format 1-12 +template +class I_formatter final : public flag_formatter { +public: + explicit I_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(to12h(tm_time), dest); + } +}; + +// minutes 0-59 +template +class M_formatter final : public flag_formatter { +public: + explicit M_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// seconds 0-59 +template +class S_formatter final : public flag_formatter { +public: + explicit S_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// milliseconds +template +class e_formatter final : public flag_formatter { +public: + explicit e_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + auto millis = fmt_helper::time_fraction(msg.time); + const size_t field_size = 3; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad3(static_cast(millis.count()), dest); + } +}; + +// microseconds +template +class f_formatter final : public flag_formatter { +public: + explicit f_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + auto micros = fmt_helper::time_fraction(msg.time); + + const size_t field_size = 6; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad6(static_cast(micros.count()), dest); + } +}; + +// nanoseconds +template +class F_formatter final : public flag_formatter { +public: + explicit F_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + auto ns = fmt_helper::time_fraction(msg.time); + const size_t field_size = 9; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::pad9(static_cast(ns.count()), dest); + } +}; + +// seconds since epoch +template +class E_formatter final : public flag_formatter { +public: + explicit E_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + const size_t field_size = 10; + ScopedPadder p(field_size, padinfo_, dest); + auto duration = msg.time.time_since_epoch(); + auto seconds = std::chrono::duration_cast(duration).count(); + fmt_helper::append_int(seconds, dest); + } +}; + +// AM/PM +template +class p_formatter final : public flag_formatter { +public: + explicit p_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 2; + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 12 hour clock 02:55:02 pm +template +class r_formatter final : public flag_formatter { +public: + explicit r_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 11; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(to12h(tm_time), dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + dest.push_back(' '); + fmt_helper::append_string_view(ampm(tm_time), dest); + } +}; + +// 24-hour HH:MM time, equivalent to %H:%M +template +class R_formatter final : public flag_formatter { +public: + explicit R_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 5; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + } +}; + +// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S +template +class T_formatter final : public flag_formatter { +public: + explicit T_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 8; + ScopedPadder p(field_size, padinfo_, dest); + + fmt_helper::pad2(tm_time.tm_hour, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_min, dest); + dest.push_back(':'); + fmt_helper::pad2(tm_time.tm_sec, dest); + } +}; + +// ISO 8601 offset from UTC in timezone (+-HH:MM) +template +class z_formatter final : public flag_formatter { +public: + explicit z_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + z_formatter() = default; + z_formatter(const z_formatter &) = delete; + z_formatter &operator=(const z_formatter &) = delete; + + void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override { + const size_t field_size = 6; + ScopedPadder p(field_size, padinfo_, dest); + + auto total_minutes = get_cached_offset(msg, tm_time); + bool is_negative = total_minutes < 0; + if (is_negative) { + total_minutes = -total_minutes; + dest.push_back('-'); + } else { + dest.push_back('+'); + } + + fmt_helper::pad2(total_minutes / 60, dest); // hours + dest.push_back(':'); + fmt_helper::pad2(total_minutes % 60, dest); // minutes + } + +private: + log_clock::time_point last_update_{std::chrono::seconds(0)}; + int offset_minutes_{0}; + + int get_cached_offset(const log_msg &msg, const std::tm &tm_time) { + // refresh every 10 seconds + if (msg.time - last_update_ >= std::chrono::seconds(10)) { + offset_minutes_ = os::utc_minutes_offset(tm_time); + last_update_ = msg.time; + } + return offset_minutes_; + } +}; + +// Thread id +template +class t_formatter final : public flag_formatter { +public: + explicit t_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + const auto field_size = ScopedPadder::count_digits(msg.thread_id); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.thread_id, dest); + } +}; + +// Current pid +template +class pid_formatter final : public flag_formatter { +public: + explicit pid_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override { + const auto pid = static_cast(details::os::pid()); + auto field_size = ScopedPadder::count_digits(pid); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(pid, dest); + } +}; + +template +class v_formatter final : public flag_formatter { +public: + explicit v_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + ScopedPadder p(msg.payload.size(), padinfo_, dest); + fmt_helper::append_string_view(msg.payload, dest); + } +}; + +class ch_formatter final : public flag_formatter { +public: + explicit ch_formatter(char ch) + : ch_(ch) {} + + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override { + dest.push_back(ch_); + } + +private: + char ch_; +}; + +// aggregate user chars to display as is +class aggregate_formatter final : public flag_formatter { +public: + aggregate_formatter() = default; + + void add_ch(char ch) { str_ += ch; } + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override { + fmt_helper::append_string_view(str_, dest); + } + +private: + std::string str_; +}; + +// mark the color range. expect it to be in the form of "%^colored text%$" +class color_start_formatter final : public flag_formatter { +public: + explicit color_start_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + msg.color_range_start = dest.size(); + } +}; + +class color_stop_formatter final : public flag_formatter { +public: + explicit color_stop_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + msg.color_range_end = dest.size(); + } +}; + +// print source location +template +class source_location_formatter final : public flag_formatter { +public: + explicit source_location_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } + + size_t text_size; + if (padinfo_.enabled()) { + // calc text size for padding based on "filename:line" + text_size = std::char_traits::length(msg.source.filename) + + ScopedPadder::count_digits(msg.source.line) + 1; + } else { + text_size = 0; + } + + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + } +}; + +// print source filename +template +class source_filename_formatter final : public flag_formatter { +public: + explicit source_filename_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } + size_t text_size = + padinfo_.enabled() ? std::char_traits::length(msg.source.filename) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.filename, dest); + } +}; + +template +class short_filename_formatter final : public flag_formatter { +public: + explicit short_filename_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable : 4127) // consider using 'if constexpr' instead +#endif // _MSC_VER + static const char *basename(const char *filename) { + // if the size is 2 (1 character + null terminator) we can use the more efficient strrchr + // the branch will be elided by optimizations + if (sizeof(os::folder_seps) == 2) { + const char *rv = std::strrchr(filename, os::folder_seps[0]); + return rv != nullptr ? rv + 1 : filename; + } else { + const std::reverse_iterator begin(filename + std::strlen(filename)); + const std::reverse_iterator end(filename); + + const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps), + std::end(os::folder_seps) - 1); + return it != end ? it.base() : filename; + } + } +#ifdef _MSC_VER + #pragma warning(pop) +#endif // _MSC_VER + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } + auto filename = basename(msg.source.filename); + size_t text_size = padinfo_.enabled() ? std::char_traits::length(filename) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(filename, dest); + } +}; + +template +class source_linenum_formatter final : public flag_formatter { +public: + explicit source_linenum_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } + + auto field_size = ScopedPadder::count_digits(msg.source.line); + ScopedPadder p(field_size, padinfo_, dest); + fmt_helper::append_int(msg.source.line, dest); + } +}; + +// print source funcname +template +class source_funcname_formatter final : public flag_formatter { +public: + explicit source_funcname_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + if (msg.source.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } + size_t text_size = + padinfo_.enabled() ? std::char_traits::length(msg.source.funcname) : 0; + ScopedPadder p(text_size, padinfo_, dest); + fmt_helper::append_string_view(msg.source.funcname, dest); + } +}; + +// print elapsed time since last message +template +class elapsed_formatter final : public flag_formatter { +public: + using DurationUnits = Units; + + explicit elapsed_formatter(padding_info padinfo) + : flag_formatter(padinfo), + last_message_time_(log_clock::now()) {} + + void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { + auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero()); + auto delta_units = std::chrono::duration_cast(delta); + last_message_time_ = msg.time; + auto delta_count = static_cast(delta_units.count()); + auto n_digits = static_cast(ScopedPadder::count_digits(delta_count)); + ScopedPadder p(n_digits, padinfo_, dest); + fmt_helper::append_int(delta_count, dest); + } + +private: + log_clock::time_point last_message_time_; +}; + +// Class for formatting Mapped Diagnostic Context (MDC) in log messages. +// Example: [logger-name] [info] [mdc_key_1:mdc_value_1 mdc_key_2:mdc_value_2] some message +template +class mdc_formatter : public flag_formatter { +public: + explicit mdc_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &, const std::tm &, memory_buf_t &dest) override { + auto &mdc_map = mdc::get_context(); + if (mdc_map.empty()) { + ScopedPadder p(0, padinfo_, dest); + return; + } else { + format_mdc(mdc_map, dest); + } + } + + void format_mdc(const mdc::mdc_map_t &mdc_map, memory_buf_t &dest) { + auto last_element = --mdc_map.end(); + for (auto it = mdc_map.begin(); it != mdc_map.end(); ++it) { + auto &pair = *it; + const auto &key = pair.first; + const auto &value = pair.second; + size_t content_size = key.size() + value.size() + 1; // 1 for ':' + + if (it != last_element) { + content_size++; // 1 for ' ' + } + + ScopedPadder p(content_size, padinfo_, dest); + fmt_helper::append_string_view(key, dest); + fmt_helper::append_string_view(":", dest); + fmt_helper::append_string_view(value, dest); + if (it != last_element) { + fmt_helper::append_string_view(" ", dest); + } + } + } +}; + +// Full info formatter +// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] [%s:%#] %v +class full_formatter final : public flag_formatter { +public: + explicit full_formatter(padding_info padinfo) + : flag_formatter(padinfo) {} + + void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) override { + using std::chrono::duration_cast; + using std::chrono::milliseconds; + using std::chrono::seconds; + + // cache the date/time part for the next second. + auto duration = msg.time.time_since_epoch(); + auto secs = duration_cast(duration); + + if (cache_timestamp_ != secs || cached_datetime_.size() == 0) { + cached_datetime_.clear(); + cached_datetime_.push_back('['); + fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_); + cached_datetime_.push_back('-'); + + fmt_helper::pad2(tm_time.tm_mday, cached_datetime_); + cached_datetime_.push_back(' '); + + fmt_helper::pad2(tm_time.tm_hour, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_min, cached_datetime_); + cached_datetime_.push_back(':'); + + fmt_helper::pad2(tm_time.tm_sec, cached_datetime_); + cached_datetime_.push_back('.'); + + cache_timestamp_ = secs; + } + dest.append(cached_datetime_.begin(), cached_datetime_.end()); + + auto millis = fmt_helper::time_fraction(msg.time); + fmt_helper::pad3(static_cast(millis.count()), dest); + dest.push_back(']'); + dest.push_back(' '); + + // append logger name if exists + if (msg.logger_name.size() > 0) { + dest.push_back('['); + fmt_helper::append_string_view(msg.logger_name, dest); + dest.push_back(']'); + dest.push_back(' '); + } + + dest.push_back('['); + // wrap the level name with color + msg.color_range_start = dest.size(); + // fmt_helper::append_string_view(level::to_c_str(msg.level), dest); + fmt_helper::append_string_view(level::to_string_view(msg.level), dest); + msg.color_range_end = dest.size(); + dest.push_back(']'); + dest.push_back(' '); + + // add source location if present + if (!msg.source.empty()) { + dest.push_back('['); + const char *filename = + details::short_filename_formatter::basename( + msg.source.filename); + fmt_helper::append_string_view(filename, dest); + dest.push_back(':'); + fmt_helper::append_int(msg.source.line, dest); + dest.push_back(']'); + dest.push_back(' '); + } + + // add mdc if present + auto &mdc_map = mdc::get_context(); + if (!mdc_map.empty()) { + dest.push_back('['); + mdc_formatter_.format_mdc(mdc_map, dest); + dest.push_back(']'); + dest.push_back(' '); + } + // fmt_helper::append_string_view(msg.msg(), dest); + fmt_helper::append_string_view(msg.payload, dest); + } + +private: + std::chrono::seconds cache_timestamp_{0}; + memory_buf_t cached_datetime_; + mdc_formatter mdc_formatter_{padding_info{}}; +}; + +} // namespace details + +SPDLOG_INLINE pattern_formatter::pattern_formatter(std::string pattern, + pattern_time_type time_type, + std::string eol, + custom_flags custom_user_flags) + : pattern_(std::move(pattern)), + eol_(std::move(eol)), + pattern_time_type_(time_type), + need_localtime_(false), + last_log_secs_(0), + custom_handlers_(std::move(custom_user_flags)) { + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + compile_pattern_(pattern_); +} + +// use by default full formatter for if pattern is not given +SPDLOG_INLINE pattern_formatter::pattern_formatter(pattern_time_type time_type, std::string eol) + : pattern_("%+"), + eol_(std::move(eol)), + pattern_time_type_(time_type), + need_localtime_(true), + last_log_secs_(0) { + std::memset(&cached_tm_, 0, sizeof(cached_tm_)); + formatters_.push_back(details::make_unique(details::padding_info{})); +} + +SPDLOG_INLINE std::unique_ptr pattern_formatter::clone() const { + custom_flags cloned_custom_formatters; + for (auto &it : custom_handlers_) { + cloned_custom_formatters[it.first] = it.second->clone(); + } + auto cloned = details::make_unique(pattern_, pattern_time_type_, eol_, + std::move(cloned_custom_formatters)); + cloned->need_localtime(need_localtime_); +#if defined(__GNUC__) && __GNUC__ < 5 + return std::move(cloned); +#else + return cloned; +#endif +} + +SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest) { + if (need_localtime_) { + const auto secs = + std::chrono::duration_cast(msg.time.time_since_epoch()); + if (secs != last_log_secs_) { + cached_tm_ = get_time_(msg); + last_log_secs_ = secs; + } + } + + for (auto &f : formatters_) { + f->format(msg, cached_tm_, dest); + } + // write eol + details::fmt_helper::append_string_view(eol_, dest); +} + +SPDLOG_INLINE void pattern_formatter::set_pattern(std::string pattern) { + pattern_ = std::move(pattern); + need_localtime_ = false; + compile_pattern_(pattern_); +} + +SPDLOG_INLINE void pattern_formatter::need_localtime(bool need) { need_localtime_ = need; } + +SPDLOG_INLINE std::tm pattern_formatter::get_time_(const details::log_msg &msg) { + if (pattern_time_type_ == pattern_time_type::local) { + return details::os::localtime(log_clock::to_time_t(msg.time)); + } + return details::os::gmtime(log_clock::to_time_t(msg.time)); +} + +template +SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_info padding) { + // process custom flags + auto it = custom_handlers_.find(flag); + if (it != custom_handlers_.end()) { + auto custom_handler = it->second->clone(); + custom_handler->set_padding_info(padding); + formatters_.push_back(std::move(custom_handler)); + return; + } + + // process built-in flags + switch (flag) { + case ('+'): // default formatter + formatters_.push_back(details::make_unique(padding)); + need_localtime_ = true; + break; + + case 'n': // logger name + formatters_.push_back(details::make_unique>(padding)); + break; + + case 'l': // level + formatters_.push_back(details::make_unique>(padding)); + break; + + case 'L': // short level + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('t'): // thread id + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('v'): // the message text + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('a'): // weekday + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('A'): // short weekday + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('b'): + case ('h'): // month + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('B'): // short month + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('c'): // datetime + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('C'): // year 2 digits + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('Y'): // year 4 digits + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('D'): + case ('x'): // datetime MM/DD/YY + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('m'): // month 1-12 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('d'): // day of month 1-31 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('H'): // hours 24 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('I'): // hours 12 + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('M'): // minutes + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('S'): // seconds + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('e'): // milliseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('f'): // microseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('F'): // nanoseconds + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('E'): // seconds since epoch + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('p'): // am/pm + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('r'): // 12 hour clock 02:55:02 pm + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('R'): // 24-hour HH:MM time + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('T'): + case ('X'): // ISO 8601 time format (HH:MM:SS) + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('z'): // timezone + formatters_.push_back(details::make_unique>(padding)); + need_localtime_ = true; + break; + + case ('P'): // pid + formatters_.push_back(details::make_unique>(padding)); + break; + + case ('^'): // color range start + formatters_.push_back(details::make_unique(padding)); + break; + + case ('$'): // color range end + formatters_.push_back(details::make_unique(padding)); + break; + + case ('@'): // source location (filename:filenumber) + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('s'): // short source filename - without directory name + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('g'): // full source filename + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('#'): // source line number + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('!'): // source funcname + formatters_.push_back( + details::make_unique>(padding)); + break; + + case ('%'): // % char + formatters_.push_back(details::make_unique('%')); + break; + + case ('u'): // elapsed time since last log message in nanos + formatters_.push_back( + details::make_unique>( + padding)); + break; + + case ('i'): // elapsed time since last log message in micros + formatters_.push_back( + details::make_unique>( + padding)); + break; + + case ('o'): // elapsed time since last log message in millis + formatters_.push_back( + details::make_unique>( + padding)); + break; + + case ('O'): // elapsed time since last log message in seconds + formatters_.push_back( + details::make_unique>( + padding)); + break; + + case ('&'): + formatters_.push_back(details::make_unique>(padding)); + break; + + default: // Unknown flag appears as is + auto unknown_flag = details::make_unique(); + + if (!padding.truncate_) { + unknown_flag->add_ch('%'); + unknown_flag->add_ch(flag); + formatters_.push_back((std::move(unknown_flag))); + } + // fix issue #1617 (prev char was '!' and should have been treated as funcname flag + // instead of truncating flag) spdlog::set_pattern("[%10!] %v") => "[ main] some + // message" spdlog::set_pattern("[%3!!] %v") => "[mai] some message" + else { + padding.truncate_ = false; + formatters_.push_back( + details::make_unique>(padding)); + unknown_flag->add_ch(flag); + formatters_.push_back((std::move(unknown_flag))); + } + + break; + } +} + +// Extract given pad spec (e.g. %8X, %=8X, %-8!X, %8!X, %=8!X, %-8!X, %+8!X) +// Advance the given it pass the end of the padding spec found (if any) +// Return padding. +SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_( + std::string::const_iterator &it, std::string::const_iterator end) { + using details::padding_info; + using details::scoped_padder; + const size_t max_width = 64; + if (it == end) { + return padding_info{}; + } + + padding_info::pad_side side; + switch (*it) { + case '-': + side = padding_info::pad_side::right; + ++it; + break; + case '=': + side = padding_info::pad_side::center; + ++it; + break; + default: + side = details::padding_info::pad_side::left; + break; + } + + if (it == end || !std::isdigit(static_cast(*it))) { + return padding_info{}; // no padding if no digit found here + } + + auto width = static_cast(*it) - '0'; + for (++it; it != end && std::isdigit(static_cast(*it)); ++it) { + auto digit = static_cast(*it) - '0'; + width = width * 10 + digit; + } + + // search for the optional truncate marker '!' + bool truncate; + if (it != end && *it == '!') { + truncate = true; + ++it; + } else { + truncate = false; + } + return details::padding_info{std::min(width, max_width), side, truncate}; +} + +SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern) { + auto end = pattern.end(); + std::unique_ptr user_chars; + formatters_.clear(); + for (auto it = pattern.begin(); it != end; ++it) { + if (*it == '%') { + if (user_chars) // append user chars found so far + { + formatters_.push_back(std::move(user_chars)); + } + + auto padding = handle_padspec_(++it, end); + + if (it != end) { + if (padding.enabled()) { + handle_flag_(*it, padding); + } else { + handle_flag_(*it, padding); + } + } else { + break; + } + } else // chars not following the % sign should be displayed as is + { + if (!user_chars) { + user_chars = details::make_unique(); + } + user_chars->add_ch(*it); + } + } + if (user_chars) // append raw chars found so far + { + formatters_.push_back(std::move(user_chars)); + } +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/pattern_formatter.h b/cpp_src/vendor/spdlog/pattern_formatter.h new file mode 100644 index 000000000..ececd6732 --- /dev/null +++ b/cpp_src/vendor/spdlog/pattern_formatter.h @@ -0,0 +1,118 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace details { + +// padding information. +struct padding_info { + enum class pad_side { left, right, center }; + + padding_info() = default; + padding_info(size_t width, padding_info::pad_side side, bool truncate) + : width_(width), + side_(side), + truncate_(truncate), + enabled_(true) {} + + bool enabled() const { return enabled_; } + size_t width_ = 0; + pad_side side_ = pad_side::left; + bool truncate_ = false; + bool enabled_ = false; +}; + +class SPDLOG_API flag_formatter { +public: + explicit flag_formatter(padding_info padinfo) + : padinfo_(padinfo) {} + flag_formatter() = default; + virtual ~flag_formatter() = default; + virtual void format(const details::log_msg &msg, + const std::tm &tm_time, + memory_buf_t &dest) = 0; + +protected: + padding_info padinfo_; +}; + +} // namespace details + +class SPDLOG_API custom_flag_formatter : public details::flag_formatter { +public: + virtual std::unique_ptr clone() const = 0; + + void set_padding_info(const details::padding_info &padding) { + flag_formatter::padinfo_ = padding; + } +}; + +class SPDLOG_API pattern_formatter final : public formatter { +public: + using custom_flags = std::unordered_map>; + + explicit pattern_formatter(std::string pattern, + pattern_time_type time_type = pattern_time_type::local, + std::string eol = spdlog::details::os::default_eol, + custom_flags custom_user_flags = custom_flags()); + + // use default pattern is not given + explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, + std::string eol = spdlog::details::os::default_eol); + + pattern_formatter(const pattern_formatter &other) = delete; + pattern_formatter &operator=(const pattern_formatter &other) = delete; + + std::unique_ptr clone() const override; + void format(const details::log_msg &msg, memory_buf_t &dest) override; + + template + pattern_formatter &add_flag(char flag, Args &&...args) { + custom_handlers_[flag] = details::make_unique(std::forward(args)...); + return *this; + } + void set_pattern(std::string pattern); + void need_localtime(bool need = true); + +private: + std::string pattern_; + std::string eol_; + pattern_time_type pattern_time_type_; + bool need_localtime_; + std::tm cached_tm_; + std::chrono::seconds last_log_secs_; + std::vector> formatters_; + custom_flags custom_handlers_; + + std::tm get_time_(const details::log_msg &msg); + template + void handle_flag_(char flag, details::padding_info padding); + + // Extract given pad spec (e.g. %8X) + // Advance the given it pass the end of the padding spec found (if any) + // Return padding. + static details::padding_info handle_padspec_(std::string::const_iterator &it, + std::string::const_iterator end); + + void compile_pattern_(const std::string &pattern); +}; +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "pattern_formatter-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/android_sink.h b/cpp_src/vendor/spdlog/sinks/android_sink.h index e37667558..4435a560a 100644 --- a/cpp_src/vendor/spdlog/sinks/android_sink.h +++ b/cpp_src/vendor/spdlog/sinks/android_sink.h @@ -1,91 +1,137 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#if defined(__ANDROID__) +#ifdef __ANDROID__ -#include "sink.h" -#include "../details/os.h" + #include + #include + #include + #include + #include -#include -#include -#include -#include -#include + #include + #include + #include + #include + #include + #include -#if !defined(SPDLOG_ANDROID_RETRIES) -#define SPDLOG_ANDROID_RETRIES 2 -#endif + #if !defined(SPDLOG_ANDROID_RETRIES) + #define SPDLOG_ANDROID_RETRIES 2 + #endif -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { /* -* Android sink (logging using __android_log_write) -* __android_log_write is thread-safe. No lock is needed. -*/ -class android_sink : public sink -{ + * Android sink + * (logging using __android_log_write or __android_log_buf_write depending on the specified + * BufferID) + */ +template +class android_sink final : public base_sink { public: - explicit android_sink(const std::string& tag = "spdlog", bool use_raw_msg = false): _tag(tag), _use_raw_msg(use_raw_msg) {} + explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) + : tag_(std::move(tag)), + use_raw_msg_(use_raw_msg) {} - void log(const details::log_msg& msg) override - { - const android_LogPriority priority = convert_to_android(msg.level); - const char *msg_output = (_use_raw_msg ? msg.raw.c_str() : msg.formatted.c_str()); +protected: + void sink_it_(const details::log_msg &msg) override { + const android_LogPriority priority = convert_to_android_(msg.level); + memory_buf_t formatted; + if (use_raw_msg_) { + details::fmt_helper::append_string_view(msg.payload, formatted); + } else { + base_sink::formatter_->format(msg, formatted); + } + formatted.push_back('\0'); + const char *msg_output = formatted.data(); // See system/core/liblog/logger_write.c for explanation of return value - int ret = __android_log_write(priority, _tag.c_str(), msg_output); + int ret = android_log(priority, tag_.c_str(), msg_output); + if (ret == -EPERM) { + return; // !__android_log_is_loggable + } int retry_count = 0; - while ((ret == -11/*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) - { + while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) { details::os::sleep_for_millis(5); - ret = __android_log_write(priority, _tag.c_str(), msg_output); + ret = android_log(priority, tag_.c_str(), msg_output); retry_count++; } - if (ret < 0) - { - throw spdlog_ex("__android_log_write() failed", ret); + if (ret < 0) { + throw_spdlog_ex("logging to Android failed", ret); } } - void flush() override - { - } + void flush_() override {} private: - static android_LogPriority convert_to_android(spdlog::level::level_enum level) - { - switch(level) - { - case spdlog::level::trace: - return ANDROID_LOG_VERBOSE; - case spdlog::level::debug: - return ANDROID_LOG_DEBUG; - case spdlog::level::info: - return ANDROID_LOG_INFO; - case spdlog::level::warn: - return ANDROID_LOG_WARN; - case spdlog::level::err: - return ANDROID_LOG_ERROR; - case spdlog::level::critical: - return ANDROID_LOG_FATAL; - default: - return ANDROID_LOG_DEFAULT; + // There might be liblog versions used, that do not support __android_log_buf_write. So we only + // compile and link against + // __android_log_buf_write, if user explicitly provides a non-default log buffer. Otherwise, + // when using the default log buffer, always log via __android_log_write. + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log( + int prio, const char *tag, const char *text) { + return __android_log_write(prio, tag, text); + } + + template + typename std::enable_if(log_id::LOG_ID_MAIN), int>::type android_log( + int prio, const char *tag, const char *text) { + return __android_log_buf_write(ID, prio, tag, text); + } + + static android_LogPriority convert_to_android_(spdlog::level::level_enum level) { + switch (level) { + case spdlog::level::trace: + return ANDROID_LOG_VERBOSE; + case spdlog::level::debug: + return ANDROID_LOG_DEBUG; + case spdlog::level::info: + return ANDROID_LOG_INFO; + case spdlog::level::warn: + return ANDROID_LOG_WARN; + case spdlog::level::err: + return ANDROID_LOG_ERROR; + case spdlog::level::critical: + return ANDROID_LOG_FATAL; + default: + return ANDROID_LOG_DEFAULT; } } - std::string _tag; - bool _use_raw_msg; + std::string tag_; + bool use_raw_msg_; }; +using android_sink_mt = android_sink; +using android_sink_st = android_sink; + +template +using android_sink_buf_mt = android_sink; +template +using android_sink_buf_st = android_sink; + +} // namespace sinks + +// Create and register android syslog logger + +template +inline std::shared_ptr android_logger_mt(const std::string &logger_name, + const std::string &tag = "spdlog") { + return Factory::template create(logger_name, tag); } + +template +inline std::shared_ptr android_logger_st(const std::string &logger_name, + const std::string &tag = "spdlog") { + return Factory::template create(logger_name, tag); } -#endif +} // namespace spdlog + +#endif // __ANDROID__ diff --git a/cpp_src/vendor/spdlog/sinks/ansicolor_sink-inl.h b/cpp_src/vendor/spdlog/sinks/ansicolor_sink-inl.h new file mode 100644 index 000000000..16a7995ad --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/ansicolor_sink-inl.h @@ -0,0 +1,137 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE ansicolor_sink::ansicolor_sink(FILE *target_file, color_mode mode) + : target_file_(target_file), + mutex_(ConsoleMutex::mutex()), + formatter_(details::make_unique()) + +{ + set_color_mode(mode); + colors_.at(level::trace) = to_string_(white); + colors_.at(level::debug) = to_string_(cyan); + colors_.at(level::info) = to_string_(green); + colors_.at(level::warn) = to_string_(yellow_bold); + colors_.at(level::err) = to_string_(red_bold); + colors_.at(level::critical) = to_string_(bold_on_red); + colors_.at(level::off) = to_string_(reset); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_color(level::level_enum color_level, + string_view_t color) { + std::lock_guard lock(mutex_); + colors_.at(static_cast(color_level)) = to_string_(color); +} + +template +SPDLOG_INLINE void ansicolor_sink::log(const details::log_msg &msg) { + // Wrap the originally formatted message in color codes. + // If color is not supported in the terminal, log as is instead. + std::lock_guard lock(mutex_); + msg.color_range_start = 0; + msg.color_range_end = 0; + memory_buf_t formatted; + formatter_->format(msg, formatted); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { + // before color range + print_range_(formatted, 0, msg.color_range_start); + // in color range + print_ccode_(colors_.at(static_cast(msg.level))); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + print_ccode_(reset); + // after color range + print_range_(formatted, msg.color_range_end, formatted.size()); + } else // no color + { + print_range_(formatted, 0, formatted.size()); + } + fflush(target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::flush() { + std::lock_guard lock(mutex_); + fflush(target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_pattern(const std::string &pattern) { + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +SPDLOG_INLINE void ansicolor_sink::set_formatter( + std::unique_ptr sink_formatter) { + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +template +SPDLOG_INLINE bool ansicolor_sink::should_color() { + return should_do_colors_; +} + +template +SPDLOG_INLINE void ansicolor_sink::set_color_mode(color_mode mode) { + switch (mode) { + case color_mode::always: + should_do_colors_ = true; + return; + case color_mode::automatic: + should_do_colors_ = + details::os::in_terminal(target_file_) && details::os::is_color_terminal(); + return; + case color_mode::never: + should_do_colors_ = false; + return; + default: + should_do_colors_ = false; + } +} + +template +SPDLOG_INLINE void ansicolor_sink::print_ccode_(const string_view_t &color_code) { + fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); +} + +template +SPDLOG_INLINE void ansicolor_sink::print_range_(const memory_buf_t &formatted, + size_t start, + size_t end) { + fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); +} + +template +SPDLOG_INLINE std::string ansicolor_sink::to_string_(const string_view_t &sv) { + return std::string(sv.data(), sv.size()); +} + +// ansicolor_stdout_sink +template +SPDLOG_INLINE ansicolor_stdout_sink::ansicolor_stdout_sink(color_mode mode) + : ansicolor_sink(stdout, mode) {} + +// ansicolor_stderr_sink +template +SPDLOG_INLINE ansicolor_stderr_sink::ansicolor_stderr_sink(color_mode mode) + : ansicolor_sink(stderr, mode) {} + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/ansicolor_sink.h b/cpp_src/vendor/spdlog/sinks/ansicolor_sink.h index 9fc828245..ff53730c0 100644 --- a/cpp_src/vendor/spdlog/sinks/ansicolor_sink.h +++ b/cpp_src/vendor/spdlog/sinks/ansicolor_sink.h @@ -1,137 +1,115 @@ -// -// Copyright(c) 2017 spdlog authors. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "base_sink.h" -#include "../common.h" -#include "../details/os.h" - +#include +#include +#include +#include +#include +#include #include -#include -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { /** - * This sink prefixes the output with an ANSI escape sequence color code depending on the severity + * This sink prefixes the output with an ANSI escape sequence color code + * depending on the severity * of the message. * If no color terminal detected, omit the escape codes. */ -template -class ansicolor_sink : public base_sink -{ + +template +class ansicolor_sink : public sink { public: - explicit ansicolor_sink(FILE* file) : target_file_(file) - { - should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal(); - colors_[level::trace] = cyan; - colors_[level::debug] = cyan; - colors_[level::info] = reset; - colors_[level::warn] = yellow + bold; - colors_[level::err] = red + bold; - colors_[level::critical] = bold + on_red; - colors_[level::off] = reset; - } - - ~ansicolor_sink() override - { - ansicolor_sink::_flush(); - } - - void set_color(level::level_enum color_level, const std::string& color) - { - std::lock_guard lock(base_sink::_mutex); - colors_[color_level] = color; - } - - /// Formatting codes - const std::string reset = "\033[m"; - const std::string bold = "\033[1m"; - const std::string dark = "\033[2m"; - const std::string underline = "\033[4m"; - const std::string blink = "\033[5m"; - const std::string reverse = "\033[7m"; - const std::string concealed = "\033[8m"; - const std::string clear_line = "\033[K"; + using mutex_t = typename ConsoleMutex::mutex_t; + ansicolor_sink(FILE *target_file, color_mode mode); + ~ansicolor_sink() override = default; + + ansicolor_sink(const ansicolor_sink &other) = delete; + ansicolor_sink(ansicolor_sink &&other) = delete; + + ansicolor_sink &operator=(const ansicolor_sink &other) = delete; + ansicolor_sink &operator=(ansicolor_sink &&other) = delete; + + void set_color(level::level_enum color_level, string_view_t color); + void set_color_mode(color_mode mode); + bool should_color(); + + void log(const details::log_msg &msg) override; + void flush() override; + void set_pattern(const std::string &pattern) final; + void set_formatter(std::unique_ptr sink_formatter) override; + + // Formatting codes + const string_view_t reset = "\033[m"; + const string_view_t bold = "\033[1m"; + const string_view_t dark = "\033[2m"; + const string_view_t underline = "\033[4m"; + const string_view_t blink = "\033[5m"; + const string_view_t reverse = "\033[7m"; + const string_view_t concealed = "\033[8m"; + const string_view_t clear_line = "\033[K"; // Foreground colors - const std::string black = "\033[30m"; - const std::string red = "\033[31m"; - const std::string green = "\033[32m"; - const std::string yellow = "\033[33m"; - const std::string blue = "\033[34m"; - const std::string magenta = "\033[35m"; - const std::string cyan = "\033[36m"; - const std::string white = "\033[37m"; + const string_view_t black = "\033[30m"; + const string_view_t red = "\033[31m"; + const string_view_t green = "\033[32m"; + const string_view_t yellow = "\033[33m"; + const string_view_t blue = "\033[34m"; + const string_view_t magenta = "\033[35m"; + const string_view_t cyan = "\033[36m"; + const string_view_t white = "\033[37m"; /// Background colors - const std::string on_black = "\033[40m"; - const std::string on_red = "\033[41m"; - const std::string on_green = "\033[42m"; - const std::string on_yellow = "\033[43m"; - const std::string on_blue = "\033[44m"; - const std::string on_magenta = "\033[45m"; - const std::string on_cyan = "\033[46m"; - const std::string on_white = "\033[47m"; - -protected: - void _sink_it(const details::log_msg& msg) override - { - // Wrap the originally formatted message in color codes. - // If color is not supported in the terminal, log as is instead. - if (should_do_colors_) - { - const std::string& prefix = colors_[msg.level]; - fwrite(prefix.data(), sizeof(char), prefix.size(), target_file_); - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_); - fwrite(reset.data(), sizeof(char), reset.size(), target_file_); - fwrite(clear_line.data(), sizeof(char), clear_line.size(), target_file_); - } - else - { - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), target_file_); - } - _flush(); - } - - void _flush() override - { - fflush(target_file_); - } - - FILE* target_file_; + const string_view_t on_black = "\033[40m"; + const string_view_t on_red = "\033[41m"; + const string_view_t on_green = "\033[42m"; + const string_view_t on_yellow = "\033[43m"; + const string_view_t on_blue = "\033[44m"; + const string_view_t on_magenta = "\033[45m"; + const string_view_t on_cyan = "\033[46m"; + const string_view_t on_white = "\033[47m"; + + /// Bold colors + const string_view_t yellow_bold = "\033[33m\033[1m"; + const string_view_t red_bold = "\033[31m\033[1m"; + const string_view_t bold_on_red = "\033[1m\033[41m"; + +private: + FILE *target_file_; + mutex_t &mutex_; bool should_do_colors_; - std::unordered_map colors_; + std::unique_ptr formatter_; + std::array colors_; + void print_ccode_(const string_view_t &color_code); + void print_range_(const memory_buf_t &formatted, size_t start, size_t end); + static std::string to_string_(const string_view_t &sv); }; - -template -class ansicolor_stdout_sink: public ansicolor_sink -{ +template +class ansicolor_stdout_sink : public ansicolor_sink { public: - ansicolor_stdout_sink(): ansicolor_sink(stdout) - {} + explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); }; -using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; -using ansicolor_stdout_sink_st = ansicolor_stdout_sink; - -template -class ansicolor_stderr_sink: public ansicolor_sink -{ +template +class ansicolor_stderr_sink : public ansicolor_sink { public: - ansicolor_stderr_sink(): ansicolor_sink(stderr) - {} + explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); }; -using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; -using ansicolor_stderr_sink_st = ansicolor_stderr_sink; +using ansicolor_stdout_sink_mt = ansicolor_stdout_sink; +using ansicolor_stdout_sink_st = ansicolor_stdout_sink; + +using ansicolor_stderr_sink_mt = ansicolor_stderr_sink; +using ansicolor_stderr_sink_st = ansicolor_stderr_sink; -} // namespace sinks -} // namespace spdlog +} // namespace sinks +} // namespace spdlog +#ifdef SPDLOG_HEADER_ONLY + #include "ansicolor_sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/base_sink-inl.h b/cpp_src/vendor/spdlog/sinks/base_sink-inl.h new file mode 100644 index 000000000..ada161bcc --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/base_sink-inl.h @@ -0,0 +1,59 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +#include +#include + +template +SPDLOG_INLINE spdlog::sinks::base_sink::base_sink() + : formatter_{details::make_unique()} {} + +template +SPDLOG_INLINE spdlog::sinks::base_sink::base_sink( + std::unique_ptr formatter) + : formatter_{std::move(formatter)} {} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::log(const details::log_msg &msg) { + std::lock_guard lock(mutex_); + sink_it_(msg); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::flush() { + std::lock_guard lock(mutex_); + flush_(); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern(const std::string &pattern) { + std::lock_guard lock(mutex_); + set_pattern_(pattern); +} + +template +void SPDLOG_INLINE +spdlog::sinks::base_sink::set_formatter(std::unique_ptr sink_formatter) { + std::lock_guard lock(mutex_); + set_formatter_(std::move(sink_formatter)); +} + +template +void SPDLOG_INLINE spdlog::sinks::base_sink::set_pattern_(const std::string &pattern) { + set_formatter_(details::make_unique(pattern)); +} + +template +void SPDLOG_INLINE +spdlog::sinks::base_sink::set_formatter_(std::unique_ptr sink_formatter) { + formatter_ = std::move(sink_formatter); +} diff --git a/cpp_src/vendor/spdlog/sinks/base_sink.h b/cpp_src/vendor/spdlog/sinks/base_sink.h index 1d9758923..1ca772a65 100644 --- a/cpp_src/vendor/spdlog/sinks/base_sink.h +++ b/cpp_src/vendor/spdlog/sinks/base_sink.h @@ -1,51 +1,51 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once // // base sink templated over a mutex (either dummy or real) -// concrete implementation should only override the _sink_it method. -// all locking is taken care of here so no locking needed by the implementers.. +// concrete implementation should override the sink_it_() and flush_() methods. +// locking is taken care of in this class - no locking needed by the +// implementers.. // -#include "sink.h" -#include "../formatter.h" -#include "../common.h" -#include "../details/log_msg.h" +#include +#include +#include -#include - -namespace spdlog -{ -namespace sinks -{ -template -class base_sink : public sink -{ +namespace spdlog { +namespace sinks { +template +class SPDLOG_API base_sink : public sink { public: - base_sink() = default; + base_sink(); + explicit base_sink(std::unique_ptr formatter); + ~base_sink() override = default; - base_sink(const base_sink&) = delete; - base_sink& operator=(const base_sink&) = delete; + base_sink(const base_sink &) = delete; + base_sink(base_sink &&) = delete; - void log(const details::log_msg& msg) SPDLOG_FINAL override - { - std::lock_guard lock(_mutex); - _sink_it(msg); - } + base_sink &operator=(const base_sink &) = delete; + base_sink &operator=(base_sink &&) = delete; - void flush() SPDLOG_FINAL override - { - std::lock_guard lock(_mutex); - _flush(); - } + void log(const details::log_msg &msg) final; + void flush() final; + void set_pattern(const std::string &pattern) final; + void set_formatter(std::unique_ptr sink_formatter) final; protected: - virtual void _sink_it(const details::log_msg& msg) = 0; - virtual void _flush() = 0; - Mutex _mutex; + // sink formatter + std::unique_ptr formatter_; + Mutex mutex_; + + virtual void sink_it_(const details::log_msg &msg) = 0; + virtual void flush_() = 0; + virtual void set_pattern_(const std::string &pattern); + virtual void set_formatter_(std::unique_ptr sink_formatter); }; -} -} +} // namespace sinks +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "base_sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/basic_file_sink-inl.h b/cpp_src/vendor/spdlog/sinks/basic_file_sink-inl.h new file mode 100644 index 000000000..f7c1abf7c --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/basic_file_sink-inl.h @@ -0,0 +1,42 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE basic_file_sink::basic_file_sink(const filename_t &filename, + bool truncate, + const file_event_handlers &event_handlers) + : file_helper_{event_handlers} { + file_helper_.open(filename, truncate); +} + +template +SPDLOG_INLINE const filename_t &basic_file_sink::filename() const { + return file_helper_.filename(); +} + +template +SPDLOG_INLINE void basic_file_sink::sink_it_(const details::log_msg &msg) { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); +} + +template +SPDLOG_INLINE void basic_file_sink::flush_() { + file_helper_.flush(); +} + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/basic_file_sink.h b/cpp_src/vendor/spdlog/sinks/basic_file_sink.h new file mode 100644 index 000000000..699caa147 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/basic_file_sink.h @@ -0,0 +1,65 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace spdlog { +namespace sinks { +/* + * Trivial file sink with single file as target + */ +template +class basic_file_sink final : public base_sink { +public: + explicit basic_file_sink(const filename_t &filename, + bool truncate = false, + const file_event_handlers &event_handlers = {}); + const filename_t &filename() const; + +protected: + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + +private: + details::file_helper file_helper_; +}; + +using basic_file_sink_mt = basic_file_sink; +using basic_file_sink_st = basic_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr basic_logger_mt(const std::string &logger_name, + const filename_t &filename, + bool truncate = false, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, truncate, + event_handlers); +} + +template +inline std::shared_ptr basic_logger_st(const std::string &logger_name, + const filename_t &filename, + bool truncate = false, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, truncate, + event_handlers); +} + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "basic_file_sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/callback_sink.h b/cpp_src/vendor/spdlog/sinks/callback_sink.h new file mode 100644 index 000000000..71668ef28 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/callback_sink.h @@ -0,0 +1,56 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +#include +#include + +namespace spdlog { + +// callbacks type +typedef std::function custom_log_callback; + +namespace sinks { +/* + * Trivial callback sink, gets a callback function and calls it on each log + */ +template +class callback_sink final : public base_sink { +public: + explicit callback_sink(const custom_log_callback &callback) + : callback_{callback} {} + +protected: + void sink_it_(const details::log_msg &msg) override { callback_(msg); } + void flush_() override{}; + +private: + custom_log_callback callback_; +}; + +using callback_sink_mt = callback_sink; +using callback_sink_st = callback_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr callback_logger_mt(const std::string &logger_name, + const custom_log_callback &callback) { + return Factory::template create(logger_name, callback); +} + +template +inline std::shared_ptr callback_logger_st(const std::string &logger_name, + const custom_log_callback &callback) { + return Factory::template create(logger_name, callback); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/daily_file_sink.h b/cpp_src/vendor/spdlog/sinks/daily_file_sink.h new file mode 100644 index 000000000..1b1dc44a8 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/daily_file_sink.h @@ -0,0 +1,252 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of daily log file names in format basename.YYYY-MM-DD.ext + */ +struct daily_filename_calculator { + // Create filename for the form basename.YYYY-MM-DD + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), + basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, + ext); + } +}; + +/* + * Generator of daily log file names with strftime format. + * Usages: + * auto sink = + * std::make_shared("myapp-%Y-%m-%d:%H:%M:%S.log", hour, + * minute);" auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", + * hour, minute)" + * + */ +struct daily_filename_format_calculator { + static filename_t calc_filename(const filename_t &file_path, const tm &now_tm) { +#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) + std::wstringstream stream; +#else + std::stringstream stream; +#endif + stream << std::put_time(&now_tm, file_path.c_str()); + return stream.str(); + } +}; + +/* + * Rotating file sink based on date. + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class daily_file_sink final : public base_sink { +public: + // create daily file sink which rotates on given time + daily_file_sink(filename_t base_filename, + int rotation_hour, + int rotation_minute, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)), + rotation_h_(rotation_hour), + rotation_m_(rotation_minute), + file_helper_{event_handlers}, + truncate_(truncate), + max_files_(max_files), + filenames_q_() { + if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || + rotation_minute > 59) { + throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); + } + + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) { + init_filenames_q_(); + } + } + + filename_t filename() { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) { + delete_old_(); + } + } + + void flush_() override { file_helper_.flush(); } + +private: + void init_filenames_q_() { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::hours(24); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_hour = rotation_h_; + date.tm_min = rotation_m_; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) { + return rotation_time; + } + return {rotation_time + std::chrono::hours(24)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) { + filenames_q_.push_back(std::move(current_file)); + throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), + errno); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + int rotation_h_; + int rotation_m_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + details::circular_q filenames_q_; +}; + +using daily_file_sink_mt = daily_file_sink; +using daily_file_sink_st = daily_file_sink; +using daily_file_format_sink_mt = daily_file_sink; +using daily_file_format_sink_st = + daily_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr daily_logger_mt(const std::string &logger_name, + const filename_t &filename, + int hour = 0, + int minute = 0, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, hour, minute, + truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_format_mt( + const std::string &logger_name, + const filename_t &filename, + int hour = 0, + int minute = 0, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_st(const std::string &logger_name, + const filename_t &filename, + int hour = 0, + int minute = 0, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, hour, minute, + truncate, max_files, event_handlers); +} + +template +inline std::shared_ptr daily_logger_format_st( + const std::string &logger_name, + const filename_t &filename, + int hour = 0, + int minute = 0, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create( + logger_name, filename, hour, minute, truncate, max_files, event_handlers); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/dist_sink.h b/cpp_src/vendor/spdlog/sinks/dist_sink.h index 39f162c56..69c4971c9 100644 --- a/cpp_src/vendor/spdlog/sinks/dist_sink.h +++ b/cpp_src/vendor/spdlog/sinks/dist_sink.h @@ -1,70 +1,81 @@ -// -// Copyright (c) 2015 David Schury, Gabi Melman +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../details/log_msg.h" -#include "../details/null_mutex.h" #include "base_sink.h" -#include "sink.h" +#include +#include +#include #include -#include #include +#include #include -// Distribution sink (mux). Stores a vector of sinks which get called when log is called +// Distribution sink (mux). Stores a vector of sinks which get called when log +// is called -namespace spdlog -{ -namespace sinks -{ -template -class dist_sink : public base_sink -{ +namespace spdlog { +namespace sinks { + +template +class dist_sink : public base_sink { public: - explicit dist_sink() :_sinks() {} - dist_sink(const dist_sink&) = delete; - dist_sink& operator=(const dist_sink&) = delete; + dist_sink() = default; + explicit dist_sink(std::vector> sinks) + : sinks_(sinks) {} + + dist_sink(const dist_sink &) = delete; + dist_sink &operator=(const dist_sink &) = delete; + + void add_sink(std::shared_ptr sub_sink) { + std::lock_guard lock(base_sink::mutex_); + sinks_.push_back(sub_sink); + } + + void remove_sink(std::shared_ptr sub_sink) { + std::lock_guard lock(base_sink::mutex_); + sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sub_sink), sinks_.end()); + } + + void set_sinks(std::vector> sinks) { + std::lock_guard lock(base_sink::mutex_); + sinks_ = std::move(sinks); + } + + std::vector> &sinks() { return sinks_; } protected: - std::vector> _sinks; - - void _sink_it(const details::log_msg& msg) override - { - for (auto &sink : _sinks) - { - if( sink->should_log( msg.level)) - { - sink->log(msg); + void sink_it_(const details::log_msg &msg) override { + for (auto &sub_sink : sinks_) { + if (sub_sink->should_log(msg.level)) { + sub_sink->log(msg); } } } - void _flush() override - { - for (auto &sink : _sinks) - sink->flush(); + void flush_() override { + for (auto &sub_sink : sinks_) { + sub_sink->flush(); + } } -public: - void add_sink(std::shared_ptr sink) - { - std::lock_guard lock(base_sink::_mutex); - _sinks.push_back(sink); + void set_pattern_(const std::string &pattern) override { + set_formatter_(details::make_unique(pattern)); } - void remove_sink(std::shared_ptr sink) - { - std::lock_guard lock(base_sink::_mutex); - _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end()); + void set_formatter_(std::unique_ptr sink_formatter) override { + base_sink::formatter_ = std::move(sink_formatter); + for (auto &sub_sink : sinks_) { + sub_sink->set_formatter(base_sink::formatter_->clone()); + } } + std::vector> sinks_; }; using dist_sink_mt = dist_sink; using dist_sink_st = dist_sink; -} -} +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/dup_filter_sink.h b/cpp_src/vendor/spdlog/sinks/dup_filter_sink.h new file mode 100644 index 000000000..1498142c4 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/dup_filter_sink.h @@ -0,0 +1,92 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "dist_sink.h" +#include +#include + +#include +#include +#include +#include + +// Duplicate message removal sink. +// Skip the message if previous one is identical and less than "max_skip_duration" have passed +// +// Example: +// +// #include +// +// int main() { +// auto dup_filter = std::make_shared(std::chrono::seconds(5), +// level::info); dup_filter->add_sink(std::make_shared()); +// spdlog::logger l("logger", dup_filter); +// l.info("Hello"); +// l.info("Hello"); +// l.info("Hello"); +// l.info("Different Hello"); +// } +// +// Will produce: +// [2019-06-25 17:50:56.511] [logger] [info] Hello +// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. +// [2019-06-25 17:50:56.512] [logger] [info] Different Hello + +namespace spdlog { +namespace sinks { +template +class dup_filter_sink : public dist_sink { +public: + template + explicit dup_filter_sink(std::chrono::duration max_skip_duration, + level::level_enum notification_level = level::info) + : max_skip_duration_{max_skip_duration}, + log_level_{notification_level} {} + +protected: + std::chrono::microseconds max_skip_duration_; + log_clock::time_point last_msg_time_; + std::string last_msg_payload_; + size_t skip_counter_ = 0; + level::level_enum log_level_; + + void sink_it_(const details::log_msg &msg) override { + bool filtered = filter_(msg); + if (!filtered) { + skip_counter_ += 1; + return; + } + + // log the "skipped.." message + if (skip_counter_ > 0) { + char buf[64]; + auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", + static_cast(skip_counter_)); + if (msg_size > 0 && static_cast(msg_size) < sizeof(buf)) { + details::log_msg skipped_msg{msg.source, msg.logger_name, log_level_, + string_view_t{buf, static_cast(msg_size)}}; + dist_sink::sink_it_(skipped_msg); + } + } + + // log current message + dist_sink::sink_it_(msg); + last_msg_time_ = msg.time; + skip_counter_ = 0; + last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); + } + + // return whether the log msg should be displayed (true) or skipped (false) + bool filter_(const details::log_msg &msg) { + auto filter_duration = msg.time - last_msg_time_; + return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); + } +}; + +using dup_filter_sink_mt = dup_filter_sink; +using dup_filter_sink_st = dup_filter_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/file_sinks.h b/cpp_src/vendor/spdlog/sinks/file_sinks.h deleted file mode 100644 index a213136ee..000000000 --- a/cpp_src/vendor/spdlog/sinks/file_sinks.h +++ /dev/null @@ -1,315 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// clang-format off - -#include "base_sink.h" -#include "../details/null_mutex.h" -#include "../details/file_helper.h" -#include "../fmt/fmt.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace spdlog -{ -namespace sinks -{ -/* - * Trivial file sink with single file as target - */ -template -class simple_file_sink SPDLOG_FINAL : public base_sink -{ -public: - explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false) - { - _file_helper.open(filename, truncate); - } - - void set_force_flush(bool force_flush) - { - _force_flush = force_flush; - } - void reopen () { - std::lock_guard lock(base_sink::_mutex); - _file_helper.reopen(false); - } - -protected: - void _sink_it(const details::log_msg& msg) override - { - _file_helper.write(msg); - if(_force_flush) - _file_helper.flush(); - } - - void _flush() override - { - _file_helper.flush(); - } - -private: - details::file_helper _file_helper; - bool _force_flush; -}; - -/* - * Implementation of file sink, that performs - * reopen() only before writing (if _reopen - * flag was set to true). log() and flush() - * cannot work in parallel - only useful (and - * more efficient than simple_file_sink) when - * there is synchronization on a higher level. - */ -class fast_file_sink SPDLOG_FINAL : public sink -{ -public: - explicit fast_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false), _reopen(false) - { - _file_helper.open(filename, truncate); - } - - fast_file_sink(const fast_file_sink&) = delete; - fast_file_sink& operator=(const fast_file_sink&) = delete; - - void log(const details::log_msg& msg) SPDLOG_FINAL override - { - if (_reopen) { - _file_helper.reopen(false); - _reopen = false; - } - _file_helper.write(msg); - if(_force_flush) { - flush(); - } - } - - void flush() SPDLOG_FINAL override - { - _file_helper.flush(); - } - - void reopen () - { - _reopen = true; - } - - void set_force_flush(bool force_flush) - { - _force_flush = force_flush; - } - -private: - details::file_helper _file_helper; - std::atomic _force_flush; - std::atomic _reopen; -}; - -using simple_file_sink_mt = simple_file_sink; -using simple_file_sink_st = simple_file_sink; - -/* - * Rotating file sink based on size - */ -template -class rotating_file_sink SPDLOG_FINAL : public base_sink -{ -public: - rotating_file_sink(filename_t base_filename, - std::size_t max_size, std::size_t max_files) : - _base_filename(std::move(base_filename)), - _max_size(max_size), - _max_files(max_files) - { - _file_helper.open(calc_filename(_base_filename, 0)); - _current_size = _file_helper.size(); //expensive. called only once - } - - // calc filename according to index and file extension if exists. - // e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt". - static filename_t calc_filename(const filename_t& filename, std::size_t index) - { - typename std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; - if (index != 0u) - { - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename); - w.write(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); - } - else - { - w.write(SPDLOG_FILENAME_T("{}"), filename); - } - return w.str(); - } - -protected: - void _sink_it(const details::log_msg& msg) override - { - _current_size += msg.formatted.size(); - if (_current_size > _max_size) - { - _rotate(); - _current_size = msg.formatted.size(); - } - _file_helper.write(msg); - } - - void _flush() override - { - _file_helper.flush(); - } - -private: - // Rotate files: - // log.txt -> log.1.txt - // log.1.txt -> log.2.txt - // log.2.txt -> log.3.txt - // log.3.txt -> delete - void _rotate() - { - using details::os::filename_to_str; - _file_helper.close(); - for (auto i = _max_files; i > 0; --i) - { - filename_t src = calc_filename(_base_filename, i - 1); - filename_t target = calc_filename(_base_filename, i); - - if (details::file_helper::file_exists(target)) - { - if (details::os::remove(target) != 0) - { - throw spdlog_ex("rotating_file_sink: failed removing " + filename_to_str(target), errno); - } - } - if (details::file_helper::file_exists(src) && details::os::rename(src, target) != 0) - { - throw spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno); - } - } - _file_helper.reopen(true); - } - - filename_t _base_filename; - std::size_t _max_size; - std::size_t _max_files; - std::size_t _current_size; - details::file_helper _file_helper; -}; - -using rotating_file_sink_mt = rotating_file_sink; -using rotating_file_sink_st = rotating_file_sink; - -/* - * Default generator of daily log file names. - */ -struct default_daily_file_name_calculator -{ - // Create filename for the form filename.YYYY-MM-DD_hh-mm.ext - static filename_t calc_filename(const filename_t& filename) - { - std::tm tm = spdlog::details::os::localtime(); - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename); - std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; - w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, ext); - return w.str(); - } -}; - -/* - * Generator of daily log file names in format basename.YYYY-MM-DD.ext - */ -struct dateonly_daily_file_name_calculator -{ - // Create filename for the form basename.YYYY-MM-DD - static filename_t calc_filename(const filename_t& filename) - { - std::tm tm = spdlog::details::os::localtime(); - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename); - std::conditional::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; - w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, ext); - return w.str(); - } -}; - -/* - * Rotating file sink based on date. rotates at midnight - */ -template -class daily_file_sink SPDLOG_FINAL :public base_sink < Mutex > -{ -public: - //create daily file sink which rotates on given time - daily_file_sink( - filename_t base_filename, - int rotation_hour, - int rotation_minute) : - _base_filename(std::move(base_filename)), - _rotation_h(rotation_hour), - _rotation_m(rotation_minute) - { - if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) - throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); - _rotation_tp = _next_rotation_tp(); - _file_helper.open(FileNameCalc::calc_filename(_base_filename)); - } - - -protected: -using sink_clock = reindexer::system_clock_w; - - void _sink_it(const details::log_msg& msg) override - { - if (sink_clock::now() >= _rotation_tp) - { - _file_helper.open(FileNameCalc::calc_filename(_base_filename)); - _rotation_tp = _next_rotation_tp(); - } - _file_helper.write(msg); - } - - void _flush() override - { - _file_helper.flush(); - } - -private: - sink_clock::time_point _next_rotation_tp() - { - auto now = sink_clock::now(); - time_t tnow = sink_clock::to_time_t(now); - tm date = spdlog::details::os::localtime(tnow); - date.tm_hour = _rotation_h; - date.tm_min = _rotation_m; - date.tm_sec = 0; - auto rotation_time = sink_clock::from_time_t(std::mktime(&date)); - if (rotation_time > now) - { - return rotation_time; - } - return{ rotation_time + std::chrono::hours(24) }; - } - - filename_t _base_filename; - int _rotation_h; - int _rotation_m; - sink_clock::time_point _rotation_tp; - details::file_helper _file_helper; -}; - -using daily_file_sink_mt = daily_file_sink; -using daily_file_sink_st = daily_file_sink; - -} -} diff --git a/cpp_src/vendor/spdlog/sinks/hourly_file_sink.h b/cpp_src/vendor/spdlog/sinks/hourly_file_sink.h new file mode 100644 index 000000000..1f138925f --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/hourly_file_sink.h @@ -0,0 +1,191 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext + */ +struct hourly_filename_calculator { + // Create filename for the form basename.YYYY-MM-DD-H + static filename_t calc_filename(const filename_t &filename, const tm &now_tm) { + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, + now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, + now_tm.tm_hour, ext); + } +}; + +/* + * Rotating file sink based on time. + * If truncate != false , the created file will be truncated. + * If max_files > 0, retain only the last max_files and delete previous. + */ +template +class hourly_file_sink final : public base_sink { +public: + // create hourly file sink which rotates on given time + hourly_file_sink(filename_t base_filename, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) + : base_filename_(std::move(base_filename)), + file_helper_{event_handlers}, + truncate_(truncate), + max_files_(max_files), + filenames_q_() { + auto now = log_clock::now(); + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + file_helper_.open(filename, truncate_); + remove_init_file_ = file_helper_.size() == 0; + rotation_tp_ = next_rotation_tp_(); + + if (max_files_ > 0) { + init_filenames_q_(); + } + } + + filename_t filename() { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); + } + +protected: + void sink_it_(const details::log_msg &msg) override { + auto time = msg.time; + bool should_rotate = time >= rotation_tp_; + if (should_rotate) { + if (remove_init_file_) { + file_helper_.close(); + details::os::remove(file_helper_.filename()); + } + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); + file_helper_.open(filename, truncate_); + rotation_tp_ = next_rotation_tp_(); + } + remove_init_file_ = false; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + file_helper_.write(formatted); + + // Do the cleaning only at the end because it might throw on failure. + if (should_rotate && max_files_ > 0) { + delete_old_(); + } + } + + void flush_() override { file_helper_.flush(); } + +private: + void init_filenames_q_() { + using details::os::path_exists; + + filenames_q_ = details::circular_q(static_cast(max_files_)); + std::vector filenames; + auto now = log_clock::now(); + while (filenames.size() < max_files_) { + auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); + if (!path_exists(filename)) { + break; + } + filenames.emplace_back(filename); + now -= std::chrono::hours(1); + } + for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) { + filenames_q_.push_back(std::move(*iter)); + } + } + + tm now_tm(log_clock::time_point tp) { + time_t tnow = log_clock::to_time_t(tp); + return spdlog::details::os::localtime(tnow); + } + + log_clock::time_point next_rotation_tp_() { + auto now = log_clock::now(); + tm date = now_tm(now); + date.tm_min = 0; + date.tm_sec = 0; + auto rotation_time = log_clock::from_time_t(std::mktime(&date)); + if (rotation_time > now) { + return rotation_time; + } + return {rotation_time + std::chrono::hours(1)}; + } + + // Delete the file N rotations ago. + // Throw spdlog_ex on failure to delete the old file. + void delete_old_() { + using details::os::filename_to_str; + using details::os::remove_if_exists; + + filename_t current_file = file_helper_.filename(); + if (filenames_q_.full()) { + auto old_filename = std::move(filenames_q_.front()); + filenames_q_.pop_front(); + bool ok = remove_if_exists(old_filename) == 0; + if (!ok) { + filenames_q_.push_back(std::move(current_file)); + SPDLOG_THROW(spdlog_ex( + "Failed removing hourly file " + filename_to_str(old_filename), errno)); + } + } + filenames_q_.push_back(std::move(current_file)); + } + + filename_t base_filename_; + log_clock::time_point rotation_tp_; + details::file_helper file_helper_; + bool truncate_; + uint16_t max_files_; + details::circular_q filenames_q_; + bool remove_init_file_; +}; + +using hourly_file_sink_mt = hourly_file_sink; +using hourly_file_sink_st = hourly_file_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr hourly_logger_mt(const std::string &logger_name, + const filename_t &filename, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, truncate, + max_files, event_handlers); +} + +template +inline std::shared_ptr hourly_logger_st(const std::string &logger_name, + const filename_t &filename, + bool truncate = false, + uint16_t max_files = 0, + const file_event_handlers &event_handlers = {}) { + return Factory::template create(logger_name, filename, truncate, + max_files, event_handlers); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/kafka_sink.h b/cpp_src/vendor/spdlog/sinks/kafka_sink.h new file mode 100644 index 000000000..91e987865 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/kafka_sink.h @@ -0,0 +1,119 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for kafka +// Building and using requires librdkafka library. +// For building librdkafka library check the url below +// https://github.com/confluentinc/librdkafka +// + +#include "spdlog/async.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/details/synchronous_factory.h" +#include "spdlog/sinks/base_sink.h" +#include +#include + +// kafka header +#include + +namespace spdlog { +namespace sinks { + +struct kafka_sink_config { + std::string server_addr; + std::string produce_topic; + int32_t flush_timeout_ms = 1000; + + kafka_sink_config(std::string addr, std::string topic, int flush_timeout_ms = 1000) + : server_addr{std::move(addr)}, + produce_topic{std::move(topic)}, + flush_timeout_ms(flush_timeout_ms) {} +}; + +template +class kafka_sink : public base_sink { +public: + kafka_sink(kafka_sink_config config) + : config_{std::move(config)} { + try { + std::string errstr; + conf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL)); + RdKafka::Conf::ConfResult confRes = + conf_->set("bootstrap.servers", config_.server_addr, errstr); + if (confRes != RdKafka::Conf::CONF_OK) { + throw_spdlog_ex( + fmt_lib::format("conf set bootstrap.servers failed err:{}", errstr)); + } + + tconf_.reset(RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC)); + if (tconf_ == nullptr) { + throw_spdlog_ex(fmt_lib::format("create topic config failed")); + } + + producer_.reset(RdKafka::Producer::create(conf_.get(), errstr)); + if (producer_ == nullptr) { + throw_spdlog_ex(fmt_lib::format("create producer failed err:{}", errstr)); + } + topic_.reset(RdKafka::Topic::create(producer_.get(), config_.produce_topic, + tconf_.get(), errstr)); + if (topic_ == nullptr) { + throw_spdlog_ex(fmt_lib::format("create topic failed err:{}", errstr)); + } + } catch (const std::exception &e) { + throw_spdlog_ex(fmt_lib::format("error create kafka instance: {}", e.what())); + } + } + + ~kafka_sink() { producer_->flush(config_.flush_timeout_ms); } + +protected: + void sink_it_(const details::log_msg &msg) override { + producer_->produce(topic_.get(), 0, RdKafka::Producer::RK_MSG_COPY, + (void *)msg.payload.data(), msg.payload.size(), NULL, NULL); + } + + void flush_() override { producer_->flush(config_.flush_timeout_ms); } + +private: + kafka_sink_config config_; + std::unique_ptr producer_ = nullptr; + std::unique_ptr conf_ = nullptr; + std::unique_ptr tconf_ = nullptr; + std::unique_ptr topic_ = nullptr; +}; + +using kafka_sink_mt = kafka_sink; +using kafka_sink_st = kafka_sink; + +} // namespace sinks + +template +inline std::shared_ptr kafka_logger_mt(const std::string &logger_name, + spdlog::sinks::kafka_sink_config config) { + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_st(const std::string &logger_name, + spdlog::sinks::kafka_sink_config config) { + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_mt( + std::string logger_name, spdlog::sinks::kafka_sink_config config) { + return Factory::template create(logger_name, config); +} + +template +inline std::shared_ptr kafka_logger_async_st( + std::string logger_name, spdlog::sinks::kafka_sink_config config) { + return Factory::template create(logger_name, config); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/mongo_sink.h b/cpp_src/vendor/spdlog/sinks/mongo_sink.h new file mode 100644 index 000000000..c5b38ab95 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/mongo_sink.h @@ -0,0 +1,108 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for mongodb +// Building and using requires mongocxx library. +// For building mongocxx library check the url below +// http://mongocxx.org/mongocxx-v3/installation/ +// + +#include "spdlog/common.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/sinks/base_sink.h" +#include + +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { +template +class mongo_sink : public base_sink { +public: + mongo_sink(const std::string &db_name, + const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") try + : mongo_sink(std::make_shared(), db_name, collection_name, uri) { + } catch (const std::exception &e) { + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); + } + + mongo_sink(std::shared_ptr instance, + const std::string &db_name, + const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") + : instance_(std::move(instance)), + db_name_(db_name), + coll_name_(collection_name) { + try { + client_ = spdlog::details::make_unique(mongocxx::uri{uri}); + } catch (const std::exception &e) { + throw_spdlog_ex(fmt_lib::format("Error opening database: {}", e.what())); + } + } + + ~mongo_sink() { flush_(); } + +protected: + void sink_it_(const details::log_msg &msg) override { + using bsoncxx::builder::stream::document; + using bsoncxx::builder::stream::finalize; + + if (client_ != nullptr) { + auto doc = document{} << "timestamp" << bsoncxx::types::b_date(msg.time) << "level" + << level::to_string_view(msg.level).data() << "level_num" + << msg.level << "message" + << std::string(msg.payload.begin(), msg.payload.end()) + << "logger_name" + << std::string(msg.logger_name.begin(), msg.logger_name.end()) + << "thread_id" << static_cast(msg.thread_id) << finalize; + client_->database(db_name_).collection(coll_name_).insert_one(doc.view()); + } + } + + void flush_() override {} + +private: + std::shared_ptr instance_; + std::string db_name_; + std::string coll_name_; + std::unique_ptr client_ = nullptr; +}; + +#include "spdlog/details/null_mutex.h" +#include +using mongo_sink_mt = mongo_sink; +using mongo_sink_st = mongo_sink; + +} // namespace sinks + +template +inline std::shared_ptr mongo_logger_mt( + const std::string &logger_name, + const std::string &db_name, + const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") { + return Factory::template create(logger_name, db_name, collection_name, + uri); +} + +template +inline std::shared_ptr mongo_logger_st( + const std::string &logger_name, + const std::string &db_name, + const std::string &collection_name, + const std::string &uri = "mongodb://localhost:27017") { + return Factory::template create(logger_name, db_name, collection_name, + uri); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/msvc_sink.h b/cpp_src/vendor/spdlog/sinks/msvc_sink.h index d230613e4..2e5f6875e 100644 --- a/cpp_src/vendor/spdlog/sinks/msvc_sink.h +++ b/cpp_src/vendor/spdlog/sinks/msvc_sink.h @@ -1,49 +1,68 @@ -// -// Copyright(c) 2016 Alexander Dalshov. +// Copyright(c) 2016 Alexander Dalshov & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once #if defined(_WIN32) -#include "base_sink.h" -#include "../details/null_mutex.h" + #include + #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) + #include + #endif + #include -#include + #include + #include -#include -#include + // Avoid including windows.h (https://stackoverflow.com/a/30741042) + #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString); + #else +extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString); + #endif +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { /* -* MSVC sink (logging using OutputDebugStringA) -*/ -template -class msvc_sink : public base_sink -{ + * MSVC sink (logging using OutputDebugStringA) + */ +template +class msvc_sink : public base_sink { public: - explicit msvc_sink() - { - } + msvc_sink() = default; + msvc_sink(bool check_debugger_present) + : check_debugger_present_{check_debugger_present} {}; protected: - void _sink_it(const details::log_msg& msg) override - { - OutputDebugStringA(msg.formatted.c_str()); + void sink_it_(const details::log_msg &msg) override { + if (check_debugger_present_ && !IsDebuggerPresent()) { + return; + } + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + formatted.push_back('\0'); // add a null terminator for OutputDebugString + #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) + wmemory_buf_t wformatted; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted); + OutputDebugStringW(wformatted.data()); + #else + OutputDebugStringA(formatted.data()); + #endif } - void _flush() override - {} + void flush_() override {} + + bool check_debugger_present_ = true; }; using msvc_sink_mt = msvc_sink; using msvc_sink_st = msvc_sink; -} -} +using windebug_sink_mt = msvc_sink_mt; +using windebug_sink_st = msvc_sink_st; + +} // namespace sinks +} // namespace spdlog #endif diff --git a/cpp_src/vendor/spdlog/sinks/null_sink.h b/cpp_src/vendor/spdlog/sinks/null_sink.h index 9a4fd08d8..c51247fe6 100644 --- a/cpp_src/vendor/spdlog/sinks/null_sink.h +++ b/cpp_src/vendor/spdlog/sinks/null_sink.h @@ -1,35 +1,41 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "base_sink.h" -#include "../details/null_mutex.h" +#include +#include +#include #include -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { -template -class null_sink : public base_sink -{ +template +class null_sink : public base_sink { protected: - void _sink_it(const details::log_msg&) override - {} - - void _flush() override - {} - + void sink_it_(const details::log_msg &) override {} + void flush_() override {} }; using null_sink_mt = null_sink; using null_sink_st = null_sink; +} // namespace sinks + +template +inline std::shared_ptr null_logger_mt(const std::string &logger_name) { + auto null_logger = Factory::template create(logger_name); + null_logger->set_level(level::off); + return null_logger; } + +template +inline std::shared_ptr null_logger_st(const std::string &logger_name) { + auto null_logger = Factory::template create(logger_name); + null_logger->set_level(level::off); + return null_logger; } +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/ostream_sink.h b/cpp_src/vendor/spdlog/sinks/ostream_sink.h index 9648cc05f..6af9dd091 100644 --- a/cpp_src/vendor/spdlog/sinks/ostream_sink.h +++ b/cpp_src/vendor/spdlog/sinks/ostream_sink.h @@ -1,47 +1,43 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../details/null_mutex.h" -#include "base_sink.h" +#include +#include -#include #include +#include -namespace spdlog -{ -namespace sinks -{ -template -class ostream_sink : public base_sink -{ +namespace spdlog { +namespace sinks { +template +class ostream_sink final : public base_sink { public: - explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {} - ostream_sink(const ostream_sink&) = delete; - ostream_sink& operator=(const ostream_sink&) = delete; + explicit ostream_sink(std::ostream &os, bool force_flush = false) + : ostream_(os), + force_flush_(force_flush) {} + ostream_sink(const ostream_sink &) = delete; + ostream_sink &operator=(const ostream_sink &) = delete; protected: - void _sink_it(const details::log_msg& msg) override - { - _ostream.write(msg.formatted.data(), msg.formatted.size()); - if (_force_flush) - _ostream.flush(); + void sink_it_(const details::log_msg &msg) override { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + ostream_.write(formatted.data(), static_cast(formatted.size())); + if (force_flush_) { + ostream_.flush(); + } } - void _flush() override - { - _ostream.flush(); - } + void flush_() override { ostream_.flush(); } - std::ostream& _ostream; - bool _force_flush; + std::ostream &ostream_; + bool force_flush_; }; using ostream_sink_mt = ostream_sink; using ostream_sink_st = ostream_sink; -} -} +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/qt_sinks.h b/cpp_src/vendor/spdlog/sinks/qt_sinks.h new file mode 100644 index 000000000..d319e8473 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/qt_sinks.h @@ -0,0 +1,304 @@ +// Copyright(c) 2015-present, Gabi Melman, mguludag and spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// +// Custom sink for QPlainTextEdit or QTextEdit and its children (QTextBrowser... +// etc) Building and using requires Qt library. +// +// Warning: the qt_sink won't be notified if the target widget is destroyed. +// If the widget's lifetime can be shorter than the logger's one, you should provide some permanent +// QObject, and then use a standard signal/slot. +// + +#include "spdlog/common.h" +#include "spdlog/details/log_msg.h" +#include "spdlog/details/synchronous_factory.h" +#include "spdlog/sinks/base_sink.h" +#include + +#include +#include + +// +// qt_sink class +// +namespace spdlog { +namespace sinks { +template +class qt_sink : public base_sink { +public: + qt_sink(QObject *qt_object, std::string meta_method) + : qt_object_(qt_object), + meta_method_(std::move(meta_method)) { + if (!qt_object_) { + throw_spdlog_ex("qt_sink: qt_object is null"); + } + } + + ~qt_sink() { flush_(); } + +protected: + void sink_it_(const details::log_msg &msg) override { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + QMetaObject::invokeMethod( + qt_object_, meta_method_.c_str(), Qt::AutoConnection, + Q_ARG(QString, QString::fromUtf8(str.data(), static_cast(str.size())).trimmed())); + } + + void flush_() override {} + +private: + QObject *qt_object_ = nullptr; + std::string meta_method_; +}; + +// Qt color sink to QTextEdit. +// Color location is determined by the sink log pattern like in the rest of spdlog sinks. +// Colors can be modified if needed using sink->set_color(level, qtTextCharFormat). +// max_lines is the maximum number of lines that the sink will hold before removing the oldest +// lines. By default, only ascii (latin1) is supported by this sink. Set is_utf8 to true if utf8 +// support is needed. +template +class qt_color_sink : public base_sink { +public: + qt_color_sink(QTextEdit *qt_text_edit, + int max_lines, + bool dark_colors = false, + bool is_utf8 = false) + : qt_text_edit_(qt_text_edit), + max_lines_(max_lines), + is_utf8_(is_utf8) { + if (!qt_text_edit_) { + throw_spdlog_ex("qt_color_text_sink: text_edit is null"); + } + + default_color_ = qt_text_edit_->currentCharFormat(); + // set colors + QTextCharFormat format; + // trace + format.setForeground(dark_colors ? Qt::darkGray : Qt::gray); + colors_.at(level::trace) = format; + // debug + format.setForeground(dark_colors ? Qt::darkCyan : Qt::cyan); + colors_.at(level::debug) = format; + // info + format.setForeground(dark_colors ? Qt::darkGreen : Qt::green); + colors_.at(level::info) = format; + // warn + format.setForeground(dark_colors ? Qt::darkYellow : Qt::yellow); + colors_.at(level::warn) = format; + // err + format.setForeground(Qt::red); + colors_.at(level::err) = format; + // critical + format.setForeground(Qt::white); + format.setBackground(Qt::red); + colors_.at(level::critical) = format; + } + + ~qt_color_sink() { flush_(); } + + void set_default_color(QTextCharFormat format) { + // std::lock_guard lock(base_sink::mutex_); + default_color_ = format; + } + + void set_level_color(level::level_enum color_level, QTextCharFormat format) { + // std::lock_guard lock(base_sink::mutex_); + colors_.at(static_cast(color_level)) = format; + } + + QTextCharFormat &get_level_color(level::level_enum color_level) { + std::lock_guard lock(base_sink::mutex_); + return colors_.at(static_cast(color_level)); + } + + QTextCharFormat &get_default_color() { + std::lock_guard lock(base_sink::mutex_); + return default_color_; + } + +protected: + struct invoke_params { + invoke_params(int max_lines, + QTextEdit *q_text_edit, + QString payload, + QTextCharFormat default_color, + QTextCharFormat level_color, + int color_range_start, + int color_range_end) + : max_lines(max_lines), + q_text_edit(q_text_edit), + payload(std::move(payload)), + default_color(default_color), + level_color(level_color), + color_range_start(color_range_start), + color_range_end(color_range_end) {} + int max_lines; + QTextEdit *q_text_edit; + QString payload; + QTextCharFormat default_color; + QTextCharFormat level_color; + int color_range_start; + int color_range_end; + }; + + void sink_it_(const details::log_msg &msg) override { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + + const string_view_t str = string_view_t(formatted.data(), formatted.size()); + // apply the color to the color range in the formatted message. + QString payload; + int color_range_start = static_cast(msg.color_range_start); + int color_range_end = static_cast(msg.color_range_end); + if (is_utf8_) { + payload = QString::fromUtf8(str.data(), static_cast(str.size())); + // convert color ranges from byte index to character index. + if (msg.color_range_start < msg.color_range_end) { + color_range_start = QString::fromUtf8(str.data(), msg.color_range_start).size(); + color_range_end = QString::fromUtf8(str.data(), msg.color_range_end).size(); + } + } else { + payload = QString::fromLatin1(str.data(), static_cast(str.size())); + } + + invoke_params params{max_lines_, // max lines + qt_text_edit_, // text edit to append to + std::move(payload), // text to append + default_color_, // default color + colors_.at(msg.level), // color to apply + color_range_start, // color range start + color_range_end}; // color range end + + QMetaObject::invokeMethod( + qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection); + } + + void flush_() override {} + + // Add colored text to the text edit widget. This method is invoked in the GUI thread. + // It is a static method to ensure that it is handled correctly even if the sink is destroyed + // prematurely before it is invoked. + + static void invoke_method_(invoke_params params) { + auto *document = params.q_text_edit->document(); + QTextCursor cursor(document); + + // remove first blocks if number of blocks exceeds max_lines + while (document->blockCount() > params.max_lines) { + cursor.select(QTextCursor::BlockUnderCursor); + cursor.removeSelectedText(); + cursor.deleteChar(); // delete the newline after the block + } + + cursor.movePosition(QTextCursor::End); + cursor.setCharFormat(params.default_color); + + // if color range not specified or not not valid, just append the text with default color + if (params.color_range_end <= params.color_range_start) { + cursor.insertText(params.payload); + return; + } + + // insert the text before the color range + cursor.insertText(params.payload.left(params.color_range_start)); + + // insert the colorized text + cursor.setCharFormat(params.level_color); + cursor.insertText(params.payload.mid(params.color_range_start, + params.color_range_end - params.color_range_start)); + + // insert the text after the color range with default format + cursor.setCharFormat(params.default_color); + cursor.insertText(params.payload.mid(params.color_range_end)); + } + + QTextEdit *qt_text_edit_; + int max_lines_; + bool is_utf8_; + QTextCharFormat default_color_; + std::array colors_; +}; + +#include "spdlog/details/null_mutex.h" +#include + +using qt_sink_mt = qt_sink; +using qt_sink_st = qt_sink; +using qt_color_sink_mt = qt_color_sink; +using qt_color_sink_st = qt_color_sink; +} // namespace sinks + +// +// Factory functions +// + +// log to QTextEdit +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, + QTextEdit *qt_object, + const std::string &meta_method = "append") { + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, + QTextEdit *qt_object, + const std::string &meta_method = "append") { + return Factory::template create(logger_name, qt_object, meta_method); +} + +// log to QPlainTextEdit +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, + QPlainTextEdit *qt_object, + const std::string &meta_method = "appendPlainText") { + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, + QPlainTextEdit *qt_object, + const std::string &meta_method = "appendPlainText") { + return Factory::template create(logger_name, qt_object, meta_method); +} +// log to QObject +template +inline std::shared_ptr qt_logger_mt(const std::string &logger_name, + QObject *qt_object, + const std::string &meta_method) { + return Factory::template create(logger_name, qt_object, meta_method); +} + +template +inline std::shared_ptr qt_logger_st(const std::string &logger_name, + QObject *qt_object, + const std::string &meta_method) { + return Factory::template create(logger_name, qt_object, meta_method); +} + +// log to QTextEdit with colorized output +template +inline std::shared_ptr qt_color_logger_mt(const std::string &logger_name, + QTextEdit *qt_text_edit, + int max_lines, + bool is_utf8 = false) { + return Factory::template create(logger_name, qt_text_edit, max_lines, + false, is_utf8); +} + +template +inline std::shared_ptr qt_color_logger_st(const std::string &logger_name, + QTextEdit *qt_text_edit, + int max_lines, + bool is_utf8 = false) { + return Factory::template create(logger_name, qt_text_edit, max_lines, + false, is_utf8); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/reopen_file_sink.h b/cpp_src/vendor/spdlog/sinks/reopen_file_sink.h new file mode 100644 index 000000000..e6cfd4488 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/reopen_file_sink.h @@ -0,0 +1,100 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +/* + * File sink, that allows to manually reopen file + * Thread safe + */ +class reopen_file_sink_mt final : public sink { +public: + explicit reopen_file_sink_mt(const filename_t& filename, bool truncate = false) { file_helper_.open(filename, truncate); } + + reopen_file_sink_mt(const reopen_file_sink_mt&) = delete; + reopen_file_sink_mt& operator=(const reopen_file_sink_mt&) = delete; + + void log(const details::log_msg& msg) final override { + std::lock_guard lck(mtx_); + if (reopen_) { + file_helper_.reopen(false); + } + memory_buf_t formatted; + formatter_->format(msg, formatted); + file_helper_.write(formatted); + } + + void flush() final override { + std::lock_guard lck(mtx_); + file_helper_.flush(); + } + + void reopen() noexcept { + std::lock_guard lck(mtx_); + reopen_ = true; + } + + virtual void set_pattern(const std::string& pattern) final override { + std::lock_guard lck(mtx_); + formatter_ = details::make_unique(pattern); + } + virtual void set_formatter(std::unique_ptr sink_formatter) final override { + std::lock_guard lck(mtx_); + formatter_ = std::move(sink_formatter); + } + +private: + std::unique_ptr formatter_ = details::make_unique(); + details::file_helper file_helper_; + bool reopen_ = false; + std::mutex mtx_; +}; + +class reopen_file_sink_st final : public sink { +public: + explicit reopen_file_sink_st(const filename_t& filename, bool truncate = false) { file_helper_.open(filename, truncate); } + + reopen_file_sink_st(const reopen_file_sink_st&) = delete; + reopen_file_sink_st& operator=(const reopen_file_sink_st&) = delete; + + void log(const details::log_msg& msg) final override { + if (reopen_.load(std::memory_order_relaxed)) { + reopen_.store(false, std::memory_order_relaxed); + + // Using mutex to avoid race on flush + std::lock_guard lck(mtx_); + file_helper_.reopen(false); + } + memory_buf_t formatted; + formatter_->format(msg, formatted); + file_helper_.write(formatted); + } + + void flush() final override { + std::lock_guard lck(mtx_); + file_helper_.flush(); + } + + // This must be thread-safe + void reopen() noexcept { reopen_.store(true, std::memory_order_relaxed); } + + virtual void set_pattern(const std::string& pattern) final override { + formatter_ = details::make_unique(pattern); + } + virtual void set_formatter(std::unique_ptr sink_formatter) final override { formatter_ = std::move(sink_formatter); } + +private: + std::unique_ptr formatter_ = details::make_unique(); + details::file_helper file_helper_; + std::atomic reopen_ = {false}; + std::mutex mtx_; +}; + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/ringbuffer_sink.h b/cpp_src/vendor/spdlog/sinks/ringbuffer_sink.h new file mode 100644 index 000000000..6156c6a51 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/ringbuffer_sink.h @@ -0,0 +1,67 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include "spdlog/details/circular_q.h" +#include "spdlog/details/log_msg_buffer.h" +#include "spdlog/details/null_mutex.h" +#include "spdlog/sinks/base_sink.h" + +#include +#include +#include + +namespace spdlog { +namespace sinks { +/* + * Ring buffer sink + */ +template +class ringbuffer_sink final : public base_sink { +public: + explicit ringbuffer_sink(size_t n_items) + : q_{n_items} {} + + std::vector last_raw(size_t lim = 0) { + std::lock_guard lock(base_sink::mutex_); + auto items_available = q_.size(); + auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; + std::vector ret; + ret.reserve(n_items); + for (size_t i = (items_available - n_items); i < items_available; i++) { + ret.push_back(q_.at(i)); + } + return ret; + } + + std::vector last_formatted(size_t lim = 0) { + std::lock_guard lock(base_sink::mutex_); + auto items_available = q_.size(); + auto n_items = lim > 0 ? (std::min)(lim, items_available) : items_available; + std::vector ret; + ret.reserve(n_items); + for (size_t i = (items_available - n_items); i < items_available; i++) { + memory_buf_t formatted; + base_sink::formatter_->format(q_.at(i), formatted); + ret.push_back(SPDLOG_BUF_TO_STRING(formatted)); + } + return ret; + } + +protected: + void sink_it_(const details::log_msg &msg) override { + q_.push_back(details::log_msg_buffer{msg}); + } + void flush_() override {} + +private: + details::circular_q q_; +}; + +using ringbuffer_sink_mt = ringbuffer_sink; +using ringbuffer_sink_st = ringbuffer_sink; + +} // namespace sinks + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/rotating_file_sink-inl.h b/cpp_src/vendor/spdlog/sinks/rotating_file_sink-inl.h new file mode 100644 index 000000000..6f10256fc --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/rotating_file_sink-inl.h @@ -0,0 +1,144 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace spdlog { +namespace sinks { + +template +SPDLOG_INLINE rotating_file_sink::rotating_file_sink( + filename_t base_filename, + std::size_t max_size, + std::size_t max_files, + bool rotate_on_open, + const file_event_handlers &event_handlers) + : base_filename_(std::move(base_filename)), + max_size_(max_size), + max_files_(max_files), + file_helper_{event_handlers} { + if (max_size == 0) { + throw_spdlog_ex("rotating sink constructor: max_size arg cannot be zero"); + } + + if (max_files > 200000) { + throw_spdlog_ex("rotating sink constructor: max_files arg cannot exceed 200000"); + } + file_helper_.open(calc_filename(base_filename_, 0)); + current_size_ = file_helper_.size(); // expensive. called only once + if (rotate_on_open && current_size_ > 0) { + rotate_(); + current_size_ = 0; + } +} + +// calc filename according to index and file extension if exists. +// e.g. calc_filename("logs/mylog.txt, 3) => "logs/mylog.3.txt". +template +SPDLOG_INLINE filename_t rotating_file_sink::calc_filename(const filename_t &filename, + std::size_t index) { + if (index == 0u) { + return filename; + } + + filename_t basename, ext; + std::tie(basename, ext) = details::file_helper::split_by_extension(filename); + return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext); +} + +template +SPDLOG_INLINE filename_t rotating_file_sink::filename() { + std::lock_guard lock(base_sink::mutex_); + return file_helper_.filename(); +} + +template +SPDLOG_INLINE void rotating_file_sink::sink_it_(const details::log_msg &msg) { + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + auto new_size = current_size_ + formatted.size(); + + // rotate if the new estimated file size exceeds max size. + // rotate only if the real size > 0 to better deal with full disk (see issue #2261). + // we only check the real size when new_size > max_size_ because it is relatively expensive. + if (new_size > max_size_) { + file_helper_.flush(); + if (file_helper_.size() > 0) { + rotate_(); + new_size = formatted.size(); + } + } + file_helper_.write(formatted); + current_size_ = new_size; +} + +template +SPDLOG_INLINE void rotating_file_sink::flush_() { + file_helper_.flush(); +} + +// Rotate files: +// log.txt -> log.1.txt +// log.1.txt -> log.2.txt +// log.2.txt -> log.3.txt +// log.3.txt -> delete +template +SPDLOG_INLINE void rotating_file_sink::rotate_() { + using details::os::filename_to_str; + using details::os::path_exists; + + file_helper_.close(); + for (auto i = max_files_; i > 0; --i) { + filename_t src = calc_filename(base_filename_, i - 1); + if (!path_exists(src)) { + continue; + } + filename_t target = calc_filename(base_filename_, i); + + if (!rename_file_(src, target)) { + // if failed try again after a small delay. + // this is a workaround to a windows issue, where very high rotation + // rates can cause the rename to fail with permission denied (because of antivirus?). + details::os::sleep_for_millis(100); + if (!rename_file_(src, target)) { + file_helper_.reopen( + true); // truncate the log file anyway to prevent it to grow beyond its limit! + current_size_ = 0; + throw_spdlog_ex("rotating_file_sink: failed renaming " + filename_to_str(src) + + " to " + filename_to_str(target), + errno); + } + } + } + file_helper_.reopen(true); +} + +// delete the target if exists, and rename the src file to target +// return true on success, false otherwise. +template +SPDLOG_INLINE bool rotating_file_sink::rename_file_(const filename_t &src_filename, + const filename_t &target_filename) { + // try to delete the target file in case it already exists. + (void)details::os::remove(target_filename); + return details::os::rename(src_filename, target_filename) == 0; +} + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/rotating_file_sink.h b/cpp_src/vendor/spdlog/sinks/rotating_file_sink.h new file mode 100644 index 000000000..cd43d349d --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/rotating_file_sink.h @@ -0,0 +1,89 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +// +// Rotating file sink based on size +// +template +class rotating_file_sink final : public base_sink { +public: + rotating_file_sink(filename_t base_filename, + std::size_t max_size, + std::size_t max_files, + bool rotate_on_open = false, + const file_event_handlers &event_handlers = {}); + static filename_t calc_filename(const filename_t &filename, std::size_t index); + filename_t filename(); + +protected: + void sink_it_(const details::log_msg &msg) override; + void flush_() override; + +private: + // Rotate files: + // log.txt -> log.1.txt + // log.1.txt -> log.2.txt + // log.2.txt -> log.3.txt + // log.3.txt -> delete + void rotate_(); + + // delete the target if exists, and rename the src file to target + // return true on success, false otherwise. + bool rename_file_(const filename_t &src_filename, const filename_t &target_filename); + + filename_t base_filename_; + std::size_t max_size_; + std::size_t max_files_; + std::size_t current_size_; + details::file_helper file_helper_; +}; + +using rotating_file_sink_mt = rotating_file_sink; +using rotating_file_sink_st = rotating_file_sink; + +} // namespace sinks + +// +// factory functions +// + +template +inline std::shared_ptr rotating_logger_mt(const std::string &logger_name, + const filename_t &filename, + size_t max_file_size, + size_t max_files, + bool rotate_on_open = false, + const file_event_handlers &event_handlers = {}) { + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); +} + +template +inline std::shared_ptr rotating_logger_st(const std::string &logger_name, + const filename_t &filename, + size_t max_file_size, + size_t max_files, + bool rotate_on_open = false, + const file_event_handlers &event_handlers = {}) { + return Factory::template create( + logger_name, filename, max_file_size, max_files, rotate_on_open, event_handlers); +} +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "rotating_file_sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/sink-inl.h b/cpp_src/vendor/spdlog/sinks/sink-inl.h new file mode 100644 index 000000000..e4b271404 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/sink-inl.h @@ -0,0 +1,22 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include + +SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const { + return msg_level >= level_.load(std::memory_order_relaxed); +} + +SPDLOG_INLINE void spdlog::sinks::sink::set_level(level::level_enum log_level) { + level_.store(log_level, std::memory_order_relaxed); +} + +SPDLOG_INLINE spdlog::level::level_enum spdlog::sinks::sink::level() const { + return static_cast(level_.load(std::memory_order_relaxed)); +} diff --git a/cpp_src/vendor/spdlog/sinks/sink.h b/cpp_src/vendor/spdlog/sinks/sink.h index ff7a144e1..585068536 100644 --- a/cpp_src/vendor/spdlog/sinks/sink.h +++ b/cpp_src/vendor/spdlog/sinks/sink.h @@ -1,46 +1,34 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../details/log_msg.h" +#include +#include -namespace spdlog -{ -namespace sinks -{ -class sink -{ +namespace spdlog { + +namespace sinks { +class SPDLOG_API sink { public: virtual ~sink() = default; - - virtual void log(const details::log_msg& msg) = 0; + virtual void log(const details::log_msg &msg) = 0; virtual void flush() = 0; + virtual void set_pattern(const std::string &pattern) = 0; + virtual void set_formatter(std::unique_ptr sink_formatter) = 0; - bool should_log(level::level_enum msg_level) const; void set_level(level::level_enum log_level); level::level_enum level() const; + bool should_log(level::level_enum msg_level) const; -private: - level_t _level{ level::trace }; +protected: + // sink log level - default is all + level_t level_{level::trace}; }; -inline bool sink::should_log(level::level_enum msg_level) const -{ - return msg_level >= _level.load(std::memory_order_relaxed); -} - -inline void sink::set_level(level::level_enum log_level) -{ - _level.store(log_level); -} - -inline level::level_enum sink::level() const -{ - return static_cast(_level.load(std::memory_order_relaxed)); -} +} // namespace sinks +} // namespace spdlog -} -} +#ifdef SPDLOG_HEADER_ONLY + #include "sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/stdout_color_sinks-inl.h b/cpp_src/vendor/spdlog/sinks/stdout_color_sinks-inl.h new file mode 100644 index 000000000..166e38614 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/stdout_color_sinks-inl.h @@ -0,0 +1,38 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +namespace spdlog { + +template +SPDLOG_INLINE std::shared_ptr stdout_color_mt(const std::string &logger_name, + color_mode mode) { + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stdout_color_st(const std::string &logger_name, + color_mode mode) { + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_color_mt(const std::string &logger_name, + color_mode mode) { + return Factory::template create(logger_name, mode); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_color_st(const std::string &logger_name, + color_mode mode) { + return Factory::template create(logger_name, mode); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/stdout_color_sinks.h b/cpp_src/vendor/spdlog/sinks/stdout_color_sinks.h new file mode 100644 index 000000000..72991fe0e --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/stdout_color_sinks.h @@ -0,0 +1,49 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifdef _WIN32 + #include +#else + #include +#endif + +#include + +namespace spdlog { +namespace sinks { +#ifdef _WIN32 +using stdout_color_sink_mt = wincolor_stdout_sink_mt; +using stdout_color_sink_st = wincolor_stdout_sink_st; +using stderr_color_sink_mt = wincolor_stderr_sink_mt; +using stderr_color_sink_st = wincolor_stderr_sink_st; +#else +using stdout_color_sink_mt = ansicolor_stdout_sink_mt; +using stdout_color_sink_st = ansicolor_stdout_sink_st; +using stderr_color_sink_mt = ansicolor_stderr_sink_mt; +using stderr_color_sink_st = ansicolor_stderr_sink_st; +#endif +} // namespace sinks + +template +std::shared_ptr stdout_color_mt(const std::string &logger_name, + color_mode mode = color_mode::automatic); + +template +std::shared_ptr stdout_color_st(const std::string &logger_name, + color_mode mode = color_mode::automatic); + +template +std::shared_ptr stderr_color_mt(const std::string &logger_name, + color_mode mode = color_mode::automatic); + +template +std::shared_ptr stderr_color_st(const std::string &logger_name, + color_mode mode = color_mode::automatic); + +} // namespace spdlog + +#ifdef SPDLOG_HEADER_ONLY + #include "stdout_color_sinks-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/stdout_sinks-inl.h b/cpp_src/vendor/spdlog/sinks/stdout_sinks-inl.h new file mode 100644 index 000000000..f98244db2 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/stdout_sinks-inl.h @@ -0,0 +1,126 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include +#include + +#ifdef _WIN32 + // under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675) + // so instead we use ::FileWrite + #include + + #ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp + #include // WriteFile (..) + #endif + + #include // _get_osfhandle(..) + #include // _fileno(..) +#endif // WIN32 + +namespace spdlog { + +namespace sinks { + +template +SPDLOG_INLINE stdout_sink_base::stdout_sink_base(FILE *file) + : mutex_(ConsoleMutex::mutex()), + file_(file), + formatter_(details::make_unique()) { +#ifdef _WIN32 + // get windows handle from the FILE* object + + handle_ = reinterpret_cast(::_get_osfhandle(::_fileno(file_))); + + // don't throw to support cases where no console is attached, + // and let the log method to do nothing if (handle_ == INVALID_HANDLE_VALUE). + // throw only if non stdout/stderr target is requested (probably regular file and not console). + if (handle_ == INVALID_HANDLE_VALUE && file != stdout && file != stderr) { + throw_spdlog_ex("spdlog::stdout_sink_base: _get_osfhandle() failed", errno); + } +#endif // WIN32 +} + +template +SPDLOG_INLINE void stdout_sink_base::log(const details::log_msg &msg) { +#ifdef _WIN32 + if (handle_ == INVALID_HANDLE_VALUE) { + return; + } + std::lock_guard lock(mutex_); + memory_buf_t formatted; + formatter_->format(msg, formatted); + auto size = static_cast(formatted.size()); + DWORD bytes_written = 0; + bool ok = ::WriteFile(handle_, formatted.data(), size, &bytes_written, nullptr) != 0; + if (!ok) { + throw_spdlog_ex("stdout_sink_base: WriteFile() failed. GetLastError(): " + + std::to_string(::GetLastError())); + } +#else + std::lock_guard lock(mutex_); + memory_buf_t formatted; + formatter_->format(msg, formatted); + ::fwrite(formatted.data(), sizeof(char), formatted.size(), file_); +#endif // WIN32 + ::fflush(file_); // flush every line to terminal +} + +template +SPDLOG_INLINE void stdout_sink_base::flush() { + std::lock_guard lock(mutex_); + fflush(file_); +} + +template +SPDLOG_INLINE void stdout_sink_base::set_pattern(const std::string &pattern) { + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +SPDLOG_INLINE void stdout_sink_base::set_formatter( + std::unique_ptr sink_formatter) { + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +// stdout sink +template +SPDLOG_INLINE stdout_sink::stdout_sink() + : stdout_sink_base(stdout) {} + +// stderr sink +template +SPDLOG_INLINE stderr_sink::stderr_sink() + : stdout_sink_base(stderr) {} + +} // namespace sinks + +// factory methods +template +SPDLOG_INLINE std::shared_ptr stdout_logger_mt(const std::string &logger_name) { + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stdout_logger_st(const std::string &logger_name) { + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_logger_mt(const std::string &logger_name) { + return Factory::template create(logger_name); +} + +template +SPDLOG_INLINE std::shared_ptr stderr_logger_st(const std::string &logger_name) { + return Factory::template create(logger_name); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/stdout_sinks.h b/cpp_src/vendor/spdlog/sinks/stdout_sinks.h index 0567a05d2..6ef09968a 100644 --- a/cpp_src/vendor/spdlog/sinks/stdout_sinks.h +++ b/cpp_src/vendor/spdlog/sinks/stdout_sinks.h @@ -1,81 +1,84 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../details/null_mutex.h" -#include "base_sink.h" - #include -#include -#include +#include +#include +#include + +#ifdef _WIN32 + #include +#endif -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { -template -class stdout_sink SPDLOG_FINAL : public base_sink -{ - using MyType = stdout_sink; +namespace sinks { +template +class stdout_sink_base : public sink { public: - explicit stdout_sink() = default; + using mutex_t = typename ConsoleMutex::mutex_t; + explicit stdout_sink_base(FILE *file); + ~stdout_sink_base() override = default; + + stdout_sink_base(const stdout_sink_base &other) = delete; + stdout_sink_base(stdout_sink_base &&other) = delete; + + stdout_sink_base &operator=(const stdout_sink_base &other) = delete; + stdout_sink_base &operator=(stdout_sink_base &&other) = delete; - static std::shared_ptr instance() - { - static std::shared_ptr instance = std::make_shared(); - return instance; - } + void log(const details::log_msg &msg) override; + void flush() override; + void set_pattern(const std::string &pattern) override; + + void set_formatter(std::unique_ptr sink_formatter) override; protected: - void _sink_it(const details::log_msg& msg) override - { - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout); - _flush(); - } - - void _flush() override - { - fflush(stdout); - } + mutex_t &mutex_; + FILE *file_; + std::unique_ptr formatter_; +#ifdef _WIN32 + HANDLE handle_; +#endif // WIN32 }; -using stdout_sink_mt = stdout_sink; -using stdout_sink_st = stdout_sink; - -template -class stderr_sink SPDLOG_FINAL : public base_sink -{ - using MyType = stderr_sink; +template +class stdout_sink : public stdout_sink_base { +public: + stdout_sink(); +}; +template +class stderr_sink : public stdout_sink_base { public: - explicit stderr_sink() = default; + stderr_sink(); +}; - static std::shared_ptr instance() - { - static std::shared_ptr instance = std::make_shared(); - return instance; - } +using stdout_sink_mt = stdout_sink; +using stdout_sink_st = stdout_sink; -protected: - void _sink_it(const details::log_msg& msg) override - { - fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr); - _flush(); - } - - void _flush() override - { - fflush(stderr); - } -}; +using stderr_sink_mt = stderr_sink; +using stderr_sink_st = stderr_sink; + +} // namespace sinks + +// factory methods +template +std::shared_ptr stdout_logger_mt(const std::string &logger_name); + +template +std::shared_ptr stdout_logger_st(const std::string &logger_name); + +template +std::shared_ptr stderr_logger_mt(const std::string &logger_name); + +template +std::shared_ptr stderr_logger_st(const std::string &logger_name); -using stderr_sink_mt = stderr_sink; -using stderr_sink_st = stderr_sink; +} // namespace spdlog -} -} +#ifdef SPDLOG_HEADER_ONLY + #include "stdout_sinks-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/syslog_sink.h b/cpp_src/vendor/spdlog/sinks/syslog_sink.h index d1ffc5c88..a2df3b44d 100644 --- a/cpp_src/vendor/spdlog/sinks/syslog_sink.h +++ b/cpp_src/vendor/spdlog/sinks/syslog_sink.h @@ -1,82 +1,103 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "../common.h" - -#ifdef SPDLOG_ENABLE_SYSLOG - -#include "sink.h" -#include "../details/log_msg.h" +#include +#include +#include #include #include #include - -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { /** * Sink that write to syslog using the `syscall()` library call. - * - * Locking is not needed, as `syslog()` itself is thread-safe. */ -class syslog_sink : public sink -{ +template +class syslog_sink : public base_sink { public: - // - syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER): - _ident(ident) - { - _priorities[static_cast(level::trace)] = LOG_DEBUG; - _priorities[static_cast(level::debug)] = LOG_DEBUG; - _priorities[static_cast(level::info)] = LOG_INFO; - _priorities[static_cast(level::warn)] = LOG_WARNING; - _priorities[static_cast(level::err)] = LOG_ERR; - _priorities[static_cast(level::critical)] = LOG_CRIT; - _priorities[static_cast(level::off)] = LOG_INFO; - - //set ident to be program name if empty - ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility); + syslog_sink(std::string ident, int syslog_option, int syslog_facility, bool enable_formatting) + : enable_formatting_{enable_formatting}, + syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, + /* spdlog::level::debug */ LOG_DEBUG, + /* spdlog::level::info */ LOG_INFO, + /* spdlog::level::warn */ LOG_WARNING, + /* spdlog::level::err */ LOG_ERR, + /* spdlog::level::critical */ LOG_CRIT, + /* spdlog::level::off */ LOG_INFO}}, + ident_{std::move(ident)} { + // set ident to be program name if empty + ::openlog(ident_.empty() ? nullptr : ident_.c_str(), syslog_option, syslog_facility); } - ~syslog_sink() override - { - ::closelog(); + ~syslog_sink() override { ::closelog(); } + + syslog_sink(const syslog_sink &) = delete; + syslog_sink &operator=(const syslog_sink &) = delete; + +protected: + void sink_it_(const details::log_msg &msg) override { + string_view_t payload; + memory_buf_t formatted; + if (enable_formatting_) { + base_sink::formatter_->format(msg, formatted); + payload = string_view_t(formatted.data(), formatted.size()); + } else { + payload = msg.payload; + } + + size_t length = payload.size(); + // limit to max int + if (length > static_cast(std::numeric_limits::max())) { + length = static_cast(std::numeric_limits::max()); + } + + ::syslog(syslog_prio_from_level(msg), "%.*s", static_cast(length), payload.data()); } - syslog_sink(const syslog_sink&) = delete; - syslog_sink& operator=(const syslog_sink&) = delete; - - void log(const details::log_msg &msg) override - { - ::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str()); - } - - void flush() override - { - } - - -private: - std::array _priorities; - //must store the ident because the man says openlog might use the pointer as is and not a string copy - const std::string _ident; + void flush_() override {} + bool enable_formatting_ = false; // // Simply maps spdlog's log level to syslog priority level. // - int syslog_prio_from_level(const details::log_msg &msg) const - { - return _priorities[static_cast(msg.level)]; + int syslog_prio_from_level(const details::log_msg &msg) const { + return syslog_levels_.at(static_cast(msg.level)); } + +private: + using levels_array = std::array; + levels_array syslog_levels_; + // must store the ident because the man says openlog might use the pointer as + // is and not a string copy + const std::string ident_; }; -} + +using syslog_sink_mt = syslog_sink; +using syslog_sink_st = syslog_sink; +} // namespace sinks + +// Create and register a syslog logger +template +inline std::shared_ptr syslog_logger_mt(const std::string &logger_name, + const std::string &syslog_ident = "", + int syslog_option = 0, + int syslog_facility = LOG_USER, + bool enable_formatting = false) { + return Factory::template create(logger_name, syslog_ident, syslog_option, + syslog_facility, enable_formatting); } -#endif +template +inline std::shared_ptr syslog_logger_st(const std::string &logger_name, + const std::string &syslog_ident = "", + int syslog_option = 0, + int syslog_facility = LOG_USER, + bool enable_formatting = false) { + return Factory::template create(logger_name, syslog_ident, syslog_option, + syslog_facility, enable_formatting); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/systemd_sink.h b/cpp_src/vendor/spdlog/sinks/systemd_sink.h new file mode 100644 index 000000000..d2cd55f2e --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/systemd_sink.h @@ -0,0 +1,121 @@ +// Copyright(c) 2019 ZVYAGIN.Alexander@gmail.com +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#include + +#include +#ifndef SD_JOURNAL_SUPPRESS_LOCATION + #define SD_JOURNAL_SUPPRESS_LOCATION +#endif +#include + +namespace spdlog { +namespace sinks { + +/** + * Sink that write to systemd journal using the `sd_journal_send()` library call. + */ +template +class systemd_sink : public base_sink { +public: + systemd_sink(std::string ident = "", bool enable_formatting = false) + : ident_{std::move(ident)}, + enable_formatting_{enable_formatting}, + syslog_levels_{{/* spdlog::level::trace */ LOG_DEBUG, + /* spdlog::level::debug */ LOG_DEBUG, + /* spdlog::level::info */ LOG_INFO, + /* spdlog::level::warn */ LOG_WARNING, + /* spdlog::level::err */ LOG_ERR, + /* spdlog::level::critical */ LOG_CRIT, + /* spdlog::level::off */ LOG_INFO}} {} + + ~systemd_sink() override {} + + systemd_sink(const systemd_sink &) = delete; + systemd_sink &operator=(const systemd_sink &) = delete; + +protected: + const std::string ident_; + bool enable_formatting_ = false; + using levels_array = std::array; + levels_array syslog_levels_; + + void sink_it_(const details::log_msg &msg) override { + int err; + string_view_t payload; + memory_buf_t formatted; + if (enable_formatting_) { + base_sink::formatter_->format(msg, formatted); + payload = string_view_t(formatted.data(), formatted.size()); + } else { + payload = msg.payload; + } + + size_t length = payload.size(); + // limit to max int + if (length > static_cast(std::numeric_limits::max())) { + length = static_cast(std::numeric_limits::max()); + } + + const string_view_t syslog_identifier = ident_.empty() ? msg.logger_name : ident_; + + // Do not send source location if not available + if (msg.source.empty()) { + // Note: function call inside '()' to avoid macro expansion + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), + "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", msg.thread_id, +#endif + "SYSLOG_IDENTIFIER=%.*s", + static_cast(syslog_identifier.size()), + syslog_identifier.data(), nullptr); + } else { + err = (sd_journal_send)("MESSAGE=%.*s", static_cast(length), payload.data(), + "PRIORITY=%d", syslog_level(msg.level), +#ifndef SPDLOG_NO_THREAD_ID + "TID=%zu", msg.thread_id, +#endif + "SYSLOG_IDENTIFIER=%.*s", + static_cast(syslog_identifier.size()), + syslog_identifier.data(), "CODE_FILE=%s", msg.source.filename, + "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", + msg.source.funcname, nullptr); + } + + if (err) { + throw_spdlog_ex("Failed writing to systemd", errno); + } + } + + int syslog_level(level::level_enum l) { + return syslog_levels_.at(static_cast(l)); + } + + void flush_() override {} +}; + +using systemd_sink_mt = systemd_sink; +using systemd_sink_st = systemd_sink; +} // namespace sinks + +// Create and register a syslog logger +template +inline std::shared_ptr systemd_logger_mt(const std::string &logger_name, + const std::string &ident = "", + bool enable_formatting = false) { + return Factory::template create(logger_name, ident, enable_formatting); +} + +template +inline std::shared_ptr systemd_logger_st(const std::string &logger_name, + const std::string &ident = "", + bool enable_formatting = false) { + return Factory::template create(logger_name, ident, enable_formatting); +} +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/tcp_sink.h b/cpp_src/vendor/spdlog/sinks/tcp_sink.h new file mode 100644 index 000000000..253496454 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/tcp_sink.h @@ -0,0 +1,75 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 + #include +#else + #include +#endif + +#include +#include +#include +#include + +#pragma once + +// Simple tcp client sink +// Connects to remote address and send the formatted log. +// Will attempt to reconnect if connection drops. +// If more complicated behaviour is needed (i.e get responses), you can inherit it and override the +// sink_it_ method. + +namespace spdlog { +namespace sinks { + +struct tcp_sink_config { + std::string server_host; + int server_port; + bool lazy_connect = false; // if true connect on first log call instead of on construction + + tcp_sink_config(std::string host, int port) + : server_host{std::move(host)}, + server_port{port} {} +}; + +template +class tcp_sink : public spdlog::sinks::base_sink { +public: + // connect to tcp host/port or throw if failed + // host can be hostname or ip address + + explicit tcp_sink(tcp_sink_config sink_config) + : config_{std::move(sink_config)} { + if (!config_.lazy_connect) { + this->client_.connect(config_.server_host, config_.server_port); + } + } + + ~tcp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + if (!client_.is_connected()) { + client_.connect(config_.server_host, config_.server_port); + } + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + tcp_sink_config config_; + details::tcp_client client_; +}; + +using tcp_sink_mt = tcp_sink; +using tcp_sink_st = tcp_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/udp_sink.h b/cpp_src/vendor/spdlog/sinks/udp_sink.h new file mode 100644 index 000000000..4bff0fd2c --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/udp_sink.h @@ -0,0 +1,69 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include +#ifdef _WIN32 + #include +#else + #include +#endif + +#include +#include +#include +#include + +// Simple udp client sink +// Sends formatted log via udp + +namespace spdlog { +namespace sinks { + +struct udp_sink_config { + std::string server_host; + uint16_t server_port; + + udp_sink_config(std::string host, uint16_t port) + : server_host{std::move(host)}, + server_port{port} {} +}; + +template +class udp_sink : public spdlog::sinks::base_sink { +public: + // host can be hostname or ip address + explicit udp_sink(udp_sink_config sink_config) + : client_{sink_config.server_host, sink_config.server_port} {} + + ~udp_sink() override = default; + +protected: + void sink_it_(const spdlog::details::log_msg &msg) override { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + client_.send(formatted.data(), formatted.size()); + } + + void flush_() override {} + details::udp_client client_; +}; + +using udp_sink_mt = udp_sink; +using udp_sink_st = udp_sink; + +} // namespace sinks + +// +// factory functions +// +template +inline std::shared_ptr udp_logger_mt(const std::string &logger_name, + sinks::udp_sink_config skin_config) { + return Factory::template create(logger_name, skin_config); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/win_eventlog_sink.h b/cpp_src/vendor/spdlog/sinks/win_eventlog_sink.h new file mode 100644 index 000000000..2c9b582d3 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/win_eventlog_sink.h @@ -0,0 +1,260 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +// Writing to Windows Event Log requires the registry entries below to be present, with the +// following modifications: +// 1. should be replaced with your log name (e.g. your application name) +// 2. should be replaced with the specific source name and the key should be +// duplicated for +// each source used in the application +// +// Since typically modifications of this kind require elevation, it's better to do it as a part of +// setup procedure. The snippet below uses mscoree.dll as the message file as it exists on most of +// the Windows systems anyway and happens to contain the needed resource. +// +// You can also specify a custom message file if needed. +// Please refer to Event Log functions descriptions in MSDN for more details on custom message +// files. + +/*--------------------------------------------------------------------------------------- + +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\] + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\\] +"TypesSupported"=dword:00000007 +"EventMessageFile"=hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,\ + 00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,\ + 5c,00,6d,00,73,00,63,00,6f,00,72,00,65,00,65,00,2e,00,64,00,6c,00,6c,00,00,\ + 00 + +-----------------------------------------------------------------------------------------*/ + +#pragma once + +#include +#include + +#include +#include + +#include +#include +#include + +namespace spdlog { +namespace sinks { + +namespace win_eventlog { + +namespace internal { + +struct local_alloc_t { + HLOCAL hlocal_; + + SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {} + + local_alloc_t(local_alloc_t const &) = delete; + local_alloc_t &operator=(local_alloc_t const &) = delete; + + ~local_alloc_t() SPDLOG_NOEXCEPT { + if (hlocal_) { + LocalFree(hlocal_); + } + } +}; + +/** Windows error */ +struct win32_error : public spdlog_ex { + /** Formats an error report line: "user-message: error-code (system message)" */ + static std::string format(std::string const &user_message, DWORD error_code = GetLastError()) { + std::string system_message; + + local_alloc_t format_message_result{}; + auto format_message_succeeded = + ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&format_message_result.hlocal_, 0, nullptr); + + if (format_message_succeeded && format_message_result.hlocal_) { + system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_); + } + + return fmt_lib::format("{}: {}{}", user_message, error_code, system_message); + } + + explicit win32_error(std::string const &func_name, DWORD error = GetLastError()) + : spdlog_ex(format(func_name, error)) {} +}; + +/** Wrapper for security identifiers (SID) on Windows */ +struct sid_t { + std::vector buffer_; + +public: + sid_t() {} + + /** creates a wrapped SID copy */ + static sid_t duplicate_sid(PSID psid) { + if (!::IsValidSid(psid)) { + throw_spdlog_ex("sid_t::sid_t(): invalid SID received"); + } + + auto const sid_length{::GetLengthSid(psid)}; + + sid_t result; + result.buffer_.resize(sid_length); + if (!::CopySid(sid_length, (PSID)result.as_sid(), psid)) { + SPDLOG_THROW(win32_error("CopySid")); + } + + return result; + } + + /** Retrieves pointer to the internal buffer contents as SID* */ + SID *as_sid() const { return buffer_.empty() ? nullptr : (SID *)buffer_.data(); } + + /** Get SID for the current user */ + static sid_t get_current_user_sid() { + /* create and init RAII holder for process token */ + struct process_token_t { + HANDLE token_handle_ = INVALID_HANDLE_VALUE; + explicit process_token_t(HANDLE process) { + if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle_)) { + SPDLOG_THROW(win32_error("OpenProcessToken")); + } + } + + ~process_token_t() { ::CloseHandle(token_handle_); } + + } current_process_token( + ::GetCurrentProcess()); // GetCurrentProcess returns pseudohandle, no leak here! + + // Get the required size, this is expected to fail with ERROR_INSUFFICIENT_BUFFER and return + // the token size + DWORD tusize = 0; + if (::GetTokenInformation(current_process_token.token_handle_, TokenUser, NULL, 0, + &tusize)) { + SPDLOG_THROW(win32_error("GetTokenInformation should fail")); + } + + // get user token + std::vector buffer(static_cast(tusize)); + if (!::GetTokenInformation(current_process_token.token_handle_, TokenUser, + (LPVOID)buffer.data(), tusize, &tusize)) { + SPDLOG_THROW(win32_error("GetTokenInformation")); + } + + // create a wrapper of the SID data as stored in the user token + return sid_t::duplicate_sid(((TOKEN_USER *)buffer.data())->User.Sid); + } +}; + +struct eventlog { + static WORD get_event_type(details::log_msg const &msg) { + switch (msg.level) { + case level::trace: + case level::debug: + return EVENTLOG_SUCCESS; + + case level::info: + return EVENTLOG_INFORMATION_TYPE; + + case level::warn: + return EVENTLOG_WARNING_TYPE; + + case level::err: + case level::critical: + case level::off: + return EVENTLOG_ERROR_TYPE; + + default: + return EVENTLOG_INFORMATION_TYPE; + } + } + + static WORD get_event_category(details::log_msg const &msg) { return (WORD)msg.level; } +}; + +} // namespace internal + +/* + * Windows Event Log sink + */ +template +class win_eventlog_sink : public base_sink { +private: + HANDLE hEventLog_{NULL}; + internal::sid_t current_user_sid_; + std::string source_; + DWORD event_id_; + + HANDLE event_log_handle() { + if (!hEventLog_) { + hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str()); + if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED) { + SPDLOG_THROW(internal::win32_error("RegisterEventSource")); + } + } + + return hEventLog_; + } + +protected: + void sink_it_(const details::log_msg &msg) override { + using namespace internal; + + bool succeeded; + memory_buf_t formatted; + base_sink::formatter_->format(msg, formatted); + formatted.push_back('\0'); + +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT + wmemory_buf_t buf; + details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf); + + LPCWSTR lp_wstr = buf.data(); + succeeded = static_cast(::ReportEventW( + event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr)); +#else + LPCSTR lp_str = formatted.data(); + succeeded = static_cast(::ReportEventA( + event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), + event_id_, current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr)); +#endif + + if (!succeeded) { + SPDLOG_THROW(win32_error("ReportEvent")); + } + } + + void flush_() override {} + +public: + win_eventlog_sink(std::string const &source, + DWORD event_id = 1000 /* according to mscoree.dll */) + : source_(source), + event_id_(event_id) { + try { + current_user_sid_ = internal::sid_t::get_current_user_sid(); + } catch (...) { + // get_current_user_sid() is unlikely to fail and if it does, we can still proceed + // without current_user_sid but in the event log the record will have no user name + } + } + + ~win_eventlog_sink() { + if (hEventLog_) DeregisterEventSource(hEventLog_); + } +}; + +} // namespace win_eventlog + +using win_eventlog_sink_mt = win_eventlog::win_eventlog_sink; +using win_eventlog_sink_st = win_eventlog::win_eventlog_sink; + +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/wincolor_sink-inl.h b/cpp_src/vendor/spdlog/sinks/wincolor_sink-inl.h new file mode 100644 index 000000000..10b8a74a2 --- /dev/null +++ b/cpp_src/vendor/spdlog/sinks/wincolor_sink-inl.h @@ -0,0 +1,163 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +#include +#include + +namespace spdlog { +namespace sinks { +template +SPDLOG_INLINE wincolor_sink::wincolor_sink(void *out_handle, color_mode mode) + : out_handle_(out_handle), + mutex_(ConsoleMutex::mutex()), + formatter_(details::make_unique()) { + set_color_mode_impl(mode); + // set level colors + colors_[level::trace] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; // white + colors_[level::debug] = FOREGROUND_GREEN | FOREGROUND_BLUE; // cyan + colors_[level::info] = FOREGROUND_GREEN; // green + colors_[level::warn] = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; // intense yellow + colors_[level::err] = FOREGROUND_RED | FOREGROUND_INTENSITY; // intense red + colors_[level::critical] = BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE | + FOREGROUND_INTENSITY; // intense white on red background + colors_[level::off] = 0; +} + +template +SPDLOG_INLINE wincolor_sink::~wincolor_sink() { + this->flush(); +} + +// change the color for the given level +template +void SPDLOG_INLINE wincolor_sink::set_color(level::level_enum level, + std::uint16_t color) { + std::lock_guard lock(mutex_); + colors_[static_cast(level)] = color; +} + +template +void SPDLOG_INLINE wincolor_sink::log(const details::log_msg &msg) { + if (out_handle_ == nullptr || out_handle_ == INVALID_HANDLE_VALUE) { + return; + } + + std::lock_guard lock(mutex_); + msg.color_range_start = 0; + msg.color_range_end = 0; + memory_buf_t formatted; + formatter_->format(msg, formatted); + if (should_do_colors_ && msg.color_range_end > msg.color_range_start) { + // before color range + print_range_(formatted, 0, msg.color_range_start); + // in color range + auto orig_attribs = + static_cast(set_foreground_color_(colors_[static_cast(msg.level)])); + print_range_(formatted, msg.color_range_start, msg.color_range_end); + // reset to orig colors + ::SetConsoleTextAttribute(static_cast(out_handle_), orig_attribs); + print_range_(formatted, msg.color_range_end, formatted.size()); + } else // print without colors if color range is invalid (or color is disabled) + { + write_to_file_(formatted); + } +} + +template +void SPDLOG_INLINE wincolor_sink::flush() { + // windows console always flushed? +} + +template +void SPDLOG_INLINE wincolor_sink::set_pattern(const std::string &pattern) { + std::lock_guard lock(mutex_); + formatter_ = std::unique_ptr(new pattern_formatter(pattern)); +} + +template +void SPDLOG_INLINE +wincolor_sink::set_formatter(std::unique_ptr sink_formatter) { + std::lock_guard lock(mutex_); + formatter_ = std::move(sink_formatter); +} + +template +void SPDLOG_INLINE wincolor_sink::set_color_mode(color_mode mode) { + std::lock_guard lock(mutex_); + set_color_mode_impl(mode); +} + +template +void SPDLOG_INLINE wincolor_sink::set_color_mode_impl(color_mode mode) { + if (mode == color_mode::automatic) { + // should do colors only if out_handle_ points to actual console. + DWORD console_mode; + bool in_console = ::GetConsoleMode(static_cast(out_handle_), &console_mode) != 0; + should_do_colors_ = in_console; + } else { + should_do_colors_ = mode == color_mode::always ? true : false; + } +} + +// set foreground color and return the orig console attributes (for resetting later) +template +std::uint16_t SPDLOG_INLINE +wincolor_sink::set_foreground_color_(std::uint16_t attribs) { + CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; + if (!::GetConsoleScreenBufferInfo(static_cast(out_handle_), &orig_buffer_info)) { + // just return white if failed getting console info + return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + } + + // change only the foreground bits (lowest 4 bits) + auto new_attribs = static_cast(attribs) | (orig_buffer_info.wAttributes & 0xfff0); + auto ignored = + ::SetConsoleTextAttribute(static_cast(out_handle_), static_cast(new_attribs)); + (void)(ignored); + return static_cast(orig_buffer_info.wAttributes); // return orig attribs +} + +// print a range of formatted message to console +template +void SPDLOG_INLINE wincolor_sink::print_range_(const memory_buf_t &formatted, + size_t start, + size_t end) { + if (end > start) { + auto size = static_cast(end - start); + auto ignored = ::WriteConsoleA(static_cast(out_handle_), formatted.data() + start, + size, nullptr, nullptr); + (void)(ignored); + } +} + +template +void SPDLOG_INLINE wincolor_sink::write_to_file_(const memory_buf_t &formatted) { + auto size = static_cast(formatted.size()); + DWORD bytes_written = 0; + auto ignored = ::WriteFile(static_cast(out_handle_), formatted.data(), size, + &bytes_written, nullptr); + (void)(ignored); +} + +// wincolor_stdout_sink +template +SPDLOG_INLINE wincolor_stdout_sink::wincolor_stdout_sink(color_mode mode) + : wincolor_sink(::GetStdHandle(STD_OUTPUT_HANDLE), mode) {} + +// wincolor_stderr_sink +template +SPDLOG_INLINE wincolor_stderr_sink::wincolor_stderr_sink(color_mode mode) + : wincolor_sink(::GetStdHandle(STD_ERROR_HANDLE), mode) {} +} // namespace sinks +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/sinks/wincolor_sink.h b/cpp_src/vendor/spdlog/sinks/wincolor_sink.h index 3b4495b0c..8ba594cc2 100644 --- a/cpp_src/vendor/spdlog/sinks/wincolor_sink.h +++ b/cpp_src/vendor/spdlog/sinks/wincolor_sink.h @@ -1,121 +1,82 @@ -// -// Copyright(c) 2016 spdlog +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once -#include "base_sink.h" -#include "../details/null_mutex.h" -#include "../common.h" +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -namespace spdlog -{ -namespace sinks -{ +namespace spdlog { +namespace sinks { /* - * Windows color console sink. Uses WriteConsoleA to write to the console with colors + * Windows color console sink. Uses WriteConsoleA to write to the console with + * colors */ -template -class wincolor_sink : public base_sink -{ +template +class wincolor_sink : public sink { public: - const WORD BOLD = FOREGROUND_INTENSITY; - const WORD RED = FOREGROUND_RED; - const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE; - const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN; - - wincolor_sink(HANDLE std_handle): out_handle_(std_handle) - { - colors_[level::trace] = CYAN; - colors_[level::debug] = CYAN; - colors_[level::info] = WHITE | BOLD; - colors_[level::warn] = YELLOW | BOLD; - colors_[level::err] = RED | BOLD; // red bold - colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background - colors_[level::off] = 0; - } - - ~wincolor_sink() override - { - this->flush(); - } - - wincolor_sink(const wincolor_sink& other) = delete; - wincolor_sink& operator=(const wincolor_sink& other) = delete; + wincolor_sink(void *out_handle, color_mode mode); + ~wincolor_sink() override; + + wincolor_sink(const wincolor_sink &other) = delete; + wincolor_sink &operator=(const wincolor_sink &other) = delete; // change the color for the given level - void set_color(level::level_enum level, WORD color) - { - std::lock_guard lock(base_sink::_mutex); - colors_[level] = color; - } + void set_color(level::level_enum level, std::uint16_t color); + void log(const details::log_msg &msg) final override; + void flush() final override; + void set_pattern(const std::string &pattern) override final; + void set_formatter(std::unique_ptr sink_formatter) override final; + void set_color_mode(color_mode mode); protected: - void _sink_it(const details::log_msg& msg) override - { - auto color = colors_[msg.level]; - auto orig_attribs = set_console_attribs(color); - WriteConsoleA(out_handle_, msg.formatted.data(), static_cast(msg.formatted.size()), nullptr, nullptr); - SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors - } - - void _flush() override - { - // windows console always flushed? - } - -private: - HANDLE out_handle_; - std::unordered_map colors_; - - // set color and return the orig console attributes (for resetting later) - WORD set_console_attribs(WORD attribs) - { - CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info; - GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info); - WORD back_color = orig_buffer_info.wAttributes; - // retrieve the current background color - back_color &= static_cast(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY)); - // keep the background color unchanged - SetConsoleTextAttribute(out_handle_, attribs | back_color); - return orig_buffer_info.wAttributes; //return orig attribs - } + using mutex_t = typename ConsoleMutex::mutex_t; + void *out_handle_; + mutex_t &mutex_; + bool should_do_colors_; + std::unique_ptr formatter_; + std::array colors_; + + // set foreground color and return the orig console attributes (for resetting later) + std::uint16_t set_foreground_color_(std::uint16_t attribs); + + // print a range of formatted message to console + void print_range_(const memory_buf_t &formatted, size_t start, size_t end); + + // in case we are redirected to file (not in console mode) + void write_to_file_(const memory_buf_t &formatted); + + void set_color_mode_impl(color_mode mode); }; -// -// windows color console to stdout -// -template -class wincolor_stdout_sink : public wincolor_sink -{ +template +class wincolor_stdout_sink : public wincolor_sink { public: - wincolor_stdout_sink() : wincolor_sink(GetStdHandle(STD_OUTPUT_HANDLE)) - {} + explicit wincolor_stdout_sink(color_mode mode = color_mode::automatic); }; -using wincolor_stdout_sink_mt = wincolor_stdout_sink; -using wincolor_stdout_sink_st = wincolor_stdout_sink; - -// -// windows color console to stderr -// -template -class wincolor_stderr_sink : public wincolor_sink -{ +template +class wincolor_stderr_sink : public wincolor_sink { public: - wincolor_stderr_sink() : wincolor_sink(GetStdHandle(STD_ERROR_HANDLE)) - {} + explicit wincolor_stderr_sink(color_mode mode = color_mode::automatic); }; -using wincolor_stderr_sink_mt = wincolor_stderr_sink; -using wincolor_stderr_sink_st = wincolor_stderr_sink; +using wincolor_stdout_sink_mt = wincolor_stdout_sink; +using wincolor_stdout_sink_st = wincolor_stdout_sink; + +using wincolor_stderr_sink_mt = wincolor_stderr_sink; +using wincolor_stderr_sink_st = wincolor_stderr_sink; +} // namespace sinks +} // namespace spdlog -} -} +#ifdef SPDLOG_HEADER_ONLY + #include "wincolor_sink-inl.h" +#endif diff --git a/cpp_src/vendor/spdlog/sinks/windebug_sink.h b/cpp_src/vendor/spdlog/sinks/windebug_sink.h deleted file mode 100644 index 37d672452..000000000 --- a/cpp_src/vendor/spdlog/sinks/windebug_sink.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright(c) 2017 Alexander Dalshov. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#if defined(_WIN32) - -#include "msvc_sink.h" - -namespace spdlog -{ -namespace sinks -{ - -/* -* Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink) -*/ -template -using windebug_sink = msvc_sink; - -using windebug_sink_mt = msvc_sink_mt; -using windebug_sink_st = msvc_sink_st; - -} -} - -#endif diff --git a/cpp_src/vendor/spdlog/spdlog-inl.h b/cpp_src/vendor/spdlog/spdlog-inl.h new file mode 100644 index 000000000..97c362222 --- /dev/null +++ b/cpp_src/vendor/spdlog/spdlog-inl.h @@ -0,0 +1,92 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#ifndef SPDLOG_HEADER_ONLY + #include +#endif + +#include +#include + +namespace spdlog { + +SPDLOG_INLINE void initialize_logger(std::shared_ptr logger) { + details::registry::instance().initialize_logger(std::move(logger)); +} + +SPDLOG_INLINE std::shared_ptr get(const std::string &name) { + return details::registry::instance().get(name); +} + +SPDLOG_INLINE void set_formatter(std::unique_ptr formatter) { + details::registry::instance().set_formatter(std::move(formatter)); +} + +SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type) { + set_formatter( + std::unique_ptr(new pattern_formatter(std::move(pattern), time_type))); +} + +SPDLOG_INLINE void enable_backtrace(size_t n_messages) { + details::registry::instance().enable_backtrace(n_messages); +} + +SPDLOG_INLINE void disable_backtrace() { details::registry::instance().disable_backtrace(); } + +SPDLOG_INLINE void dump_backtrace() { default_logger_raw()->dump_backtrace(); } + +SPDLOG_INLINE level::level_enum get_level() { return default_logger_raw()->level(); } + +SPDLOG_INLINE bool should_log(level::level_enum log_level) { + return default_logger_raw()->should_log(log_level); +} + +SPDLOG_INLINE void set_level(level::level_enum log_level) { + details::registry::instance().set_level(log_level); +} + +SPDLOG_INLINE void flush_on(level::level_enum log_level) { + details::registry::instance().flush_on(log_level); +} + +SPDLOG_INLINE void set_error_handler(void (*handler)(const std::string &msg)) { + details::registry::instance().set_error_handler(handler); +} + +SPDLOG_INLINE void register_logger(std::shared_ptr logger) { + details::registry::instance().register_logger(std::move(logger)); +} + +SPDLOG_INLINE void apply_all(const std::function)> &fun) { + details::registry::instance().apply_all(fun); +} + +SPDLOG_INLINE void drop(const std::string &name) { details::registry::instance().drop(name); } + +SPDLOG_INLINE void drop_all() { details::registry::instance().drop_all(); } + +SPDLOG_INLINE void shutdown() { details::registry::instance().shutdown(); } + +SPDLOG_INLINE void set_automatic_registration(bool automatic_registration) { + details::registry::instance().set_automatic_registration(automatic_registration); +} + +SPDLOG_INLINE std::shared_ptr default_logger() { + return details::registry::instance().default_logger(); +} + +SPDLOG_INLINE spdlog::logger *default_logger_raw() { + return details::registry::instance().get_default_raw(); +} + +SPDLOG_INLINE void set_default_logger(std::shared_ptr default_logger) { + details::registry::instance().set_default_logger(std::move(default_logger)); +} + +SPDLOG_INLINE void apply_logger_env_levels(std::shared_ptr logger) { + details::registry::instance().apply_logger_env_levels(std::move(logger)); +} + +} // namespace spdlog diff --git a/cpp_src/vendor/spdlog/spdlog.h b/cpp_src/vendor/spdlog/spdlog.h index 69935bc40..a8afbcec4 100644 --- a/cpp_src/vendor/spdlog/spdlog.h +++ b/cpp_src/vendor/spdlog/spdlog.h @@ -1,190 +1,352 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// + // spdlog main header file. // see example.cpp for usage example -#pragma once +#ifndef SPDLOG_H +#define SPDLOG_H +#pragma once -#include "common.h" -#include "logger.h" +#include +#include +#include +#include +#include -#include -#include #include +#include +#include #include -namespace spdlog -{ +namespace spdlog { + +using default_factory = synchronous_factory; +// Create and register a logger with a templated sink type +// The logger's level, formatter and flush level will be set according the +// global settings. // -// Return an existing logger or nullptr if a logger with such name doesn't exist. -// example: spdlog::get("my_logger")->info("hello {}", "world"); +// Example: +// spdlog::create("logger_name", "dailylog_filename", 11, 59); +template +inline std::shared_ptr create(std::string logger_name, SinkArgs &&...sink_args) { + return default_factory::create(std::move(logger_name), + std::forward(sink_args)...); +} + +// Initialize and register a logger, +// formatter and flush level will be set according the global settings. +// +// Useful for initializing manually created loggers with the global settings. // -std::shared_ptr get(const std::string& name); +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::initialize_logger(mylogger); +SPDLOG_API void initialize_logger(std::shared_ptr logger); + +// Return an existing logger or nullptr if a logger with such name doesn't +// exist. +// example: spdlog::get("my_logger")->info("hello {}", "world"); +SPDLOG_API std::shared_ptr get(const std::string &name); +// Set global formatter. Each sink in each logger will get a clone of this object +SPDLOG_API void set_formatter(std::unique_ptr formatter); -// -// Set global formatting +// Set global format string. // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); -// -void set_pattern(const std::string& format_string); -void set_formatter(formatter_ptr f); +SPDLOG_API void set_pattern(std::string pattern, + pattern_time_type time_type = pattern_time_type::local); + +// enable global backtrace support +SPDLOG_API void enable_backtrace(size_t n_messages); + +// disable global backtrace support +SPDLOG_API void disable_backtrace(); + +// call dump backtrace on default logger +SPDLOG_API void dump_backtrace(); + +// Get global logging level +SPDLOG_API level::level_enum get_level(); -// // Set global logging level -// -void set_level(level::level_enum log_level); +SPDLOG_API void set_level(level::level_enum log_level); + +// Determine whether the default logger should log messages with a certain level +SPDLOG_API bool should_log(level::level_enum lvl); -// // Set global flush level -// -void flush_on(level::level_enum log_level); +SPDLOG_API void flush_on(level::level_enum log_level); + +// Start/Restart a periodic flusher thread +// Warning: Use only if all your loggers are thread safe! +template +inline void flush_every(std::chrono::duration interval) { + details::registry::instance().flush_every(interval); +} -// // Set global error handler -// -void set_error_handler(log_err_handler handler); +SPDLOG_API void set_error_handler(void (*handler)(const std::string &msg)); -// -// Turn on async mode (off by default) and set the queue size for each async_logger. -// effective only for loggers created after this call. -// queue_size: size of queue (must be power of 2): -// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. -// -// async_overflow_policy (optional, block_retry by default): -// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry. -// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows. -// -// worker_warmup_cb (optional): -// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity) -// -// worker_teardown_cb (optional): -// callback function that will be called in worker thread upon exit -// -void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); +// Register the given logger with the given name +SPDLOG_API void register_logger(std::shared_ptr logger); -// Turn off async mode -void set_sync_mode(); +// Apply a user defined function on all registered loggers +// Example: +// spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); +SPDLOG_API void apply_all(const std::function)> &fun); +// Drop the reference to the given logger +SPDLOG_API void drop(const std::string &name); -// -// Create and register multi/single threaded basic file logger. -// Basic logger simply writes to given file without any limitations or rotations. -// -std::shared_ptr basic_logger_mt(const std::string& logger_name, const filename_t& filename, bool truncate = false); -std::shared_ptr basic_logger_st(const std::string& logger_name, const filename_t& filename, bool truncate = false); +// Drop all references from the registry +SPDLOG_API void drop_all(); -// -// Create and register multi/single threaded rotating file logger -// -std::shared_ptr rotating_logger_mt(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); -std::shared_ptr rotating_logger_st(const std::string& logger_name, const filename_t& filename, size_t max_file_size, size_t max_files); +// stop any running threads started by spdlog and clean registry loggers +SPDLOG_API void shutdown(); -// -// Create file logger which creates new file on the given time (default in midnight): -// -std::shared_ptr daily_logger_mt(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); -std::shared_ptr daily_logger_st(const std::string& logger_name, const filename_t& filename, int hour=0, int minute=0); +// Automatic registration of loggers when using spdlog::create() or spdlog::create_async +SPDLOG_API void set_automatic_registration(bool automatic_registration); +// API for using default logger (stdout_color_mt), +// e.g: spdlog::info("Message {}", 1); // -// Create and register stdout/stderr loggers -// -std::shared_ptr stdout_logger_mt(const std::string& logger_name); -std::shared_ptr stdout_logger_st(const std::string& logger_name); -std::shared_ptr stderr_logger_mt(const std::string& logger_name); -std::shared_ptr stderr_logger_st(const std::string& logger_name); +// The default logger object can be accessed using the spdlog::default_logger(): +// For example, to add another sink to it: +// spdlog::default_logger()->sinks().push_back(some_sink); // -// Create and register colored stdout/stderr loggers +// The default logger can replaced using spdlog::set_default_logger(new_logger). +// For example, to replace it with a file logger. // -std::shared_ptr stdout_color_mt(const std::string& logger_name); -std::shared_ptr stdout_color_st(const std::string& logger_name); -std::shared_ptr stderr_color_mt(const std::string& logger_name); -std::shared_ptr stderr_color_st(const std::string& logger_name); +// IMPORTANT: +// The default API is thread safe (for _mt loggers), but: +// set_default_logger() *should not* be used concurrently with the default API. +// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. + +SPDLOG_API std::shared_ptr default_logger(); + +SPDLOG_API spdlog::logger *default_logger_raw(); +SPDLOG_API void set_default_logger(std::shared_ptr default_logger); +// Initialize logger level based on environment configs. // -// Create and register a syslog logger +// Useful for applying SPDLOG_LEVEL to manually created loggers. // -#ifdef SPDLOG_ENABLE_SYSLOG -std::shared_ptr syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0, int syslog_facilty = (1<<3)); -#endif +// Example: +// auto mylogger = std::make_shared("mylogger", ...); +// spdlog::apply_logger_env_levels(mylogger); +SPDLOG_API void apply_logger_env_levels(std::shared_ptr logger); + +template +inline void log(source_loc source, + level::level_enum lvl, + format_string_t fmt, + Args &&...args) { + default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); +} -#if defined(__ANDROID__) -std::shared_ptr android_logger(const std::string& logger_name, const std::string& tag = "spdlog"); -#endif +template +inline void log(level::level_enum lvl, format_string_t fmt, Args &&...args) { + default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); +} + +template +inline void trace(format_string_t fmt, Args &&...args) { + default_logger_raw()->trace(fmt, std::forward(args)...); +} -// Create and register a logger with a single sink -std::shared_ptr create(const std::string& logger_name, const sink_ptr& sink); +template +inline void debug(format_string_t fmt, Args &&...args) { + default_logger_raw()->debug(fmt, std::forward(args)...); +} -// Create and register a logger with multiple sinks -std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks); -template -std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end); +template +inline void info(format_string_t fmt, Args &&...args) { + default_logger_raw()->info(fmt, std::forward(args)...); +} +template +inline void warn(format_string_t fmt, Args &&...args) { + default_logger_raw()->warn(fmt, std::forward(args)...); +} -// Create and register a logger with templated sink type -// Example: -// spdlog::create("mylog", "dailylog_filename"); -template -std::shared_ptr create(const std::string& logger_name, Args... args); +template +inline void error(format_string_t fmt, Args &&...args) { + default_logger_raw()->error(fmt, std::forward(args)...); +} -// Create and register an async logger with a single sink -std::shared_ptr create_async(const std::string& logger_name, const sink_ptr& sink, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); +template +inline void critical(format_string_t fmt, Args &&...args) { + default_logger_raw()->critical(fmt, std::forward(args)...); +} -// Create and register an async logger with multiple sinks -std::shared_ptr create_async(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); -template -std::shared_ptr create_async(const std::string& logger_name, const It& sinks_begin, const It& sinks_end, size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr, const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero(), const std::function& worker_teardown_cb = nullptr); +template +inline void log(source_loc source, level::level_enum lvl, const T &msg) { + default_logger_raw()->log(source, lvl, msg); +} -// Register the given logger with the given name -void register_logger(std::shared_ptr logger); +template +inline void log(level::level_enum lvl, const T &msg) { + default_logger_raw()->log(lvl, msg); +} -// Apply a user defined function on all registered loggers -// Example: -// spdlog::apply_all([&](std::shared_ptr l) {l->flush();}); -void apply_all(const std::function)>& fun); +#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT +template +inline void log(source_loc source, + level::level_enum lvl, + wformat_string_t fmt, + Args &&...args) { + default_logger_raw()->log(source, lvl, fmt, std::forward(args)...); +} -// Drop the reference to the given logger -void drop(const std::string &name); +template +inline void log(level::level_enum lvl, wformat_string_t fmt, Args &&...args) { + default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward(args)...); +} -// Drop all references from the registry -void drop_all(); +template +inline void trace(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->trace(fmt, std::forward(args)...); +} + +template +inline void debug(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->debug(fmt, std::forward(args)...); +} + +template +inline void info(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->info(fmt, std::forward(args)...); +} + +template +inline void warn(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->warn(fmt, std::forward(args)...); +} + +template +inline void error(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->error(fmt, std::forward(args)...); +} + +template +inline void critical(wformat_string_t fmt, Args &&...args) { + default_logger_raw()->critical(fmt, std::forward(args)...); +} +#endif + +template +inline void trace(const T &msg) { + default_logger_raw()->trace(msg); +} +template +inline void debug(const T &msg) { + default_logger_raw()->debug(msg); +} + +template +inline void info(const T &msg) { + default_logger_raw()->info(msg); +} + +template +inline void warn(const T &msg) { + default_logger_raw()->warn(msg); +} + +template +inline void error(const T &msg) { + default_logger_raw()->error(msg); +} + +template +inline void critical(const T &msg) { + default_logger_raw()->critical(msg); +} + +} // namespace spdlog -/////////////////////////////////////////////////////////////////////////////// // -// Trace & Debug can be switched on/off at compile time for zero cost debug statements. -// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in tweakme.h to enable. -// SPDLOG_TRACE(..) will also print current file and line. +// enable/disable log calls at compile time according to global level. // -// Example: -// spdlog::set_level(spdlog::level::trace); -// SPDLOG_TRACE(my_logger, "some trace message"); -// SPDLOG_TRACE(my_logger, "another trace message {} {}", 1, 2); -// SPDLOG_DEBUG(my_logger, "some debug message {} {}", 3, 4); -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SPDLOG_TRACE_ON -# define SPDLOG_STR_H(x) #x -# define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x) -# ifdef _MSC_VER -# define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ "(" SPDLOG_STR_HELPER(__LINE__) ") ] " __VA_ARGS__) -# else -# define SPDLOG_TRACE(logger, ...) logger->trace("[ " __FILE__ ":" SPDLOG_STR_HELPER(__LINE__) " ] " __VA_ARGS__) -# endif +// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h): +// SPDLOG_LEVEL_TRACE, +// SPDLOG_LEVEL_DEBUG, +// SPDLOG_LEVEL_INFO, +// SPDLOG_LEVEL_WARN, +// SPDLOG_LEVEL_ERROR, +// SPDLOG_LEVEL_CRITICAL, +// SPDLOG_LEVEL_OFF +// + +#ifndef SPDLOG_NO_SOURCE_LOC + #define SPDLOG_LOGGER_CALL(logger, level, ...) \ + (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__) #else -# define SPDLOG_TRACE(logger, ...) (void)0 + #define SPDLOG_LOGGER_CALL(logger, level, ...) \ + (logger)->log(spdlog::source_loc{}, level, __VA_ARGS__) #endif -#ifdef SPDLOG_DEBUG_ON -# define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE + #define SPDLOG_LOGGER_TRACE(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__) + #define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__) #else -# define SPDLOG_DEBUG(logger, ...) (void)0 + #define SPDLOG_LOGGER_TRACE(logger, ...) (void)0 + #define SPDLOG_TRACE(...) (void)0 #endif -} +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG + #define SPDLOG_LOGGER_DEBUG(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__) + #define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__) +#else + #define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0 + #define SPDLOG_DEBUG(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO + #define SPDLOG_LOGGER_INFO(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__) + #define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__) +#else + #define SPDLOG_LOGGER_INFO(logger, ...) (void)0 + #define SPDLOG_INFO(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN + #define SPDLOG_LOGGER_WARN(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__) + #define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__) +#else + #define SPDLOG_LOGGER_WARN(logger, ...) (void)0 + #define SPDLOG_WARN(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR + #define SPDLOG_LOGGER_ERROR(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__) + #define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__) +#else + #define SPDLOG_LOGGER_ERROR(logger, ...) (void)0 + #define SPDLOG_ERROR(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL + #define SPDLOG_LOGGER_CRITICAL(logger, ...) \ + SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__) + #define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__) +#else + #define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0 + #define SPDLOG_CRITICAL(...) (void)0 +#endif + +#ifdef SPDLOG_HEADER_ONLY + #include "spdlog-inl.h" +#endif -#include "details/spdlog_impl.h" +#endif // SPDLOG_H diff --git a/cpp_src/vendor/spdlog/stopwatch.h b/cpp_src/vendor/spdlog/stopwatch.h new file mode 100644 index 000000000..39446d78e --- /dev/null +++ b/cpp_src/vendor/spdlog/stopwatch.h @@ -0,0 +1,67 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#include +#include +#include + +// Stopwatch support for spdlog (using std::chrono::steady_clock). +// Displays elapsed seconds since construction as double. +// +// Usage: +// +// spdlog::stopwatch sw; +// ... +// spdlog::debug("Elapsed: {} seconds", sw); => "Elapsed 0.005116733 seconds" +// spdlog::info("Elapsed: {:.6} seconds", sw); => "Elapsed 0.005163 seconds" +// +// +// If other units are needed (e.g. millis instead of double), include "fmt/chrono.h" and use +// "duration_cast<..>(sw.elapsed())": +// +// #include +//.. +// using std::chrono::duration_cast; +// using std::chrono::milliseconds; +// spdlog::info("Elapsed {}", duration_cast(sw.elapsed())); => "Elapsed 5ms" + +namespace spdlog { +class stopwatch { + using clock = reindexer::steady_clock_w; // Using alternative clocks to avoid vDSO issues on some systems + std::chrono::time_point start_tp_; + +public: + stopwatch() + : start_tp_{clock::now()} {} + + std::chrono::duration elapsed() const { + return std::chrono::duration(clock::now() - start_tp_); + } + + std::chrono::milliseconds elapsed_ms() const { + return std::chrono::duration_cast(clock::now() - start_tp_); + } + + void reset() { start_tp_ = clock::now(); } +}; +} // namespace spdlog + +// Support for fmt formatting (e.g. "{:012.9}" or just "{}") +namespace +#ifdef SPDLOG_USE_STD_FORMAT + std +#else + fmt +#endif +{ + +template <> +struct formatter : formatter { + template + auto format(const spdlog::stopwatch &sw, FormatContext &ctx) const -> decltype(ctx.out()) { + return formatter::format(sw.elapsed().count(), ctx); + } +}; +} // namespace std diff --git a/cpp_src/vendor/spdlog/tweakme.h b/cpp_src/vendor/spdlog/tweakme.h index c5509622a..a47a90764 100644 --- a/cpp_src/vendor/spdlog/tweakme.h +++ b/cpp_src/vendor/spdlog/tweakme.h @@ -1,160 +1,141 @@ -// -// Copyright(c) 2015 Gabi Melman. +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org/licenses/MIT) -// #pragma once /////////////////////////////////////////////////////////////////////////////// // -// Edit this file to squeeze more performance, and to customize supported features +// Edit this file to squeeze more performance, and to customize supported +// features // /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used. -// This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ. +// This clock is less accurate - can be off by dozens of millis - depending on +// the kernel HZ. // Uncomment to use it instead of the regular clock. // // #define SPDLOG_CLOCK_COARSE /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment if date/time logging is not needed and never appear in the log pattern. -// This will prevent spdlog from querying the clock on each log call. -// -// WARNING: If the log pattern contains any date/time while this flag is on, the result is undefined. -// You must set new pattern(spdlog::set_pattern(..") without any date/time in it +// Uncomment if source location logging is not needed. +// This will prevent spdlog from using __FILE__, __LINE__ and SPDLOG_FUNCTION // -// #define SPDLOG_NO_DATETIME +// #define SPDLOG_NO_SOURCE_LOC /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment if thread id logging is not needed (i.e. no %t in the log pattern). // This will prevent spdlog from querying the thread id on each log call. // -// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is on, the result is undefined. +// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is +// on, zero will be logged as thread id. // // #define SPDLOG_NO_THREAD_ID /////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to prevent spdlog from caching thread ids in thread local storage. -// By default spdlog saves thread ids in tls to gain a few micros for each call. -// -// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined thread ids in the children logs. -// -// #define SPDLOG_DISABLE_TID_CACHING -/////////////////////////////////////////////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment if logger name logging is not needed. -// This will prevent spdlog from copying the logger name on each log call. -// -// #define SPDLOG_NO_NAME -/////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros. +// Uncomment to prevent spdlog from using thread local storage. // -// #define SPDLOG_DEBUG_ON -// #define SPDLOG_TRACE_ON -/////////////////////////////////////////////////////////////////////////////// - - -/////////////////////////////////////////////////////////////////////////////// -// Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()). -// Use only if your code never modifies concurrently the registry. -// Note that upon creating a logger the registry is modified by spdlog.. +// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined +// thread ids in the children logs. // -// #define SPDLOG_NO_REGISTRY_MUTEX +// #define SPDLOG_NO_TLS /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to avoid spdlog's usage of atomic log levels -// Use only if your code never modifies a logger's log levels concurrently by different threads. +// Use only if your code never modifies a logger's log levels concurrently by +// different threads. // // #define SPDLOG_NO_ATOMIC_LEVELS /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable usage of wchar_t for file names on Windows. // // #define SPDLOG_WCHAR_FILENAMES /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to override default eol ("\n" or "\r\n" under Linux/Windows) // // #define SPDLOG_EOL ";-)\n" /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment to use your own copy of the fmt library instead of spdlog's copy. -// In this case spdlog will try to include so set your -I flag accordingly. +// Uncomment to override default folder separators ("/" or "\\/" under +// Linux/Windows). Each character in the string is treated as a different +// separator. // -// #define SPDLOG_FMT_EXTERNAL +// #define SPDLOG_FOLDER_SEPS "\\" /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment to use printf-style messages in your logs instead of the usual -// format-style used by default. +// Uncomment to use your own copy of the fmt library instead of spdlog's copy. +// In this case spdlog will try to include so set your -I flag +// accordingly. // -// #define SPDLOG_FMT_PRINTF +// #define SPDLOG_FMT_EXTERNAL /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment to enable syslog (disabled by default) +// Uncomment to use C++20 std::format instead of fmt. // -// #define SPDLOG_ENABLE_SYSLOG +// #define SPDLOG_USE_STD_FORMAT /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to enable wchar_t support (convert to utf8) // // #define SPDLOG_WCHAR_TO_UTF8_SUPPORT /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// // Uncomment to prevent child processes from inheriting log file descriptors // // #define SPDLOG_PREVENT_CHILD_FD /////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////// -// Uncomment if your compiler doesn't support the "final" keyword. -// The final keyword allows more optimizations in release -// mode with recent compilers. See GCC's documentation for -Wsuggest-final-types -// for instance. +// Uncomment to customize level names (e.g. "MY TRACE") // -// #define SPDLOG_NO_FINAL +// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY +// CRITICAL", "OFF" } /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment to customize short level names (e.g. "MT") +// These can be longer than one character. +// +// #define SPDLOG_SHORT_LEVEL_NAMES { "T", "D", "I", "W", "E", "C", "O" } +/////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -// Uncomment to enable message counting feature. -// Use the %i in the logger pattern to display log message sequence id. +// Uncomment to disable default logger creation. +// This might save some (very) small initialization time if no default logger is needed. // -// #define SPDLOG_ENABLE_MESSAGE_COUNTER +// #define SPDLOG_DISABLE_DEFAULT_LOGGER /////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Uncomment and set to compile time level with zero cost (default is INFO). +// Macros like SPDLOG_DEBUG(..), SPDLOG_INFO(..) will expand to empty statements if not enabled +// +// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO +/////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -// Uncomment to customize level names (e.g. "MT TRACE") +// Uncomment (and change if desired) macro to use for function names. +// This is compiler dependent. +// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc. +// Defaults to __FUNCTION__ (should work on all compilers) if not defined. // -// #define SPDLOG_LEVEL_NAMES { "MY TRACE", "MY DEBUG", "MY INFO", "MY WARNING", "MY ERROR", "MY CRITICAL", "OFF" } +// #ifdef __PRETTY_FUNCTION__ +// # define SPDLOG_FUNCTION __PRETTY_FUNCTION__ +// #else +// # define SPDLOG_FUNCTION __FUNCTION__ +// #endif /////////////////////////////////////////////////////////////////////////////// diff --git a/cpp_src/vendor/spdlog/version.h b/cpp_src/vendor/spdlog/version.h new file mode 100644 index 000000000..4fa94cb68 --- /dev/null +++ b/cpp_src/vendor/spdlog/version.h @@ -0,0 +1,11 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +#define SPDLOG_VER_MAJOR 1 +#define SPDLOG_VER_MINOR 14 +#define SPDLOG_VER_PATCH 1 + +#define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch) +#define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH) diff --git a/readme.md b/readme.md index 3669b7007..93e615986 100644 --- a/readme.md +++ b/readme.md @@ -1209,6 +1209,11 @@ Example code for aggregate `items` by `price` and `name` } ``` +Sorting by aggregated`FACET`'s fields has distinct syntax in it's SQL version: +```sql +SELECT FACET(name, price ORDER BY "name" ASC, "count" DESC) FROM items +``` + ### Search in array fields with matching array indexes Reindexer allows to search data in array fields when matching values have same indexes positions.