diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..2b6da29148 --- /dev/null +++ b/.clang-format @@ -0,0 +1,162 @@ +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -2 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: DontAlign +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true +# BeforeLambdaBody: true +# BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: true +BreakInheritanceList: BeforeComma +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^\s*(\*)?\s*\\.+' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +# EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^<(gtest|gmock)/.*' + Priority: 1 + + - Regex: '^`. For example: `CMAKE_PREFIX_PATH=D:\Qt\5.5\msvc2013_64\)` * Setup redis for Windows: [https://github.com/MSOpenTech/redis/releases](https://github.com/MSOpenTech/redis/releases) diff --git a/docs/dev/git-workflow.md b/docs/dev/git-workflow.md index af30ff36e6..5a9e41e6ff 100644 --- a/docs/dev/git-workflow.md +++ b/docs/dev/git-workflow.md @@ -1,13 +1,13 @@ ### Initialize To initialize your repo do: - * make fork from `https://github.com/ostis-dev/sc-machine` + * make fork from `https://github.com/ostis-ai/sc-machine` * clone your fork to your machine and prepare ```sh git clone git@github.com:yourlogin/sc-machine.git cd sc-machine git config --global user.name "Your Name" git config --global user.email youremail@example.com -git remote add upstream git@github.com:ostis-dev/sc-machine.git +git remote add upstream git@github.com:ostis-ai/sc-machine.git ``` ### Update To update your master from `upstream` use: @@ -35,3 +35,11 @@ git rebase --abort ### Common rules * use `git rebase` instead of `merge`. [More documentation about this command](https://git-scm.com/docs/git-rebase) This command just try to apply your commits (from current branch to commits in specified branch) + +### Git hooks + +To setup `pre-commit` hook run: +```shell +cd sc-machine +pre-commit install +``` \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 18fdead20c..86d4edd139 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ termcolor -tornado \ No newline at end of file +tornado +pre-commit \ No newline at end of file diff --git a/sc-kpm/sc-agents-common/CMakeLists.txt b/sc-kpm/sc-agents-common/CMakeLists.txt index b4d3f619e4..1bb443e2f6 100644 --- a/sc-kpm/sc-agents-common/CMakeLists.txt +++ b/sc-kpm/sc-agents-common/CMakeLists.txt @@ -10,3 +10,6 @@ target_link_libraries(sc-agents-common sc-memory) sc_codegen_ex(sc-agents-common ${SC_AGENTS_COMMON_SRC} "${SC_AGENTS_COMMON_SRC}/generated") target_compile_definitions(sc-agents-common PRIVATE "-DSC_AGENTS_COMMON_SELF_BUILD") +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-agents-common) +endif () diff --git a/sc-kpm/sc-agents-common/keynodes/coreKeynodes.cpp b/sc-kpm/sc-agents-common/keynodes/coreKeynodes.cpp index 0ebd0484a9..4a32a9c8e0 100644 --- a/sc-kpm/sc-agents-common/keynodes/coreKeynodes.cpp +++ b/sc-kpm/sc-agents-common/keynodes/coreKeynodes.cpp @@ -1,14 +1,13 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "coreKeynodes.hpp" namespace scAgentsCommon { - ScAddr CoreKeynodes::question; ScAddr CoreKeynodes::question_initiated; ScAddr CoreKeynodes::question_finished; @@ -38,4 +37,4 @@ ScAddr CoreKeynodes::cardinality; ScAddr CoreKeynodes::lang_ru; ScAddr CoreKeynodes::nrel_basic_sequence; -} +} // namespace scAgentsCommon diff --git a/sc-kpm/sc-agents-common/keynodes/coreKeynodes.hpp b/sc-kpm/sc-agents-common/keynodes/coreKeynodes.hpp index 08c6ed17ae..e9cd29e8b2 100644 --- a/sc-kpm/sc-agents-common/keynodes/coreKeynodes.hpp +++ b/sc-kpm/sc-agents-common/keynodes/coreKeynodes.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -13,14 +13,12 @@ namespace scAgentsCommon { - class CoreKeynodes : public ScObject { SC_CLASS() SC_GENERATED_BODY() public: - SC_PROPERTY(Keynode("question"), ForceCreate) static ScAddr question; @@ -106,4 +104,4 @@ class CoreKeynodes : public ScObject static ScAddr nrel_basic_sequence; }; -} // namespace scAgentsCommon +} // namespace scAgentsCommon diff --git a/sc-kpm/sc-agents-common/sc_agents_common.cpp b/sc-kpm/sc-agents-common/sc_agents_common.cpp index c13e6d3f5d..f01d73f5bb 100644 --- a/sc-kpm/sc-agents-common/sc_agents_common.cpp +++ b/sc-kpm/sc-agents-common/sc_agents_common.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "keynodes/coreKeynodes.hpp" @@ -14,7 +14,6 @@ SC_IMPLEMENT_MODULE(SCAgentsCommonModule) sc_result SCAgentsCommonModule::InitializeImpl() { - if (!CoreKeynodes::InitGlobal()) return SC_RESULT_ERROR; diff --git a/sc-kpm/sc-agents-common/sc_agents_common.hpp b/sc-kpm/sc-agents-common/sc_agents_common.hpp index 9496611068..401334992d 100644 --- a/sc-kpm/sc-agents-common/sc_agents_common.hpp +++ b/sc-kpm/sc-agents-common/sc_agents_common.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once diff --git a/sc-kpm/sc-agents-common/utils/AgentUtils.cpp b/sc-kpm/sc-agents-common/utils/AgentUtils.cpp index 792d7873ec..762e651185 100644 --- a/sc-kpm/sc-agents-common/utils/AgentUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/AgentUtils.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "AgentUtils.hpp" @@ -17,11 +17,10 @@ using namespace scAgentsCommon; namespace utils { - void AgentUtils::assignParamsToQuestionNode( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddrVector & params) + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddrVector & params) { SC_CHECK_PARAM(questionNode, ("Invalid question node address")) @@ -36,7 +35,7 @@ void AgentUtils::assignParamsToQuestionNode( ScAddr AgentUtils::createQuestionNode(ScMemoryContext * ms_context) { ScAddr questionNode = ms_context->CreateNode(ScType::NodeConst); - ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, CoreKeynodes::question, questionNode); + ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, CoreKeynodes::question, questionNode); return questionNode; } @@ -44,8 +43,7 @@ bool AgentUtils::waitAgentResult(ScMemoryContext * ms_context, const ScAddr & qu { SC_CHECK_PARAM(questionNode, ("Invalid question node address")) - auto check = [ms_context](ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) - { + auto check = [ms_context](ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) { return ms_context->HelperCheckEdge(CoreKeynodes::nrel_answer, edgeAddr, ScType::EdgeAccessConstPosPerm); }; ScWaitCondition waiter(*ms_context, questionNode, SC_WAIT_CHECK(check)); @@ -65,9 +63,9 @@ ScAddr AgentUtils::initAgent(ScMemoryContext * ms_context, const ScAddr & questi } ScAddr AgentUtils::initAgentAndWaitResult( - ScMemoryContext * ms_context, - const ScAddr & questionClass, - const ScAddrVector & params) + ScMemoryContext * ms_context, + const ScAddr & questionClass, + const ScAddrVector & params) { SC_CHECK_PARAM(questionClass, ("Invalid question class address")) @@ -81,10 +79,10 @@ ScAddr AgentUtils::initAgentAndWaitResult( } void AgentUtils::finishAgentWork( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddr & answerNode, - bool isSuccess) + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddr & answerNode, + bool isSuccess) { SC_CHECK_PARAM(questionNode, ("Invalid question node address")) SC_CHECK_PARAM(answerNode, ("Invalid answer node address")) @@ -96,10 +94,10 @@ void AgentUtils::finishAgentWork( } void AgentUtils::finishAgentWork( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddrVector & answerElements, - bool isSuccess) + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddrVector & answerElements, + bool isSuccess) { SC_CHECK_PARAM(questionNode, ("Invalid question node address")) @@ -115,10 +113,9 @@ void AgentUtils::finishAgentWork(ScMemoryContext * ms_context, const ScAddr & qu SC_CHECK_PARAM(questionNode, ("Invalid question node address")) ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, CoreKeynodes::question_finished, questionNode); - ScAddr statusNode = isSuccess - ? CoreKeynodes::question_finished_successfully - : CoreKeynodes::question_finished_unsuccessfully; + ScAddr statusNode = + isSuccess ? CoreKeynodes::question_finished_successfully : CoreKeynodes::question_finished_unsuccessfully; ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, statusNode, questionNode); } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/AgentUtils.hpp b/sc-kpm/sc-agents-common/utils/AgentUtils.hpp index 84f084dd8f..602349ff3c 100644 --- a/sc-kpm/sc-agents-common/utils/AgentUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/AgentUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -13,14 +13,13 @@ using namespace std; namespace utils { - class AgentUtils { public: static ScAddr initAgentAndWaitResult( - ScMemoryContext * ms_context, - const ScAddr & questionClass, - const ScAddrVector & params); + ScMemoryContext * ms_context, + const ScAddr & questionClass, + const ScAddrVector & params); static ScAddr initAgent(ScMemoryContext * ms_context, const ScAddr & questionClass, const ScAddrVector & params); @@ -29,30 +28,28 @@ class AgentUtils static ScAddr createQuestionNode(ScMemoryContext * ms_context); static void assignParamsToQuestionNode( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddrVector & params); - - SC_DEPRECATED(0.6.0, "Use AgentUtils::finishAgentWork" - "(ScMemoryContext * ms_context, const ScAddr & questionNode, " - "const ScAddrVector & answerElements, bool isSuccess = true) instead of.") - static void finishAgentWork( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddr & answer, - bool isSuccess = true); - + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddrVector & params); + + SC_DEPRECATED( + 0.6.0, + "Use AgentUtils::finishAgentWork" + "(ScMemoryContext * ms_context, const ScAddr & questionNode, " + "const ScAddrVector & answerElements, bool isSuccess = true) instead of.") static void finishAgentWork( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - const ScAddrVector & answerElements, - bool isSuccess = true); + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddr & answer, + bool isSuccess = true); static void finishAgentWork( - ScMemoryContext * ms_context, - const ScAddr & questionNode, - bool isSuccess = true); + ScMemoryContext * ms_context, + const ScAddr & questionNode, + const ScAddrVector & answerElements, + bool isSuccess = true); + static void finishAgentWork(ScMemoryContext * ms_context, const ScAddr & questionNode, bool isSuccess = true); }; -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/CommonUtils.cpp b/sc-kpm/sc-agents-common/utils/CommonUtils.cpp index 499c751848..932e7910bb 100644 --- a/sc-kpm/sc-agents-common/utils/CommonUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/CommonUtils.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "CommonUtils.hpp" @@ -17,7 +17,6 @@ using namespace scAgentsCommon; namespace utils { - bool CommonUtils::checkType(ScMemoryContext * ms_context, const ScAddr & element, ScType scType) { SC_CHECK_PARAM(element, ("Invalid element address")) @@ -82,10 +81,10 @@ string CommonUtils::getIdtfValue(ScMemoryContext * ms_context, const ScAddr & no } string CommonUtils::getIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & idtfRelation, - const ScAddrVector & linkClasses) + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & idtfRelation, + const ScAddrVector & linkClasses) { string value; ScAddr scLink; @@ -116,21 +115,18 @@ string CommonUtils::getIdtf( return value; } -string CommonUtils::getMainIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddrVector & linkClasses) +string CommonUtils::getMainIdtf(ScMemoryContext * ms_context, const ScAddr & node, const ScAddrVector & linkClasses) { ScAddr mainIdtfNode = CoreKeynodes::nrel_main_idtf; return getIdtf(ms_context, node, mainIdtfNode, linkClasses); } void CommonUtils::setIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation, - const string & identifier, - const ScAddrVector & linkClasses) + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation, + const string & identifier, + const ScAddrVector & linkClasses) { ScAddr link = ms_context->CreateLink(); shared_ptr identifierStream = ScStreamConverter::StreamFromString(identifier); @@ -144,10 +140,10 @@ void CommonUtils::setIdtf( } void CommonUtils::setMainIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const string & identifier, - const ScAddrVector & linkClasses) + ScMemoryContext * ms_context, + const ScAddr & node, + const string & identifier, + const ScAddrVector & linkClasses) { ScAddr mainIdtfNode = CoreKeynodes::nrel_main_idtf; setIdtf(ms_context, node, mainIdtfNode, identifier, linkClasses); @@ -155,7 +151,7 @@ void CommonUtils::setMainIdtf( int CommonUtils::getPowerOfSet(ScMemoryContext * ms_context, const ScAddr & set) { - return (int) getSetPower(ms_context, set); + return (int)getSetPower(ms_context, set); } size_t CommonUtils::getSetPower(ScMemoryContext * ms_context, const ScAddr & set) @@ -177,4 +173,4 @@ bool CommonUtils::isEmpty(ScMemoryContext * ms_context, const ScAddr & set) return !iterator3->Next(); } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/CommonUtils.hpp b/sc-kpm/sc-agents-common/utils/CommonUtils.hpp index 16c1f5aa59..e8168df144 100644 --- a/sc-kpm/sc-agents-common/utils/CommonUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/CommonUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -13,7 +13,6 @@ using namespace std; namespace utils { - class CommonUtils { public: @@ -25,39 +24,45 @@ class CommonUtils SC_DEPRECATED(0.6.0, "Removed in 0.6.0") static int readNumber(ScMemoryContext * ms_context, const ScAddr & number); - SC_DEPRECATED(0.6.0, "Use CommonUtils::getLinkContent" - "(ScMemoryContext * ms_context, const ScAddr & scLink) instead of.") + SC_DEPRECATED( + 0.6.0, + "Use CommonUtils::getLinkContent" + "(ScMemoryContext * ms_context, const ScAddr & scLink) instead of.") static string readString(ScMemoryContext * ms_context, const ScAddr & scLink); static string getLinkContent(ScMemoryContext * ms_context, const ScAddr & scLink); - SC_DEPRECATED(0.6.0, "Use CommonUtils::getIdtf" - "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & idtfRelation) instead of.") + SC_DEPRECATED( + 0.6.0, + "Use CommonUtils::getIdtf" + "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & idtfRelation) instead of.") static string getIdtfValue(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & idtfRelation); static string getIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & idtfRelation, - const ScAddrVector & linkClasses = {}); + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & idtfRelation, + const ScAddrVector & linkClasses = {}); - static string getMainIdtf(ScMemoryContext *ms_context, const ScAddr &node, const ScAddrVector & linkClasses = {}); + static string getMainIdtf(ScMemoryContext * ms_context, const ScAddr & node, const ScAddrVector & linkClasses = {}); static void setIdtf( - ScMemoryContext *ms_context, - const ScAddr &node, - const ScAddr &relation, - const string &identifier, - const ScAddrVector & linkClasses = {}); + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation, + const string & identifier, + const ScAddrVector & linkClasses = {}); static void setMainIdtf( - ScMemoryContext * ms_context, - const ScAddr & node, - const string & identifier, - const ScAddrVector & linkClasses = {}); - - SC_DEPRECATED(0.6.0, "Use CommonUtils::getSetPower" - "(ScMemoryContext * ms_context, const ScAddr & set) instead of.") + ScMemoryContext * ms_context, + const ScAddr & node, + const string & identifier, + const ScAddrVector & linkClasses = {}); + + SC_DEPRECATED( + 0.6.0, + "Use CommonUtils::getSetPower" + "(ScMemoryContext * ms_context, const ScAddr & set) instead of.") static int getPowerOfSet(ScMemoryContext * ms_context, const ScAddr & set); static size_t getSetPower(ScMemoryContext * ms_context, const ScAddr & set); @@ -65,4 +70,4 @@ class CommonUtils static bool isEmpty(ScMemoryContext * ms_context, const ScAddr & set); }; -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/GenerationUtils.cpp b/sc-kpm/sc-agents-common/utils/GenerationUtils.cpp index e2175f49ef..2302feb405 100644 --- a/sc-kpm/sc-agents-common/utils/GenerationUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/GenerationUtils.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include @@ -19,12 +19,10 @@ using namespace std; namespace utils { - ScAddr GenerationUtils::wrapInOrientedSetBySequenceRelation( - ScMemoryContext * ms_context, - const ScAddrVector & addrVector, - const ScType & setType -) + ScMemoryContext * ms_context, + const ScAddrVector & addrVector, + const ScType & setType) { ScAddr set = ms_context->CreateNode(setType); if (addrVector.empty()) @@ -44,10 +42,9 @@ ScAddr GenerationUtils::wrapInOrientedSetBySequenceRelation( } ScAddr GenerationUtils::wrapInOrientedSet( - ScMemoryContext * ms_context, - const ScAddrVector & addrVector, - const ScType & setType -) + ScMemoryContext * ms_context, + const ScAddrVector & addrVector, + const ScType & setType) { const size_t maxRrelCountExceeded = 10; SC_ASSERT(addrVector.size() < maxRrelCountExceeded, ()); @@ -56,11 +53,7 @@ ScAddr GenerationUtils::wrapInOrientedSet( for (size_t i = 0; i < addrVector.size(); ++i) { ScAddr edge = ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, set, addrVector.at(i)); - ms_context->CreateEdge( - ScType::EdgeAccessConstPosPerm, - IteratorUtils::getRoleRelation(ms_context, i + 1), - edge - ); + ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, IteratorUtils::getRoleRelation(ms_context, i + 1), edge); } return set; @@ -69,8 +62,7 @@ ScAddr GenerationUtils::wrapInOrientedSet( ScAddr GenerationUtils::wrapInSet(ScMemoryContext * ms_context, const ScAddrVector & addrVector, const ScType & setType) { ScAddr set = ms_context->CreateNode(setType); - std::for_each(addrVector.begin(), addrVector.end(), [&ms_context, &set](const auto & element) - { + std::for_each(addrVector.begin(), addrVector.end(), [&ms_context, &set](const auto & element) { ms_context->CreateEdge(ScType::EdgeAccessConstPosPerm, set, element); }); @@ -111,10 +103,10 @@ bool GenerationUtils::addSetToOutline(ScMemoryContext * ms_context, ScAddr const } bool GenerationUtils::addNodeWithOutRelationToOutline( - ScMemoryContext * ms_context, - ScAddr const & node, - ScAddr const & relation, - ScAddr const & outline) + ScMemoryContext * ms_context, + ScAddr const & node, + ScAddr const & relation, + ScAddr const & outline) { if (!node.IsValid() || !relation.IsValid() || !outline.IsValid()) return false; @@ -129,10 +121,10 @@ bool GenerationUtils::addNodeWithOutRelationToOutline( } bool GenerationUtils::generateRelationBetween( - ScMemoryContext * ms_context, - ScAddr const & start, - ScAddr const & finish, - ScAddr const & relation) + ScMemoryContext * ms_context, + ScAddr const & start, + ScAddr const & finish, + ScAddr const & relation) { bool isSuccess = false; bool isRole = CommonUtils::checkType(ms_context, relation, ScType::NodeConstRole); @@ -146,4 +138,4 @@ bool GenerationUtils::generateRelationBetween( return isSuccess; } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/GenerationUtils.hpp b/sc-kpm/sc-agents-common/utils/GenerationUtils.hpp index a953154031..4adec2fbb2 100644 --- a/sc-kpm/sc-agents-common/utils/GenerationUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/GenerationUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -16,27 +16,23 @@ using namespace std; namespace utils { - class GenerationUtils { public: static ScAddr wrapInOrientedSetBySequenceRelation( - ScMemoryContext * ms_context, - const ScAddrVector & addrVector, - const ScType & setType = ScType::NodeConst - ); + ScMemoryContext * ms_context, + const ScAddrVector & addrVector, + const ScType & setType = ScType::NodeConst); static ScAddr wrapInOrientedSet( - ScMemoryContext * ms_context, - const ScAddrVector & addrVector, - const ScType & setType = ScType::NodeConst - ); + ScMemoryContext * ms_context, + const ScAddrVector & addrVector, + const ScType & setType = ScType::NodeConst); static ScAddr wrapInSet( - ScMemoryContext * ms_context, - const ScAddrVector & addrVector, - const ScType & setType = ScType::NodeConst); - + ScMemoryContext * ms_context, + const ScAddrVector & addrVector, + const ScType & setType = ScType::NodeConst); static void addToSet(ScMemoryContext * ms_context, const ScAddr & set, const ScAddrVector & elements); @@ -45,15 +41,15 @@ class GenerationUtils static bool addSetToOutline(ScMemoryContext * ms_context, ScAddr const & node, ScAddr const & outline); static bool addNodeWithOutRelationToOutline( - ScMemoryContext * ms_context, - ScAddr const & node, - ScAddr const & relation, - ScAddr const & outline); + ScMemoryContext * ms_context, + ScAddr const & node, + ScAddr const & relation, + ScAddr const & outline); static bool generateRelationBetween( - ScMemoryContext * ms_context, - ScAddr const & start, - ScAddr const & finish, - ScAddr const & relation); + ScMemoryContext * ms_context, + ScAddr const & start, + ScAddr const & finish, + ScAddr const & relation); }; -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/IteratorUtils.cpp b/sc-kpm/sc-agents-common/utils/IteratorUtils.cpp index 5428ea80a2..7346e80d70 100644 --- a/sc-kpm/sc-agents-common/utils/IteratorUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/IteratorUtils.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "CommonUtils.hpp" @@ -18,7 +18,6 @@ std::map orderRelationsMap; namespace utils { - ScAddr IteratorUtils::getRoleRelation(ScMemoryContext * ms_context, const size_t & index) { size_t minRrelCountExceeded = 1; @@ -28,7 +27,7 @@ ScAddr IteratorUtils::getRoleRelation(ScMemoryContext * ms_context, const size_t if (relationIter == orderRelationsMap.end()) { ScAddr relation = ms_context->HelperResolveSystemIdtf("rrel_" + to_string(index), ScType::NodeConstRole); - orderRelationsMap.insert({ index, relation }); + orderRelationsMap.insert({index, relation}); return relation; } // @todo: Implement common memory for tests with caching @@ -61,10 +60,10 @@ ScAddr IteratorUtils::getAnyFromSet(ScMemoryContext * ms_context, const ScAddr & } ScAddr IteratorUtils::getNextFromSet( - ScMemoryContext * ms_context, - const ScAddr & set, - const ScAddr & previous, - const ScAddr & sequenceRelation) + ScMemoryContext * ms_context, + const ScAddr & set, + const ScAddr & previous, + const ScAddr & sequenceRelation) { SC_CHECK_PARAM(set, ("Invalid set address")) SC_CHECK_PARAM(previous, ("Invalid previous element address")) @@ -75,20 +74,15 @@ ScAddr IteratorUtils::getNextFromSet( std::string const PREVIOUS_ELEMENT_ACCESS_ARC_ALIAS = "_previous_element_access_arc"; ScTemplate scTemplate; + scTemplate.Triple(set, ScType::EdgeAccessVarPosPerm >> PREVIOUS_ELEMENT_ACCESS_ARC_ALIAS, previous); scTemplate.Triple( - set, - ScType::EdgeAccessVarPosPerm >> PREVIOUS_ELEMENT_ACCESS_ARC_ALIAS, - previous); - scTemplate.Triple( - set, - ScType::EdgeAccessVarPosPerm >> NEXT_ELEMENT_ACCESS_ARC_ALIAS, - ScType::Unknown >> NEXT_ELEMENT_ALIAS); + set, ScType::EdgeAccessVarPosPerm >> NEXT_ELEMENT_ACCESS_ARC_ALIAS, ScType::Unknown >> NEXT_ELEMENT_ALIAS); scTemplate.TripleWithRelation( - PREVIOUS_ELEMENT_ACCESS_ARC_ALIAS, - ScType::EdgeDCommonVar, - NEXT_ELEMENT_ACCESS_ARC_ALIAS, - ScType::EdgeAccessVarPosPerm, - sequenceRelation); + PREVIOUS_ELEMENT_ACCESS_ARC_ALIAS, + ScType::EdgeDCommonVar, + NEXT_ELEMENT_ACCESS_ARC_ALIAS, + ScType::EdgeAccessVarPosPerm, + sequenceRelation); ScTemplateSearchResult searchResult; ms_context->HelperSearchTemplate(scTemplate, searchResult); @@ -113,10 +107,10 @@ ScAddrVector IteratorUtils::getAllWithType(ScMemoryContext * ms_context, const S } ScAddrVector IteratorUtils::getAllByRelation( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation, - bool isBeginNode) + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation, + bool isBeginNode) { SC_CHECK_PARAM(node, ("Invalid node address")) SC_CHECK_PARAM(relation, ("Invalid relation address")) @@ -131,9 +125,9 @@ ScAddrVector IteratorUtils::getAllByRelation( } ScAddrVector IteratorUtils::getAllByInRelation( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation) + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation) { return getAllByRelation(ms_context, node, relation, false); } @@ -162,9 +156,9 @@ ScAddr IteratorUtils::getFirstByOutRelation(ScMemoryContext * ms_context, const } ScAddrVector IteratorUtils::getAllByOutRelation( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation) + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation) { return getAllByRelation(ms_context, node, relation, true); } @@ -183,10 +177,10 @@ ScAddr IteratorUtils::getAnyByOutRelation(ScMemoryContext * ms_context, const Sc } ScIterator5Ptr IteratorUtils::getIterator5( - ScMemoryContext * ms_context, - ScAddr const & node, - ScAddr const & relation, - bool const isBeginNode) + ScMemoryContext * ms_context, + ScAddr const & node, + ScAddr const & relation, + bool const isBeginNode) { SC_CHECK_PARAM(node, ("Invalid node address")) SC_CHECK_PARAM(relation, ("Invalid relation address")) @@ -206,4 +200,4 @@ ScIterator5Ptr IteratorUtils::getIterator5( return iterator5; } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/IteratorUtils.hpp b/sc-kpm/sc-agents-common/utils/IteratorUtils.hpp index 4887b44522..ef2495498d 100644 --- a/sc-kpm/sc-agents-common/utils/IteratorUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/IteratorUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -17,7 +17,6 @@ using namespace std; namespace utils { - class IteratorUtils { public: @@ -29,43 +28,44 @@ class IteratorUtils static ScAddr getAnyFromSet(ScMemoryContext * ms_context, const ScAddr & set); static ScAddr getNextFromSet( - ScMemoryContext * ms_context, - const ScAddr & set, - const ScAddr & previous, - const ScAddr & sequenceRelation = scAgentsCommon::CoreKeynodes::nrel_basic_sequence); + ScMemoryContext * ms_context, + const ScAddr & set, + const ScAddr & previous, + const ScAddr & sequenceRelation = scAgentsCommon::CoreKeynodes::nrel_basic_sequence); static ScAddrVector getAllWithType(ScMemoryContext * ms_context, const ScAddr & set, ScType scType); static ScAddrVector getAllByRelation( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation, - bool isBeginNode = true); + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation, + bool isBeginNode = true); static ScAddrVector getAllByInRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); - SC_DEPRECATED(0.6.0, "Use IteratorUtils::getAnyByInRelation" - "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation) instead of.") + SC_DEPRECATED( + 0.6.0, + "Use IteratorUtils::getAnyByInRelation" + "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation) instead of.") static ScAddr getFirstByInRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); static ScAddr getAnyByInRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); - SC_DEPRECATED(0.6.0, "Use IteratorUtils::getAnyByOutRelation" - "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation) instead of.") + SC_DEPRECATED( + 0.6.0, + "Use IteratorUtils::getAnyByOutRelation" + "(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation) instead of.") static ScAddr getFirstByOutRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); - static ScAddrVector getAllByOutRelation( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation); + static ScAddrVector getAllByOutRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); static ScAddr getAnyByOutRelation(ScMemoryContext * ms_context, const ScAddr & node, const ScAddr & relation); static ScIterator5Ptr getIterator5( - ScMemoryContext * ms_context, - const ScAddr & node, - const ScAddr & relation, - bool nodeIsStart = true); + ScMemoryContext * ms_context, + const ScAddr & node, + const ScAddr & relation, + bool nodeIsStart = true); }; -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/LogicRuleUtils.cpp b/sc-kpm/sc-agents-common/utils/LogicRuleUtils.cpp index a96dbb929f..6f7781128c 100644 --- a/sc-kpm/sc-agents-common/utils/LogicRuleUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/LogicRuleUtils.cpp @@ -1,21 +1,19 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "LogicRuleUtils.hpp" #include "IteratorUtils.hpp" #include "keynodes/coreKeynodes.hpp" - using namespace std; using namespace scAgentsCommon; namespace utils { - ScAddr LogicRuleUtils::getIfStatement(ScMemoryContext * context, const ScAddr & logicRule) { SC_CHECK_PARAM(logicRule, ("Invalid logic rule address")) @@ -40,4 +38,4 @@ ScAddr LogicRuleUtils::getElseStatement(ScMemoryContext * context, const ScAddr return elseStatement; } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/LogicRuleUtils.hpp b/sc-kpm/sc-agents-common/utils/LogicRuleUtils.hpp index bad74255c4..1ad46e56bc 100644 --- a/sc-kpm/sc-agents-common/utils/LogicRuleUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/LogicRuleUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -13,7 +13,6 @@ using namespace std; namespace utils { - class LogicRuleUtils { public: @@ -22,4 +21,4 @@ class LogicRuleUtils static ScAddr getElseStatement(ScMemoryContext * context, const ScAddr & logicRule); }; -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/SetOperationsUtils.cpp b/sc-kpm/sc-agents-common/utils/SetOperationsUtils.cpp index 13702247ee..e900fd6cd8 100644 --- a/sc-kpm/sc-agents-common/utils/SetOperationsUtils.cpp +++ b/sc-kpm/sc-agents-common/utils/SetOperationsUtils.cpp @@ -1,28 +1,23 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "SetOperationsUtils.hpp" #include "CommonUtils.hpp" namespace utils { - ScAddr SetOperationsUtils::uniteSets(ScMemoryContext * context, const ScAddrVector & sets, const ScType & resultType) { ScAddr resultSet = context->CreateNode(resultType); for (const auto & set : sets) { - ScIterator3Ptr firstIter3 = context->Iterator3( - set, - ScType::EdgeAccessConstPosPerm, - ScType::Unknown - ); + ScIterator3Ptr firstIter3 = context->Iterator3(set, ScType::EdgeAccessConstPosPerm, ScType::Unknown); - while(firstIter3->Next()) + while (firstIter3->Next()) { ScAddr element = firstIter3->Get(2); @@ -39,19 +34,14 @@ ScAddr SetOperationsUtils::uniteSets(ScMemoryContext * context, const ScAddrVect ScAddr SetOperationsUtils::intersectSets( ScMemoryContext * context, const ScAddrVector & sets, - const ScType & resultType -) + const ScType & resultType) { ScAddr resultSet = context->CreateNode(resultType); for (const auto & set : sets) { - ScIterator3Ptr firstIter3 = context->Iterator3( - set, - ScType::EdgeAccessConstPosPerm, - ScType::Unknown - ); - while(firstIter3->Next()) + ScIterator3Ptr firstIter3 = context->Iterator3(set, ScType::EdgeAccessConstPosPerm, ScType::Unknown); + while (firstIter3->Next()) { ScAddr element = firstIter3->Get(2); @@ -88,25 +78,20 @@ ScAddr SetOperationsUtils::complementSets( ScMemoryContext * context, const ScAddr & firstSet, const ScAddr & secondSet, - const ScType & resultType -) + const ScType & resultType) { SC_CHECK_PARAM(firstSet, ("Invalid first set address")) SC_CHECK_PARAM(secondSet, ("Invalid second set address")) ScAddr resultSet = context->CreateNode(resultType); - ScIterator3Ptr secondIter3 = context->Iterator3( - secondSet, - ScType::EdgeAccessConstPosPerm, - ScType::Unknown - ); - while(secondIter3->Next()) + ScIterator3Ptr secondIter3 = context->Iterator3(secondSet, ScType::EdgeAccessConstPosPerm, ScType::Unknown); + while (secondIter3->Next()) { ScAddr element = secondIter3->Get(2); - if (!context->HelperCheckEdge(firstSet, element, ScType::EdgeAccessConstPosPerm) - && !context->HelperCheckEdge(resultSet, element, ScType::EdgeAccessConstPosPerm)) + if (!context->HelperCheckEdge(firstSet, element, ScType::EdgeAccessConstPosPerm) && + !context->HelperCheckEdge(resultSet, element, ScType::EdgeAccessConstPosPerm)) { context->CreateEdge(ScType::EdgeAccessConstPosPerm, resultSet, element); } @@ -115,11 +100,7 @@ ScAddr SetOperationsUtils::complementSets( return resultSet; } -bool SetOperationsUtils::compareSets( - ScMemoryContext * context, - const ScAddr & firstSet, - const ScAddr & secondSet -) +bool SetOperationsUtils::compareSets(ScMemoryContext * context, const ScAddr & firstSet, const ScAddr & secondSet) { SC_CHECK_PARAM(firstSet, ("Invalid first set address")) SC_CHECK_PARAM(secondSet, ("Invalid second set address")) @@ -130,12 +111,8 @@ bool SetOperationsUtils::compareSets( return false; } - ScIterator3Ptr firstIter3 = context->Iterator3( - firstSet, - ScType::EdgeAccessConstPosPerm, - ScType::Unknown - ); - while(firstIter3->Next()) + ScIterator3Ptr firstIter3 = context->Iterator3(firstSet, ScType::EdgeAccessConstPosPerm, ScType::Unknown); + while (firstIter3->Next()) { ScAddr element = firstIter3->Get(2); @@ -148,4 +125,4 @@ bool SetOperationsUtils::compareSets( return true; } -} +} // namespace utils diff --git a/sc-kpm/sc-agents-common/utils/SetOperationsUtils.hpp b/sc-kpm/sc-agents-common/utils/SetOperationsUtils.hpp index 6aa1a039c1..3fd1d8f8b1 100644 --- a/sc-kpm/sc-agents-common/utils/SetOperationsUtils.hpp +++ b/sc-kpm/sc-agents-common/utils/SetOperationsUtils.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -13,34 +13,26 @@ using namespace std; namespace utils { - class SetOperationsUtils { public: static ScAddr uniteSets( ScMemoryContext * context, const ScAddrVector & sets, - const ScType & resultType = ScType::NodeConst - ); + const ScType & resultType = ScType::NodeConst); static ScAddr intersectSets( ScMemoryContext * context, const ScAddrVector & sets, - const ScType & resultType = ScType::NodeConst - ); + const ScType & resultType = ScType::NodeConst); static ScAddr complementSets( ScMemoryContext * context, const ScAddr & firstSet, const ScAddr & secondSet, - const ScType & resultType = ScType::NodeConst - ); + const ScType & resultType = ScType::NodeConst); - static bool compareSets( - ScMemoryContext * context, - const ScAddr & firstSet, - const ScAddr & secondSet - ); + static bool compareSets(ScMemoryContext * context, const ScAddr & firstSet, const ScAddr & secondSet); }; -} +} // namespace utils diff --git a/sc-kpm/sc-common/CMakeLists.txt b/sc-kpm/sc-common/CMakeLists.txt index 2931c8f495..93ceaf2c00 100644 --- a/sc-kpm/sc-common/CMakeLists.txt +++ b/sc-kpm/sc-common/CMakeLists.txt @@ -21,3 +21,7 @@ target_include_directories(sc-kpm-common add_dependencies(sc-kpm-common sc-core) target_link_libraries(sc-kpm-common sc-core ${GLIB2_LIBRARIES}) target_compile_definitions(sc-kpm-common PUBLIC "-DSC_KPM_COMMON_SELF_BUILD") + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-kpm-common) +endif () diff --git a/sc-kpm/sc-common/sc_common_types.h b/sc-kpm/sc-common/sc_common_types.h index d997906b4b..af73810198 100644 --- a/sc-kpm/sc-common/sc_common_types.h +++ b/sc-kpm/sc-common/sc_common_types.h @@ -9,18 +9,18 @@ #include "sc-core/sc_memory.h" -#if defined (SC_MEMORY_SELF_BUILD) -# if defined (SC_PLATFORM_WIN) -# define _SC_KPM_EXTERN __declspec(dllexport) -# else -# define _SC_KPM_EXTERN -# endif +#if defined(SC_MEMORY_SELF_BUILD) +# if defined(SC_PLATFORM_WIN) +# define _SC_KPM_EXTERN __declspec(dllexport) +# else +# define _SC_KPM_EXTERN +# endif #else -# if defined (SC_PLATFORM_WIN) -# define _SC_KPM_EXTERN __declspec(dllimport) -# else -# define _SC_KPM_EXTERN -# endif +# if defined(SC_PLATFORM_WIN) +# define _SC_KPM_EXTERN __declspec(dllimport) +# else +# define _SC_KPM_EXTERN +# endif #endif -#endif //_sc_common_types_h_ +#endif //_sc_common_types_h_ diff --git a/sc-kpm/sc-common/sc_keynodes.h b/sc-kpm/sc-common/sc_keynodes.h index 86ec381af8..731cc53f1d 100644 --- a/sc-kpm/sc-common/sc_keynodes.h +++ b/sc-kpm/sc-common/sc_keynodes.h @@ -12,8 +12,11 @@ #include "sc_common_types.h" -_SC_KPM_EXTERN sc_result sc_common_resolve_keynode(sc_memory_context const * ctx, char const * sys_idtf, sc_addr * keynode); +_SC_KPM_EXTERN sc_result +sc_common_resolve_keynode(sc_memory_context const * ctx, char const * sys_idtf, sc_addr * keynode); -#define RESOLVE_KEYNODE(ctx, keynode) if (sc_common_resolve_keynode(ctx, keynode##_str, &keynode) != SC_RESULT_OK) return SC_RESULT_ERROR; +#define RESOLVE_KEYNODE(ctx, keynode) \ + if (sc_common_resolve_keynode(ctx, keynode##_str, &keynode) != SC_RESULT_OK) \ + return SC_RESULT_ERROR; #endif diff --git a/sc-kpm/sc-python/CMakeLists.txt b/sc-kpm/sc-python/CMakeLists.txt index 8562597b4e..566d7d10e7 100644 --- a/sc-kpm/sc-python/CMakeLists.txt +++ b/sc-kpm/sc-python/CMakeLists.txt @@ -9,3 +9,7 @@ target_link_libraries(sc-python sc-memory) add_dependencies(sc-python sc-memory) sc_codegen(sc-python ${CMAKE_CURRENT_LIST_DIR}) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-python) +endif () diff --git a/sc-kpm/sc-python/sc_python_module.cpp b/sc-kpm/sc-python/sc_python_module.cpp index 2047cf74c4..7f5a507247 100644 --- a/sc-kpm/sc-python/sc_python_module.cpp +++ b/sc-kpm/sc-python/sc_python_module.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_python_module.hpp" @@ -10,7 +10,6 @@ SC_IMPLEMENT_MODULE(PythonModule) sc_result PythonModule::InitializeImpl() { - m_httpService.reset(new HttpPythonService("http_api/http_api.py")); m_httpService->Run(); diff --git a/sc-kpm/sc-python/sc_python_module.hpp b/sc-kpm/sc-python/sc_python_module.hpp index 5726fd7a2d..d70863614f 100644 --- a/sc-kpm/sc-python/sc_python_module.hpp +++ b/sc-kpm/sc-python/sc_python_module.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once diff --git a/sc-kpm/sc-python/sc_python_services.hpp b/sc-kpm/sc-python/sc_python_services.hpp index d8502be0dd..eec191c13f 100644 --- a/sc-kpm/sc-python/sc_python_services.hpp +++ b/sc-kpm/sc-python/sc_python_services.hpp @@ -3,5 +3,3 @@ #include "sc-memory/python/sc_python_service.hpp" PYTHON_DECLARE_SERVICE(Http) - - diff --git a/sc-kpm/sc-search/CMakeLists.txt b/sc-kpm/sc-search/CMakeLists.txt index a41ec72c4c..d920dc40b3 100644 --- a/sc-kpm/sc-search/CMakeLists.txt +++ b/sc-kpm/sc-search/CMakeLists.txt @@ -9,3 +9,7 @@ target_include_directories(sc-search ) add_dependencies(sc-search sc-memory sc-kpm-common) target_link_libraries(sc-search sc-kpm-common) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-search) +endif () diff --git a/sc-kpm/sc-search/agents/search_identifiers.c b/sc-kpm/sc-search/agents/search_identifiers.c index 5e02dda6b6..49830074d0 100644 --- a/sc-kpm/sc-search/agents/search_identifiers.c +++ b/sc-kpm/sc-search/agents/search_identifiers.c @@ -12,53 +12,52 @@ #include "sc-core/sc_helper.h" #include "sc-core/sc_memory_headers.h" -sc_result agent_search_all_identifiers(const sc_event *event, sc_addr arg) +sc_result agent_search_all_identifiers(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2; - sc_iterator5 *it5; + sc_iterator5 * it5; sc_bool found = SC_FALSE; if (!sc_memory_get_arc_end(s_default_ctx, arg, &question)) return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_identifiers, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc(s_default_ctx, keynode_question_all_identifiers, question, sc_type_arc_pos_const_perm) == + SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { found = SC_TRUE; appendIntoAnswer(answer, sc_iterator3_value(it1, 2)); // iterate all const arcs, that are no accessory, and go out from sc-element - it5 = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 2), - sc_type_arc_common | sc_type_const, - sc_type_link, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const | sc_type_node_norole); + it5 = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it1, 2), + sc_type_arc_common | sc_type_const, + sc_type_link, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const | sc_type_node_norole); while (sc_iterator5_next(it5) == SC_TRUE) { // check if this relation is an identification - if (sc_helper_check_arc(s_default_ctx, keynode_identification_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_identification_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == + SC_TRUE) { - // iterate input arcs for sc-link - it2 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator5_value(it5, 2)); + it2 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator5_value(it5, 2)); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sc_helper_check_arc(s_default_ctx, keynode_languages, sc_iterator3_value(it2, 0), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_languages, sc_iterator3_value(it2, 0), sc_type_arc_pos_const_perm) == SC_TRUE) { appendIntoAnswer(answer, sc_iterator3_value(it2, 0)); appendIntoAnswer(answer, sc_iterator3_value(it2, 1)); @@ -85,25 +84,24 @@ sc_result agent_search_all_identifiers(const sc_event *event, sc_addr arg) return SC_RESULT_OK; } -sc_result agent_search_all_identified_elements(const sc_event *event, sc_addr arg) +sc_result agent_search_all_identified_elements(const sc_event * event, sc_addr arg) { sc_addr question, answer, begin, end; - sc_iterator3 *it1; + sc_iterator3 * it1; sc_bool found = SC_FALSE; if (!sc_memory_get_arc_end(s_default_ctx, arg, &question)) return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_identified_elements, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_all_identified_elements, question, sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - keynode_nrel_main_idtf, - sc_type_arc_pos_const_perm, - sc_type_arc_common | sc_type_const); + it1 = sc_iterator3_f_a_a_new( + s_default_ctx, keynode_nrel_main_idtf, sc_type_arc_pos_const_perm, sc_type_arc_common | sc_type_const); while (sc_iterator3_next(it1) == SC_TRUE) { found = SC_TRUE; diff --git a/sc-kpm/sc-search/agents/search_identifiers.h b/sc-kpm/sc-search/agents/search_identifiers.h index 4f28794ad3..6c94b977ab 100644 --- a/sc-kpm/sc-search/agents/search_identifiers.h +++ b/sc-kpm/sc-search/agents/search_identifiers.h @@ -9,15 +9,14 @@ #include "sc-core/sc_memory.h" - /*! * Function that implement sc-agent to search all identifiers of specified sc-elements */ -sc_result agent_search_all_identifiers(const sc_event *event, sc_addr arg); +sc_result agent_search_all_identifiers(const sc_event * event, sc_addr arg); /*! * Function that implement sc-agent to search all sc-elements identified with main identifier */ -sc_result agent_search_all_identified_elements(const sc_event *event, sc_addr arg); +sc_result agent_search_all_identified_elements(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/sc-search/agents/search_input_arcs.c b/sc-kpm/sc-search/agents/search_input_arcs.c index 89898c52f6..63a6f69038 100644 --- a/sc-kpm/sc-search/agents/search_input_arcs.c +++ b/sc-kpm/sc-search/agents/search_input_arcs.c @@ -14,7 +14,7 @@ #include "sc-core/sc_helper.h" #include "sc-core/sc_memory_headers.h" -sc_result agent_search_all_const_pos_input_arc(const sc_event *event, sc_addr arg) +sc_result agent_search_all_const_pos_input_arc(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2; @@ -24,29 +24,25 @@ sc_result agent_search_all_const_pos_input_arc(const sc_event *event, sc_addr ar return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_input_const_pos_arc, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_all_input_const_pos_arc, question, sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // find argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) sys_off = SC_FALSE; // iterate input arcs - it2 = sc_iterator3_a_a_f_new(s_default_ctx, - 0, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it1, 2)); + it2 = sc_iterator3_a_a_f_new(s_default_ctx, 0, sc_type_arc_pos_const_perm, sc_iterator3_value(it1, 2)); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 0)); @@ -66,7 +62,7 @@ sc_result agent_search_all_const_pos_input_arc(const sc_event *event, sc_addr ar // --------------------------------------------------- -sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event *event, sc_addr arg) +sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2, *it3; @@ -76,39 +72,34 @@ sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event *event, s return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_input_const_pos_arc_with_rel, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_all_input_const_pos_arc_with_rel, question, sc_type_arc_pos_const_perm) == + SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get question argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) sys_off = SC_FALSE; // iterate input arcs - it2 = sc_iterator3_a_a_f_new(s_default_ctx, - 0, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it1, 2)); + it2 = sc_iterator3_a_a_f_new(s_default_ctx, 0, sc_type_arc_pos_const_perm, sc_iterator3_value(it1, 2)); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) continue; // iterate relations - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - 0, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new(s_default_ctx, 0, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -130,4 +121,3 @@ sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event *event, s return SC_RESULT_OK; } - diff --git a/sc-kpm/sc-search/agents/search_input_arcs.h b/sc-kpm/sc-search/agents/search_input_arcs.h index 2c8992e9f2..0383accf7a 100644 --- a/sc-kpm/sc-search/agents/search_input_arcs.h +++ b/sc-kpm/sc-search/agents/search_input_arcs.h @@ -9,17 +9,16 @@ #include "sc-core/sc_memory.h" - /*! * Function that implement sc-agent to search all positive, constant and permanent * input arcs for specified sc-element */ -sc_result agent_search_all_const_pos_input_arc(const sc_event *event, sc_addr arg); +sc_result agent_search_all_const_pos_input_arc(const sc_event * event, sc_addr arg); /*! * Function that implement sc-agent to search all positive, constant and permanent * input arcs with relations for specified sc-element */ -sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event *event, sc_addr arg); +sc_result agent_search_all_const_pos_input_arc_with_rel(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/sc-search/agents/search_output_arcs.c b/sc-kpm/sc-search/agents/search_output_arcs.c index 38e34b2f2f..5736e60ece 100644 --- a/sc-kpm/sc-search/agents/search_output_arcs.c +++ b/sc-kpm/sc-search/agents/search_output_arcs.c @@ -13,7 +13,7 @@ #include "sc-core/sc_helper.h" #include "sc-core/sc_memory_headers.h" -sc_result agent_search_all_const_pos_output_arc(const sc_event *event, sc_addr arg) +sc_result agent_search_all_const_pos_output_arc(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2; @@ -23,29 +23,25 @@ sc_result agent_search_all_const_pos_output_arc(const sc_event *event, sc_addr a return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_output_const_pos_arc, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_all_output_const_pos_arc, question, sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) sys_off = SC_FALSE; // iterate output arcs and append them into answer - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 2), - sc_type_arc_pos_const_perm, - 0); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator3_value(it1, 2), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 1)); @@ -65,7 +61,7 @@ sc_result agent_search_all_const_pos_output_arc(const sc_event *event, sc_addr a } // --------------------------------------------- -sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event *event, sc_addr arg) +sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2, *it3; @@ -75,39 +71,34 @@ sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event *event, return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_all_output_const_pos_arc_with_rel, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_all_output_const_pos_arc_with_rel, question, sc_type_arc_pos_const_perm) == + SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) sys_off = SC_FALSE; // iterate output arcs and append them into answer - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 2), - sc_type_arc_pos_const_perm, - 0); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator3_value(it1, 2), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; // iterate relations - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -124,7 +115,6 @@ sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event *event, } sc_iterator3_free(it1); - connect_answer_to_question(question, answer); finish_question(question); diff --git a/sc-kpm/sc-search/agents/search_output_arcs.h b/sc-kpm/sc-search/agents/search_output_arcs.h index e82184396a..41dd9501d4 100644 --- a/sc-kpm/sc-search/agents/search_output_arcs.h +++ b/sc-kpm/sc-search/agents/search_output_arcs.h @@ -13,11 +13,11 @@ * Function that implement sc-agent to search all positive, constant and permanent * output arcs for specified sc-element */ -sc_result agent_search_all_const_pos_output_arc(const sc_event *event, sc_addr arg); +sc_result agent_search_all_const_pos_output_arc(const sc_event * event, sc_addr arg); /*! Function that implemets sc-agent to search all positive, constant and permanent * output arcs with relations for specified sc-element */ -sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event *event, sc_addr arg); +sc_result agent_search_all_const_pos_output_arc_with_rel(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/sc-search/agents/search_semantic_neighborhood.c b/sc-kpm/sc-search/agents/search_semantic_neighborhood.c index 681ce1e1b4..547c6f84d9 100644 --- a/sc-kpm/sc-search/agents/search_semantic_neighborhood.c +++ b/sc-kpm/sc-search/agents/search_semantic_neighborhood.c @@ -17,24 +17,25 @@ void search_translation(sc_addr elem, sc_addr answer, sc_bool sys_off) { - sc_iterator5 *it5; + sc_iterator5 * it5; sc_iterator3 *it3, *it4; sc_bool found = SC_FALSE; // iterate translations of sc-element - it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - elem, - sc_type_arc_pos_const_perm, - keynode_nrel_translation); + it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + elem, + sc_type_arc_pos_const_perm, + keynode_nrel_translation); while (sc_iterator5_next(it5) == SC_TRUE) { found = SC_TRUE; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 0)); @@ -42,25 +43,22 @@ void search_translation(sc_addr elem, sc_addr answer, sc_bool sys_off) appendIntoAnswer(answer, sc_iterator5_value(it5, 3)); // iterate translation sc-links - it3 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + it3 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 2)))) continue; // iterate input arcs for link - it4 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it3, 2)); + it4 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it3, 2)); while (sc_iterator3_next(it4) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)))) continue; - if (sc_helper_check_arc(s_default_ctx, keynode_languages, sc_iterator3_value(it4, 0), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_languages, sc_iterator3_value(it4, 0), sc_type_arc_pos_const_perm) == SC_TRUE) { appendIntoAnswer(answer, sc_iterator3_value(it4, 0)); appendIntoAnswer(answer, sc_iterator3_value(it4, 1)); @@ -69,13 +67,11 @@ void search_translation(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_iterator3_free(it4); // iterate input arcs for arc - it4 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it3, 1)); + it4 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it3, 1)); while (sc_iterator3_next(it4) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it4, 0)); @@ -87,7 +83,6 @@ void search_translation(sc_addr elem, sc_addr answer, sc_bool sys_off) appendIntoAnswer(answer, sc_iterator3_value(it3, 2)); } sc_iterator3_free(it3); - } sc_iterator5_free(it5); @@ -121,26 +116,24 @@ void search_nonbinary_relation(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_type el_type; // iterate input arcs for elem - it1 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - elem); + it1 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, elem); while (sc_iterator3_next(it1) == SC_TRUE) { // if elem is a link of non-binary relation - if (SC_TRUE == sc_helper_check_arc(s_default_ctx, keynode_nonbinary_relation, sc_iterator3_value(it1, 0), sc_type_arc_pos_const_perm)) + if (SC_TRUE == + sc_helper_check_arc( + s_default_ctx, keynode_nonbinary_relation, sc_iterator3_value(it1, 0), sc_type_arc_pos_const_perm)) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) continue; // iterate other elements of link - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - elem, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, elem, sc_type_arc_pos_const_perm, sc_type_node | sc_type_const); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 1)); @@ -149,13 +142,12 @@ void search_nonbinary_relation(sc_addr elem, sc_addr answer, sc_bool sys_off) search_arc_components(sc_iterator3_value(it2, 2), answer, sys_off); // iterate attributes of link - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) continue; sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it3, 0), &el_type); @@ -179,27 +171,22 @@ void search_nonbinary_relation(sc_addr elem, sc_addr answer, sc_bool sys_off) void search_typical_sc_neighborhood(sc_addr elem, sc_addr answer, sc_bool sys_off) { sc_iterator3 *it1, *it0; - sc_iterator5 *it5; + sc_iterator5 * it5; sc_bool found = SC_FALSE; // search for keynode_typical_sc_neighborhood - it0 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - elem); + it0 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, elem); while (sc_iterator3_next(it0) == SC_TRUE) { if (SC_ADDR_IS_EQUAL(sc_iterator3_value(it0, 0), keynode_typical_sc_neighborhood)) { found = SC_TRUE; // iterate input arcs for elem - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - elem, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, elem, sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it1) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it1, 1)); @@ -212,18 +199,21 @@ void search_typical_sc_neighborhood(sc_addr elem, sc_addr answer, sc_bool sys_of continue; } - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it0, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it0, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it0, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it0, 1)))) continue; - it5 = sc_iterator5_f_a_f_a_f_new(s_default_ctx, - keynode_sc_neighborhood, - sc_type_arc_common | sc_type_const, - sc_iterator3_value(it0, 0), - sc_type_arc_pos_const_perm, - keynode_nrel_strict_inclusion); + it5 = sc_iterator5_f_a_f_a_f_new( + s_default_ctx, + keynode_sc_neighborhood, + sc_type_arc_common | sc_type_const, + sc_iterator3_value(it0, 0), + sc_type_arc_pos_const_perm, + keynode_nrel_strict_inclusion); if (sc_iterator5_next(it5) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it0, 0)); @@ -232,7 +222,6 @@ void search_typical_sc_neighborhood(sc_addr elem, sc_addr answer, sc_bool sys_of appendIntoAnswer(answer, sc_iterator5_value(it5, 3)); } sc_iterator5_free(it5); - } sc_iterator3_free(it0); if (found == SC_TRUE) @@ -241,7 +230,7 @@ void search_typical_sc_neighborhood(sc_addr elem, sc_addr answer, sc_bool sys_of } } -sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr arg) +sc_result agent_search_full_semantic_neighborhood(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2, *it3, *it4, *it6; @@ -254,16 +243,14 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_full_semantic_neighborhood, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, keynode_question_full_semantic_neighborhood, question, sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get question argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) @@ -275,13 +262,11 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr search_arc_components(sc_iterator3_value(it1, 2), answer, sys_off); // iterate input arcs - it2 = sc_iterator3_a_a_f_new(s_default_ctx, - 0, - 0, - sc_iterator3_value(it1, 2)); + it2 = sc_iterator3_a_a_f_new(s_default_ctx, 0, 0, sc_iterator3_value(it1, 2)); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 0)); @@ -290,17 +275,15 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr search_arc_components(sc_iterator3_value(it2, 0), answer, sys_off); // iterate input arcs into found arc, to find relations - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it3, 0), &el_type); if (!(el_type & (sc_type_node_norole | sc_type_node_role))) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -316,16 +299,16 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr } // check if it's a quasy binary relation - if (sc_helper_check_arc(s_default_ctx, keynode_quasybinary_relation, sc_iterator3_value(it3, 0), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_quasybinary_relation, sc_iterator3_value(it3, 0), sc_type_arc_pos_const_perm) == + SC_TRUE) { // iterate elements of relation - it4 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator3_value(it2, 0), - sc_type_arc_pos_const_perm, - 0); + it4 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator3_value(it2, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it4) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it4, 1)); @@ -334,44 +317,52 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr search_arc_components(sc_iterator3_value(it4, 2), answer, sys_off); // iterate order relations between elements - it_order = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it4, 2), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it_order = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it4, 2), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it_order) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) + if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == sc_helper_check_arc( + s_default_ctx, + keynode_order_relation, + sc_iterator5_value(it_order, 4), + sc_type_arc_pos_const_perm)) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, sc_iterator3_value(it2, 0), sc_iterator5_value(it_order, 2), sc_type_arc_pos_const_perm)) + if (SC_FALSE == sc_helper_check_arc( + s_default_ctx, + sc_iterator3_value(it2, 0), + sc_iterator5_value(it_order, 2), + sc_type_arc_pos_const_perm)) continue; appendIntoAnswer(answer, sc_iterator5_value(it_order, 1)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 2)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 3)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 4)); - } sc_iterator5_free(it_order); // iterate roles of element in link - it6 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it4, 1)); + it6 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it4, 1)); while (sc_iterator3_next(it6) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it6, 0), &el_type); if (!(el_type & sc_type_node_role)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it6, 0)); @@ -380,7 +371,6 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr search_arc_components(sc_iterator3_value(it6, 0), answer, sys_off); } sc_iterator3_free(it6); - } sc_iterator3_free(it4); } @@ -388,21 +378,23 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr sc_iterator3_free(it3); // search all parents in quasybinary relation - it5 = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it2, 0), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it2, 0), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { // check if it's a quasy binary relation - if (sc_helper_check_arc(s_default_ctx, keynode_quasybinary_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_quasybinary_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == + SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 1)); @@ -421,13 +413,11 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr sc_iterator3_free(it2); // iterate output arcs - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 2), - 0, - 0); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator3_value(it1, 2), 0, 0); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 1)); @@ -436,17 +426,15 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr search_arc_components(sc_iterator3_value(it2, 2), answer, sys_off); // iterate input arcs into found arc, to find relations - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it3, 0), &el_type); if (!(el_type & (sc_type_node_norole | sc_type_node_role))) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -455,15 +443,17 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr // search of key sc-elements order if (SC_ADDR_IS_EQUAL(sc_iterator3_value(it3, 0), keynode_rrel_key_sc_element)) { - it_order2 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - sc_iterator3_value(it2, 1), - sc_type_arc_common | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_arc_pos_const_perm, - keynode_nrel_key_sc_element_base_order); + it_order2 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + sc_iterator3_value(it2, 1), + sc_type_arc_common | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_arc_pos_const_perm, + keynode_nrel_key_sc_element_base_order); while (sc_iterator5_next(it_order2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order2, 3)))) + if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order2, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order2, 3)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it_order2, 1)); @@ -484,15 +474,15 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr (el_type | sc_type_link)) { // iterate input arcs for link - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 2)); + it3 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 2)); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sc_helper_check_arc(s_default_ctx, keynode_languages, sc_iterator3_value(it3, 0), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_languages, sc_iterator3_value(it3, 0), sc_type_arc_pos_const_perm) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -505,7 +495,6 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr } } sc_iterator3_free(it2); - } sc_iterator3_free(it1); @@ -515,7 +504,7 @@ sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr return SC_RESULT_OK; } -sc_result agent_search_links_of_relation_connected_with_element(const sc_event *event, sc_addr arg) +sc_result agent_search_links_of_relation_connected_with_element(const sc_event * event, sc_addr arg) { sc_addr question, answer, param_elem, param_rel; sc_iterator3 *it1, *it2, *it3, *it4; @@ -528,18 +517,18 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_search_links_of_relation_connected_with_element, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, + keynode_question_search_links_of_relation_connected_with_element, + question, + sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get question arguments - it5 = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, question, sc_type_arc_pos_const_perm, 0, sc_type_arc_pos_const_perm, sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { if (SC_ADDR_IS_EQUAL(sc_iterator5_value(it5, 4), keynode_rrel_1)) @@ -568,21 +557,23 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * search_translation(param_elem, answer, sys_off); - if (SC_TRUE == sc_helper_check_arc(s_default_ctx, keynode_quasybinary_relation, param_rel, sc_type_arc_pos_const_perm)) + if (SC_TRUE == + sc_helper_check_arc(s_default_ctx, keynode_quasybinary_relation, param_rel, sc_type_arc_pos_const_perm)) { // Search subclasses in quasybinary relation // Iterate input arcs of quasybinary relation - it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_const, - sc_type_const | sc_type_arc_common, - param_elem, - sc_type_arc_pos_const_perm, - param_rel); + it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_const, + sc_type_const | sc_type_arc_common, + param_elem, + sc_type_arc_pos_const_perm, + param_rel); while (sc_iterator5_next(it5) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; found = SC_TRUE; @@ -596,14 +587,11 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * search_arc_components(sc_iterator5_value(it5, 0), answer, sys_off); // Iterate subclasses in quasybinary relation - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it1) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it1, 1)); @@ -614,21 +602,30 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * search_arc_components(sc_iterator3_value(it1, 2), answer, sys_off); // iterate order relations between elements - it_order = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 2), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it_order = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it1, 2), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it_order) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) + if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, sc_iterator5_value(it5, 0), sc_iterator5_value(it_order, 2), sc_type_arc_pos_const_perm)) + if (SC_FALSE == sc_helper_check_arc( + s_default_ctx, + sc_iterator5_value(it5, 0), + sc_iterator5_value(it_order, 2), + sc_type_arc_pos_const_perm)) continue; appendIntoAnswer(answer, sc_iterator5_value(it_order, 1)); @@ -639,18 +636,16 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * sc_iterator5_free(it_order); // iterate roles of element in link - it2 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it1, 1)); + it2 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it1, 1)); while (sc_iterator3_next(it2) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it2, 0), &el_type); if (!(el_type & sc_type_node_role)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it2, 0)); @@ -663,28 +658,26 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * sc_iterator5_free(it5); // Iterate input arcs of quasybinary relation - it1 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_const | sc_type_node, - sc_type_arc_pos_const_perm, - param_elem); + it1 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_const | sc_type_node, sc_type_arc_pos_const_perm, param_elem); while (sc_iterator3_next(it1) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) continue; // search all parents in quasybinary relation - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - sc_iterator3_value(it1, 0), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - param_rel); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + sc_iterator3_value(it1, 0), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + param_rel); if (sc_iterator5_next(it5) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; found = SC_TRUE; @@ -708,17 +701,13 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * else { // Iterate output arcs of given relation - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - param_elem, - sc_type_const, - sc_type_const, - sc_type_arc_pos_const_perm, - param_rel); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, param_elem, sc_type_const, sc_type_const, sc_type_arc_pos_const_perm, param_rel); while (sc_iterator5_next(it5) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; found = SC_TRUE; @@ -733,17 +722,13 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * sc_iterator5_free(it5); // Iterate input arcs of given relation - it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_const, - sc_type_const, - param_elem, - sc_type_arc_pos_const_perm, - param_rel); + it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, sc_type_const, sc_type_const, param_elem, sc_type_arc_pos_const_perm, param_rel); while (sc_iterator5_next(it5) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)))) continue; found = SC_TRUE; @@ -758,21 +743,15 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * sc_iterator5_free(it5); // Iterate input arcs for input element - it1 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_const, - sc_type_arc_pos_const_perm, - param_elem); + it1 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_const, sc_type_arc_pos_const_perm, param_elem); while (sc_iterator3_next(it1) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 1)))) continue; // Iterate input arcs for input element - it2 = sc_iterator3_f_a_f_new(s_default_ctx, - param_rel, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it1, 0)); + it2 = sc_iterator3_f_a_f_new(s_default_ctx, param_rel, sc_type_arc_pos_const_perm, sc_iterator3_value(it1, 0)); if (sc_iterator3_next(it2) == SC_TRUE) { if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)))) @@ -784,14 +763,12 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * appendIntoAnswer(answer, sc_iterator3_value(it1, 0)); // Iterate elements of found link of given relation - it3 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator3_value(it1, 0), - sc_type_arc_pos_const_perm, - sc_type_const); + it3 = sc_iterator3_f_a_a_new( + s_default_ctx, sc_iterator3_value(it1, 0), sc_type_arc_pos_const_perm, sc_type_const); while (sc_iterator3_next(it3) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 2)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 1)); @@ -801,14 +778,12 @@ sc_result agent_search_links_of_relation_connected_with_element(const sc_event * search_arc_components(sc_iterator3_value(it3, 2), answer, sys_off); // Iterate role relations - it4 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_const | sc_type_node, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it3, 1)); + it4 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_const | sc_type_node, sc_type_arc_pos_const_perm, sc_iterator3_value(it3, 1)); while (sc_iterator3_next(it4) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it4, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it4, 0)); diff --git a/sc-kpm/sc-search/agents/search_semantic_neighborhood.h b/sc-kpm/sc-search/agents/search_semantic_neighborhood.h index 95ef061ab6..508b94474e 100644 --- a/sc-kpm/sc-search/agents/search_semantic_neighborhood.h +++ b/sc-kpm/sc-search/agents/search_semantic_neighborhood.h @@ -12,11 +12,11 @@ /*! * Function that implements sc-agent to search full semantic neighborhood of specified sc-element */ -sc_result agent_search_full_semantic_neighborhood(const sc_event *event, sc_addr arg); +sc_result agent_search_full_semantic_neighborhood(const sc_event * event, sc_addr arg); /*! * Function that implements sc-agent to search all link of given relation, which are connected with given element */ -sc_result agent_search_links_of_relation_connected_with_element(const sc_event *event, sc_addr arg); +sc_result agent_search_links_of_relation_connected_with_element(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/sc-search/agents/search_structure.c b/sc-kpm/sc-search/agents/search_structure.c index ed250d962b..91d04e215e 100644 --- a/sc-kpm/sc-search/agents/search_structure.c +++ b/sc-kpm/sc-search/agents/search_structure.c @@ -13,7 +13,7 @@ #include "sc-core/sc_helper.h" #include "sc-core/sc_memory_headers.h" -sc_result agent_search_decomposition(const sc_event *event, sc_addr arg) +sc_result agent_search_decomposition(const sc_event * event, sc_addr arg) { sc_addr question, answer; sc_iterator3 *it1, *it2, *it3; @@ -25,16 +25,14 @@ sc_result agent_search_decomposition(const sc_event *event, sc_addr arg) return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_decomposition, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc(s_default_ctx, keynode_question_decomposition, question, sc_type_arc_pos_const_perm) == + SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) @@ -43,20 +41,22 @@ sc_result agent_search_decomposition(const sc_event *event, sc_addr arg) appendIntoAnswer(answer, sc_iterator3_value(it1, 2)); // iterate decomposition - it5 = sc_iterator5_a_a_f_a_a_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - sc_iterator3_value(it1, 2), - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_a_a_f_a_a_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + sc_iterator3_value(it1, 2), + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_decomposition_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_decomposition_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 0)); @@ -65,57 +65,58 @@ sc_result agent_search_decomposition(const sc_event *event, sc_addr arg) appendIntoAnswer(answer, sc_iterator5_value(it5, 4)); // iterate decomposition set elements - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; // iterate order relations between elements - it_order = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it2, 2), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it_order = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it2, 2), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it_order) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, sc_iterator5_value(it5, 0), sc_iterator5_value(it_order, 2), sc_type_arc_pos_const_perm)) + if (SC_FALSE == sc_helper_check_arc( + s_default_ctx, + sc_iterator5_value(it5, 0), + sc_iterator5_value(it_order, 2), + sc_type_arc_pos_const_perm)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) + if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it_order, 1)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 2)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 3)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 4)); - } sc_iterator5_free(it_order); // iterate roles of element in link - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it3 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it3) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it3, 0), &el_type); if (!(el_type & sc_type_node_role)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it3, 0)); @@ -138,7 +139,6 @@ sc_result agent_search_decomposition(const sc_event *event, sc_addr arg) return SC_RESULT_OK; } - void search_subclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) { sc_iterator3 *it2, *it6; @@ -146,20 +146,22 @@ void search_subclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_type el_type; // iterate taxonomy - it5 = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - elem, - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + elem, + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) continue; - if (SC_TRUE == sys_off && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) + if (SC_TRUE == sys_off && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 1)); @@ -172,21 +174,23 @@ void search_subclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_iterator5_free(it5); // iterate decomposition - it5 = sc_iterator5_a_a_f_a_a_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - elem, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_a_a_f_a_a_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + elem, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_decomposition_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_decomposition_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 0)); @@ -195,57 +199,55 @@ void search_subclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) appendIntoAnswer(answer, sc_iterator5_value(it5, 4)); // iterate decomposition set elements - it2 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + it2 = sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it2) == SC_TRUE) { - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 1)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it2, 2)))) continue; // iterate order relations between elements - it_order = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it2, 2), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it_order = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it2, 2), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it_order) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_order_relation, sc_iterator5_value(it_order, 4), sc_type_arc_pos_const_perm)) continue; - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, sc_iterator5_value(it5, 0), sc_iterator5_value(it_order, 2), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, sc_iterator5_value(it5, 0), sc_iterator5_value(it_order, 2), sc_type_arc_pos_const_perm)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it_order, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it_order, 1)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 2)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 3)); appendIntoAnswer(answer, sc_iterator5_value(it_order, 4)); - } sc_iterator5_free(it_order); // iterate roles of element in link - it6 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_iterator3_value(it2, 1)); + it6 = sc_iterator3_a_a_f_new( + s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, sc_iterator3_value(it2, 1)); while (sc_iterator3_next(it6) == SC_TRUE) { sc_memory_get_element_type(s_default_ctx, sc_iterator3_value(it6, 0), &el_type); if (!(el_type & sc_type_node_role)) continue; - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it6, 1)))) continue; appendIntoAnswer(answer, sc_iterator3_value(it6, 0)); @@ -263,26 +265,27 @@ void search_subclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_iterator5_free(it5); } -sc_result agent_search_all_subclasses_in_quasybinary_relation(const sc_event *event, sc_addr arg) +sc_result agent_search_all_subclasses_in_quasybinary_relation(const sc_event * event, sc_addr arg) { sc_addr question, answer; - sc_iterator3 *it1; + sc_iterator3 * it1; sc_bool sys_off = SC_TRUE; if (!sc_memory_get_arc_end(s_default_ctx, arg, &question)) return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_search_all_subclasses_in_quasybinary_relation, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, + keynode_question_search_all_subclasses_in_quasybinary_relation, + question, + sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) @@ -302,24 +305,26 @@ sc_result agent_search_all_subclasses_in_quasybinary_relation(const sc_event *ev void search_superclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) { - sc_iterator3 *it3; - sc_iterator5 *it5; + sc_iterator3 * it3; + sc_iterator5 * it5; // search taxonomy - it5 = sc_iterator5_a_a_f_a_a_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - elem, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_a_a_f_a_a_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + elem, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { - if (SC_FALSE == sc_helper_check_arc(s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) + if (SC_FALSE == + sc_helper_check_arc( + s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm)) continue; - if (SC_TRUE == sys_off && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) + if (SC_TRUE == sys_off && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 0)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)))) continue; appendIntoAnswer(answer, sc_iterator5_value(it5, 0)); @@ -332,38 +337,40 @@ void search_superclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) sc_iterator5_free(it5); // iterate input arcs - it3 = sc_iterator3_a_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - elem); + it3 = sc_iterator3_a_a_f_new(s_default_ctx, sc_type_node | sc_type_const, sc_type_arc_pos_const_perm, elem); while (sc_iterator3_next(it3) == SC_TRUE) { // search all parents in quasybinary relation - it5 = sc_iterator5_f_a_a_a_a_new(s_default_ctx, - sc_iterator3_value(it3, 0), - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it5 = sc_iterator5_f_a_a_a_a_new( + s_default_ctx, + sc_iterator3_value(it3, 0), + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const); while (sc_iterator5_next(it5) == SC_TRUE) { // check if it's a quasybinary relation - if (sc_helper_check_arc(s_default_ctx, keynode_quasybinary_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == SC_TRUE) + if (sc_helper_check_arc( + s_default_ctx, keynode_quasybinary_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == + SC_TRUE) { - if (!(sc_helper_check_arc(s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == SC_TRUE - || sc_helper_check_arc(s_default_ctx, keynode_decomposition_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == SC_TRUE)) + if (!(sc_helper_check_arc( + s_default_ctx, keynode_taxonomy_relation, sc_iterator5_value(it5, 4), sc_type_arc_pos_const_perm) == + SC_TRUE || + sc_helper_check_arc( + s_default_ctx, + keynode_decomposition_relation, + sc_iterator5_value(it5, 4), + sc_type_arc_pos_const_perm) == SC_TRUE)) continue; - - if (sys_off == SC_TRUE && (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) - || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) - || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) + if (sys_off == SC_TRUE && + (IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 1)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 2)) || + IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 3)) || IS_SYSTEM_ELEMENT(sc_iterator5_value(it5, 4)) || + IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 0)) || IS_SYSTEM_ELEMENT(sc_iterator3_value(it3, 1)))) continue; - appendIntoAnswer(answer, sc_iterator5_value(it5, 1)); appendIntoAnswer(answer, sc_iterator5_value(it5, 2)); appendIntoAnswer(answer, sc_iterator5_value(it5, 3)); @@ -376,31 +383,31 @@ void search_superclasses_rec(sc_addr elem, sc_addr answer, sc_bool sys_off) } } sc_iterator5_free(it5); - } sc_iterator3_free(it3); } -sc_result agent_search_all_superclasses_in_quasybinary_relation(const sc_event *event, sc_addr arg) +sc_result agent_search_all_superclasses_in_quasybinary_relation(const sc_event * event, sc_addr arg) { sc_addr question, answer; - sc_iterator3 *it1; + sc_iterator3 * it1; sc_bool sys_off = SC_TRUE; if (!sc_memory_get_arc_end(s_default_ctx, arg, &question)) return SC_RESULT_ERROR_INVALID_PARAMS; // check question type - if (sc_helper_check_arc(s_default_ctx, keynode_question_search_all_superclasses_in_quasybinary_relation, question, sc_type_arc_pos_const_perm) == SC_FALSE) + if (sc_helper_check_arc( + s_default_ctx, + keynode_question_search_all_superclasses_in_quasybinary_relation, + question, + sc_type_arc_pos_const_perm) == SC_FALSE) return SC_RESULT_ERROR_INVALID_TYPE; answer = create_answer_node(); // get operation argument - it1 = sc_iterator3_f_a_a_new(s_default_ctx, - question, - sc_type_arc_pos_const_perm, - 0); + it1 = sc_iterator3_f_a_a_new(s_default_ctx, question, sc_type_arc_pos_const_perm, 0); if (sc_iterator3_next(it1) == SC_TRUE) { if (IS_SYSTEM_ELEMENT(sc_iterator3_value(it1, 2))) diff --git a/sc-kpm/sc-search/agents/search_structure.h b/sc-kpm/sc-search/agents/search_structure.h index 75f4d36daa..8cb15b2742 100644 --- a/sc-kpm/sc-search/agents/search_structure.h +++ b/sc-kpm/sc-search/agents/search_structure.h @@ -12,16 +12,16 @@ /*! * Function, that implements sc-agent to search decomposition of specified sc-element */ -sc_result agent_search_decomposition(const sc_event *event, sc_addr arg); +sc_result agent_search_decomposition(const sc_event * event, sc_addr arg); /*! * Function, that implements sc-agent to search all subclasses of specified sc-element in all quasybinary relations */ -sc_result agent_search_all_subclasses_in_quasybinary_relation(const sc_event *event, sc_addr arg); +sc_result agent_search_all_subclasses_in_quasybinary_relation(const sc_event * event, sc_addr arg); /*! * Function, that implements sc-agent to search all superclasses of specified sc-element in all quasybinary relations */ -sc_result agent_search_all_superclasses_in_quasybinary_relation(const sc_event *event, sc_addr arg); +sc_result agent_search_all_superclasses_in_quasybinary_relation(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/sc-search/search.c b/sc-kpm/sc-search/search.c index 676e82f123..5252719637 100644 --- a/sc-kpm/sc-search/search.c +++ b/sc-kpm/sc-search/search.c @@ -11,21 +11,19 @@ #include "sc-core/sc_helper.h" #include "sc-core/sc_memory_headers.h" - sc_memory_context * s_default_ctx = 0; - -sc_event *event_question_search_all_output_arcs; -sc_event *event_question_search_all_input_arcs; -sc_event *event_question_search_all_output_arcs_with_rel; -sc_event *event_question_search_all_input_arcs_with_rel; -sc_event *event_question_search_full_semantic_neighborhood; -sc_event *event_question_search_all_subclasses_in_quasybinary_relation; -sc_event *event_question_search_all_superclasses_in_quasybinary_relation; -sc_event *event_question_search_decomposition; -sc_event *event_question_search_all_identifiers; -sc_event *event_question_search_all_identified_elements; -sc_event *event_question_search_links_of_relation_connected_with_element; +sc_event * event_question_search_all_output_arcs; +sc_event * event_question_search_all_input_arcs; +sc_event * event_question_search_all_output_arcs_with_rel; +sc_event * event_question_search_all_input_arcs_with_rel; +sc_event * event_question_search_full_semantic_neighborhood; +sc_event * event_question_search_all_subclasses_in_quasybinary_relation; +sc_event * event_question_search_all_superclasses_in_quasybinary_relation; +sc_event * event_question_search_decomposition; +sc_event * event_question_search_all_identifiers; +sc_event * event_question_search_all_identified_elements; +sc_event * event_question_search_links_of_relation_connected_with_element; // --------------------- Module ------------------------ @@ -36,47 +34,88 @@ _SC_EXT_EXTERN sc_result sc_module_initialize() if (search_keynodes_initialize() != SC_RESULT_OK) return SC_RESULT_ERROR; - event_question_search_all_output_arcs = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_output_arc, 0); + event_question_search_all_output_arcs = sc_event_new( + s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_output_arc, 0); if (event_question_search_all_output_arcs == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_input_arcs = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_input_arc, 0); + event_question_search_all_input_arcs = sc_event_new( + s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_input_arc, 0); if (event_question_search_all_input_arcs == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_output_arcs_with_rel = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_output_arc_with_rel, 0); + event_question_search_all_output_arcs_with_rel = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_all_const_pos_output_arc_with_rel, + 0); if (event_question_search_all_input_arcs == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_input_arcs_with_rel = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_const_pos_input_arc_with_rel, 0); + event_question_search_all_input_arcs_with_rel = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_all_const_pos_input_arc_with_rel, + 0); if (event_question_search_all_input_arcs == null_ptr) return SC_RESULT_ERROR; - event_question_search_full_semantic_neighborhood = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_full_semantic_neighborhood, 0); + event_question_search_full_semantic_neighborhood = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_full_semantic_neighborhood, + 0); if (event_question_search_full_semantic_neighborhood == null_ptr) return SC_RESULT_ERROR; - event_question_search_decomposition = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_decomposition, 0); + event_question_search_decomposition = sc_event_new( + s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_decomposition, 0); if (event_question_search_decomposition == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_identifiers = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_identifiers, 0); + event_question_search_all_identifiers = sc_event_new( + s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_identifiers, 0); if (event_question_search_all_identifiers == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_identified_elements = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_identified_elements, 0); + event_question_search_all_identified_elements = sc_event_new( + s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_identified_elements, 0); if (event_question_search_all_identified_elements == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_subclasses_in_quasybinary_relation = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_subclasses_in_quasybinary_relation, 0); + event_question_search_all_subclasses_in_quasybinary_relation = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_all_subclasses_in_quasybinary_relation, + 0); if (event_question_search_all_subclasses_in_quasybinary_relation == null_ptr) return SC_RESULT_ERROR; - event_question_search_all_superclasses_in_quasybinary_relation = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_all_superclasses_in_quasybinary_relation, 0); + event_question_search_all_superclasses_in_quasybinary_relation = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_all_superclasses_in_quasybinary_relation, + 0); if (event_question_search_all_superclasses_in_quasybinary_relation == null_ptr) return SC_RESULT_ERROR; - event_question_search_links_of_relation_connected_with_element = sc_event_new(s_default_ctx, keynode_question_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_search_links_of_relation_connected_with_element, 0); + event_question_search_links_of_relation_connected_with_element = sc_event_new( + s_default_ctx, + keynode_question_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + agent_search_links_of_relation_connected_with_element, + 0); if (event_question_search_links_of_relation_connected_with_element == null_ptr) return SC_RESULT_ERROR; diff --git a/sc-kpm/sc-search/search_defines.h b/sc-kpm/sc-search/search_defines.h index 4dfabdea90..e48bda4c97 100644 --- a/sc-kpm/sc-search/search_defines.h +++ b/sc-kpm/sc-search/search_defines.h @@ -7,10 +7,11 @@ #ifndef _search_defines_h_ #define _search_defines_h_ +#define SYSTEM_ELEMENT(el) \ + if (sc_helper_check_arc(s_default_ctx, keynode_system_element, el, sc_type_arc_pos_const_perm) == SC_FALSE) \ + sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_system_element, el); -#define SYSTEM_ELEMENT(el) if (sc_helper_check_arc(s_default_ctx, keynode_system_element,el, sc_type_arc_pos_const_perm) == SC_FALSE)\ - sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_system_element, el); +#define IS_SYSTEM_ELEMENT(el) \ + (sc_helper_check_arc(s_default_ctx, keynode_system_element, el, sc_type_arc_pos_const_perm) == SC_TRUE) -#define IS_SYSTEM_ELEMENT(el) (sc_helper_check_arc(s_default_ctx, keynode_system_element, el, sc_type_arc_pos_const_perm) == SC_TRUE) - -#endif // SEARCH_DEFINES_H +#endif // SEARCH_DEFINES_H diff --git a/sc-kpm/sc-search/search_keynodes.c b/sc-kpm/sc-search/search_keynodes.c index 8856528efa..d9d8eece6c 100644 --- a/sc-kpm/sc-search/search_keynodes.c +++ b/sc-kpm/sc-search/search_keynodes.c @@ -15,7 +15,6 @@ #include - sc_addr keynode_question_all_output_const_pos_arc; sc_addr keynode_question_all_input_const_pos_arc; sc_addr keynode_question_all_output_const_pos_arc_with_rel; @@ -58,17 +57,22 @@ sc_addr keynode_rrel_2; const char keynode_question_all_output_const_pos_arc_str[] = "question_search_all_output_const_pos_arcs"; const char keynode_question_all_input_const_pos_arc_str[] = "question_search_all_input_const_pos_arcs"; -const char keynode_question_all_output_const_pos_arc_with_rel_str[] = "question_search_all_output_const_pos_arcs_with_rel"; -const char keynode_question_all_input_const_pos_arc_with_rel_str[] = "question_search_all_input_const_pos_arcs_with_rel"; +const char keynode_question_all_output_const_pos_arc_with_rel_str[] = + "question_search_all_output_const_pos_arcs_with_rel"; +const char keynode_question_all_input_const_pos_arc_with_rel_str[] = + "question_search_all_input_const_pos_arcs_with_rel"; const char keynode_question_full_semantic_neighborhood_str[] = "question_search_full_semantic_neighborhood"; const char keynode_question_decomposition_str[] = "question_search_decomposition"; const char keynode_question_all_identifiers_str[] = "question_search_all_identifiers"; const char keynode_question_all_identified_elements_str[] = "question_search_all_identified_elements"; const char keynode_question_search_full_pattern_str[] = "question_full_pattern_search"; -const char keynode_question_search_all_subclasses_in_quasybinary_relation_str[] = "question_search_all_subclasses_in_quasybinary_relation"; -const char keynode_question_search_all_superclasses_in_quasybinary_relation_str[] = "question_search_all_superclasses_in_quasybinary_relation"; -const char keynode_question_search_links_of_relation_connected_with_element_str[] = "question_search_links_of_relation_connected_with_element"; +const char keynode_question_search_all_subclasses_in_quasybinary_relation_str[] = + "question_search_all_subclasses_in_quasybinary_relation"; +const char keynode_question_search_all_superclasses_in_quasybinary_relation_str[] = + "question_search_all_superclasses_in_quasybinary_relation"; +const char keynode_question_search_links_of_relation_connected_with_element_str[] = + "question_search_links_of_relation_connected_with_element"; const char keynode_question_initiated_str[] = "question_initiated"; const char keynode_question_str[] = "question"; @@ -97,7 +101,6 @@ const char keynode_languages_str[] = "languages"; sc_result search_keynodes_initialize() { - RESOLVE_KEYNODE(s_default_ctx, keynode_question_all_output_const_pos_arc); RESOLVE_KEYNODE(s_default_ctx, keynode_question_all_input_const_pos_arc); RESOLVE_KEYNODE(s_default_ctx, keynode_question_all_output_const_pos_arc_with_rel); diff --git a/sc-kpm/sc-search/search_utils.c b/sc-kpm/sc-search/search_utils.c index fa989dda71..5f868259e9 100644 --- a/sc-kpm/sc-search/search_utils.c +++ b/sc-kpm/sc-search/search_utils.c @@ -41,7 +41,7 @@ void appendIntoAnswer(sc_addr answer, sc_addr el) void finish_question(sc_addr question) { - sc_iterator3 *it = null_ptr; + sc_iterator3 * it = null_ptr; sc_addr arc; arc = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_question_finished, question); diff --git a/sc-kpm/sc-search/search_utils.h b/sc-kpm/sc-search/search_utils.h index 0576b5c2b6..cbea2c682f 100644 --- a/sc-kpm/sc-search/search_utils.h +++ b/sc-kpm/sc-search/search_utils.h @@ -7,7 +7,7 @@ #include "sc-core/sc_memory.h" #ifndef _search_functions_h_ -#define _search_functions_h_ +# define _search_functions_h_ /*! Creates new answer node. It automaticaly appends into system elements set * @returns Returns sc-addr of created node diff --git a/sc-kpm/sc-ui/CMakeLists.txt b/sc-kpm/sc-ui/CMakeLists.txt index 6231ca0b0a..312d7f52a3 100644 --- a/sc-kpm/sc-ui/CMakeLists.txt +++ b/sc-kpm/sc-ui/CMakeLists.txt @@ -9,3 +9,7 @@ target_include_directories(sc-ui ) add_dependencies(sc-ui sc-core sc-kpm-common) target_link_libraries(sc-ui sc-kpm-common) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-ui) +endif () diff --git a/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.cpp b/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.cpp index 51234314af..e7bdebec7c 100644 --- a/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.cpp +++ b/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.cpp @@ -17,7 +17,6 @@ uiSc2SCgJsonTranslator::uiSc2SCgJsonTranslator() uiSc2SCgJsonTranslator::~uiSc2SCgJsonTranslator() { - } void uiSc2SCgJsonTranslator::runImpl() @@ -29,7 +28,7 @@ void uiSc2SCgJsonTranslator::runImpl() mOutputData = "["; - sc_iterator3 *it = sc_iterator3_f_a_a_new(s_default_ctx, mInputConstructionAddr, sc_type_arc_pos_const_perm, 0); + sc_iterator3 * it = sc_iterator3_f_a_a_new(s_default_ctx, mInputConstructionAddr, sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it) == SC_TRUE) { el_type = 0; @@ -54,10 +53,10 @@ void uiSc2SCgJsonTranslator::runImpl() sc_addr beg_addr; if (sc_memory_get_arc_begin(s_default_ctx, addr, &beg_addr) != SC_RESULT_OK) - continue; //! TODO error logging + continue; //! TODO error logging sc_addr end_addr; if (sc_memory_get_arc_end(s_default_ctx, addr, &end_addr) != SC_RESULT_OK) - continue; //! TODO error logging + continue; //! TODO error logging attrs["begin"] = buildId(beg_addr); attrs["end"] = buildId(end_addr); @@ -90,7 +89,7 @@ void uiSc2SCgJsonTranslator::runImpl() } // ------------------------------------------------------------------------------ -sc_result uiSc2SCgJsonTranslator::ui_translate_sc2scg_json(const sc_event *event, sc_addr arg) +sc_result uiSc2SCgJsonTranslator::ui_translate_sc2scg_json(const sc_event * event, sc_addr arg) { sc_addr cmd_addr, input_addr, format_addr; diff --git a/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.h b/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.h index 623db32f33..fdc3926fa6 100644 --- a/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.h +++ b/sc-kpm/sc-ui/translators/uiSc2SCgJsonTranslator.h @@ -19,15 +19,13 @@ class uiSc2SCgJsonTranslator : public uiTranslateFromSc explicit uiSc2SCgJsonTranslator(); virtual ~uiSc2SCgJsonTranslator(); - - static sc_result ui_translate_sc2scg_json(const sc_event *event, sc_addr arg); + static sc_result ui_translate_sc2scg_json(const sc_event * event, sc_addr arg); protected: //! @copydoc uiTranslateFromSc::runImpl void runImpl(); private: - }; -#endif // _ui_Sc2SCgJsonTranslator_h_ +#endif // _ui_Sc2SCgJsonTranslator_h_ diff --git a/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.cpp b/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.cpp index e11b2e2351..ae61d61299 100644 --- a/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.cpp +++ b/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.cpp @@ -11,7 +11,7 @@ #include "uiKeynodes.h" #include "uiUtils.h" -uiSCnSentenceNode::uiSCnSentenceNode(sScElementInfo *keywordEl) +uiSCnSentenceNode::uiSCnSentenceNode(sScElementInfo * keywordEl) : mParent(0) , mType(ST_KEYWORD) , mElementInfo(keywordEl) @@ -28,7 +28,6 @@ uiSCnSentenceNode::uiSCnSentenceNode() , mType(ST_NODE) , mElementInfo(0) { - } void uiSCnSentenceNode::buildTree() @@ -54,10 +53,10 @@ void uiSCnSentenceNode::buildTree() if (mType == ST_PREDICATE) { - sScElementInfo *el = (mParent->mElementInfo == mElementInfo->target) ? mElementInfo->source : mElementInfo->target; + sScElementInfo * el = (mParent->mElementInfo == mElementInfo->target) ? mElementInfo->source : mElementInfo->target; assert(el); - uiSCnSentenceNode *child = new uiSCnSentenceNode(); + uiSCnSentenceNode * child = new uiSCnSentenceNode(); child->mType = ST_NODE; child->mElementInfo = el; _appendChildNode(child); @@ -71,12 +70,10 @@ void uiSCnSentenceNode::buildTree() void uiSCnSentenceNode::balance() { - } -const String& uiSCnSentenceNode::json() +const String & uiSCnSentenceNode::json() { - StringStream ss; ss << "{"; @@ -90,7 +87,8 @@ const String& uiSCnSentenceNode::json() { assert(mChildSentences.size() == 1); ss << ", \"SCNode\" : " << (*mChildSentences.begin())->json(); - } else + } + else { ss << ", \"SCArcs\": ["; @@ -98,7 +96,7 @@ const String& uiSCnSentenceNode::json() tSentenceNodeList::iterator it, itEnd = mChildSentences.end(); for (it = mChildSentences.begin(); it != itEnd; ++it) { - uiSCnSentenceNode *sentence = *it; + uiSCnSentenceNode * sentence = *it; assert(sentence->mType == ST_PREDICATE); if (it != mChildSentences.begin()) @@ -115,9 +113,9 @@ const String& uiSCnSentenceNode::json() return mJSONData; } -uiSCnSentenceNode* uiSCnSentenceNode::createChildNode(uiSCnSentenceNode::eSentenceNodeType type) +uiSCnSentenceNode * uiSCnSentenceNode::createChildNode(uiSCnSentenceNode::eSentenceNodeType type) { - uiSCnSentenceNode *child = new uiSCnSentenceNode(); + uiSCnSentenceNode * child = new uiSCnSentenceNode(); child->mType = type; _appendChildNode(child); return child; @@ -132,7 +130,7 @@ void uiSCnSentenceNode::destroyChilds() delete *it; } -void uiSCnSentenceNode::_removeChildNode(uiSCnSentenceNode *child) +void uiSCnSentenceNode::_removeChildNode(uiSCnSentenceNode * child) { assert(child->mParent == this); child->mParent = 0; @@ -147,7 +145,7 @@ void uiSCnSentenceNode::_removeChildNode(uiSCnSentenceNode *child) } } -void uiSCnSentenceNode::_appendChildNode(uiSCnSentenceNode *child) +void uiSCnSentenceNode::_appendChildNode(uiSCnSentenceNode * child) { assert(child->mParent != this); @@ -158,7 +156,7 @@ void uiSCnSentenceNode::_appendChildNode(uiSCnSentenceNode *child) mChildSentences.push_back(child); } -bool uiSCnSentenceNode::_hasChildNode(uiSCnSentenceNode *child) const +bool uiSCnSentenceNode::_hasChildNode(uiSCnSentenceNode * child) const { tSentenceNodeList::const_iterator it, itEnd = mChildSentences.end(); for (it = mChildSentences.begin(); it != itEnd; ++it) @@ -170,17 +168,14 @@ bool uiSCnSentenceNode::_hasChildNode(uiSCnSentenceNode *child) const return false; } -void uiSCnSentenceNode::_createChildPredicate(sScElementInfo *arc) +void uiSCnSentenceNode::_createChildPredicate(sScElementInfo * arc) { assert(arc->type & sc_type_arc_mask); - uiSCnSentenceNode *child = createChildNode(ST_PREDICATE); + uiSCnSentenceNode * child = createChildNode(ST_PREDICATE); child->mElementInfo = arc; } - - - // --------------------------------------------------------------------------------------------------- uiSc2SCnJsonTranslator::uiSc2SCnJsonTranslator() : mScElementsInfoPool(0) @@ -190,24 +185,23 @@ uiSc2SCnJsonTranslator::uiSc2SCnJsonTranslator() uiSc2SCnJsonTranslator::~uiSc2SCnJsonTranslator() { if (mScElementsInfoPool) - delete []mScElementsInfoPool; + delete[] mScElementsInfoPool; } void uiSc2SCnJsonTranslator::runImpl() { // get command arguments - sc_iterator5 *it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - mInputConstructionAddr, - sc_type_arc_pos_const_perm, - keynode_question_nrel_answer); + sc_iterator5 * it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + mInputConstructionAddr, + sc_type_arc_pos_const_perm, + keynode_question_nrel_answer); if (sc_iterator5_next(it5) == SC_TRUE) { - sc_iterator3 *it3 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + sc_iterator3 * it3 = + sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it3) == SC_TRUE) mKeywordsList.push_back(sc_iterator3_value(it3, 2)); sc_iterator3_free(it3); @@ -216,14 +210,12 @@ void uiSc2SCnJsonTranslator::runImpl() collectScElementsInfo(); - - mOutputData = "["; tScAddrList::iterator it, itEnd = mKeywordsList.end(); for (it = mKeywordsList.begin(); it != itEnd; ++it) { - uiSCnSentenceNode *sentence = new uiSCnSentenceNode(mScElementsInfo[*it]); + uiSCnSentenceNode * sentence = new uiSCnSentenceNode(mScElementsInfo[*it]); mRootSentences.push_back(sentence); } @@ -251,31 +243,25 @@ void uiSc2SCnJsonTranslator::runImpl() mRootSentences.clear(); mOutputData += "]"; - //qDebug() << "Result: " << QString().fromStdString(mOutputData); + // qDebug() << "Result: " << QString().fromStdString(mOutputData); } String uiSc2SCnJsonTranslator::translateElement(sc_addr addr, bool isKeyword) { - return ""; } bool uiSc2SCnJsonTranslator::isInOutputConstruction(sc_addr addr) const { - sc_iterator3 *it3 = sc_iterator3_f_a_f_new(s_default_ctx, - mInputConstructionAddr, - sc_type_arc_pos_const_perm, - addr); + sc_iterator3 * it3 = sc_iterator3_f_a_f_new(s_default_ctx, mInputConstructionAddr, sc_type_arc_pos_const_perm, addr); bool result = (sc_iterator3_next(it3) == SC_TRUE); sc_iterator3_free(it3); return result; } - - void uiSc2SCnJsonTranslator::collectScElementsInfo() { - sc_uint32 elementsCount =(sc_uint32) mObjects.size(); + sc_uint32 elementsCount = (sc_uint32)mObjects.size(); mScElementsInfoPool = new sScElementInfo[elementsCount]; sc_uint32 poolUsed = 0; @@ -300,7 +286,7 @@ void uiSc2SCnJsonTranslator::collectScElementsInfo() arcAddr = it->first; elType = it->second; - sScElementInfo *elInfo = mScElementsInfo[arcAddr]; + sScElementInfo * elInfo = mScElementsInfo[arcAddr]; elInfo->isInSentenceTree = false; elInfo->visualType = sScElementInfo::VT_NODE; @@ -310,16 +296,15 @@ void uiSc2SCnJsonTranslator::collectScElementsInfo() // get begin/end addrs if (sc_memory_get_arc_begin(s_default_ctx, arcAddr, &begAddr) != SC_RESULT_OK) - continue; // @todo process errors + continue; // @todo process errors if (sc_memory_get_arc_end(s_default_ctx, arcAddr, &endAddr) != SC_RESULT_OK) - continue; // @todo process errors - + continue; // @todo process errors elInfo->srcAddr = begAddr; elInfo->trgAddr = endAddr; - sScElementInfo *begInfo = mScElementsInfo[begAddr]; - sScElementInfo *endInfo = mScElementsInfo[endAddr]; + sScElementInfo * begInfo = mScElementsInfo[begAddr]; + sScElementInfo * endInfo = mScElementsInfo[endAddr]; elInfo->source = begInfo; elInfo->target = endInfo; @@ -335,7 +320,7 @@ void uiSc2SCnJsonTranslator::collectScElementsInfo() tScElemetsInfoMap::iterator itInfo, itInfoEnd = mScElementsInfo.begin(); for (itInfo = mScElementsInfo.begin(); itInfo != itInfoEnd; ++itInfo) { - sScElementInfo *el = itInfo->second; + sScElementInfo * el = itInfo->second; // possible sc-lement can be visualized as set if (el->type & sc_type_node_tuple) @@ -346,17 +331,14 @@ void uiSc2SCnJsonTranslator::collectScElementsInfo() // possible sc-element can be visualized as contour if (el->type & sc_type_node_struct) { - } - } // construct tree of sentences - } // ------------------------------------- -sc_result uiSc2SCnJsonTranslator::ui_translate_sc2scn(const sc_event *event, sc_addr arg) +sc_result uiSc2SCnJsonTranslator::ui_translate_sc2scn(const sc_event * event, sc_addr arg) { sc_addr cmd_addr, input_addr, format_addr; @@ -377,5 +359,3 @@ sc_result uiSc2SCnJsonTranslator::ui_translate_sc2scn(const sc_event *event, sc_ return SC_RESULT_OK; } - - diff --git a/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.h b/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.h index db9e43656f..dff5c17167 100644 --- a/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.h +++ b/sc-kpm/sc-ui/translators/uiSc2SCnJsonTranslator.h @@ -11,7 +11,7 @@ struct sScElementInfo { - typedef std::list tScElementInfoList; + typedef std::list tScElementInfoList; typedef enum { @@ -26,8 +26,8 @@ struct sScElementInfo sc_addr addr; sc_addr srcAddr; sc_addr trgAddr; - sScElementInfo* source; - sScElementInfo* target; + sScElementInfo * source; + sScElementInfo * target; tScElementInfoList outputArcs; tScElementInfoList inputArcs; @@ -45,10 +45,10 @@ class uiSCnSentenceNode } eSentenceNodeType; public: - typedef std::list tSentenceNodeList; + typedef std::list tSentenceNodeList; //! Create keyword sentence node - explicit uiSCnSentenceNode(sScElementInfo *keywordEl); + explicit uiSCnSentenceNode(sScElementInfo * keywordEl); virtual ~uiSCnSentenceNode(); //! Build tree based on keyword. This node must be a keyword @@ -56,32 +56,31 @@ class uiSCnSentenceNode //! Balance tree void balance(); //! Generates json for specified tree - const String& json(); + const String & json(); //! Append new child tree node to this one - uiSCnSentenceNode* createChildNode(eSentenceNodeType type); + uiSCnSentenceNode * createChildNode(eSentenceNodeType type); protected: //! Destroy tree recursively void destroyChilds(); //! Removes node from childs list - void _removeChildNode(uiSCnSentenceNode *child); + void _removeChildNode(uiSCnSentenceNode * child); //! Appends new node to childs list - void _appendChildNode(uiSCnSentenceNode *child); + void _appendChildNode(uiSCnSentenceNode * child); //! Check if specified tree node exists in child list of this one - bool _hasChildNode(uiSCnSentenceNode *child) const; - + bool _hasChildNode(uiSCnSentenceNode * child) const; private: explicit uiSCnSentenceNode(); //! Create child predicate node - void _createChildPredicate(sScElementInfo *arc); + void _createChildPredicate(sScElementInfo * arc); private: //! Pointer to parent sentence tree node - uiSCnSentenceNode *mParent; + uiSCnSentenceNode * mParent; //! Type of sentence tree node eSentenceNodeType mType; //! List of conotur article root nodes @@ -91,12 +90,11 @@ class uiSCnSentenceNode //! List of child sentences tSentenceNodeList mChildSentences; //! Pointer to sc-element info - sScElementInfo *mElementInfo; + sScElementInfo * mElementInfo; //! String that contains cache of generated json for tree String mJSONData; }; - /*! * \brief Class that translates sc-construction into * SCn-code (json representation) @@ -107,18 +105,17 @@ class uiSc2SCnJsonTranslator : public uiTranslateFromSc explicit uiSc2SCnJsonTranslator(); virtual ~uiSc2SCnJsonTranslator(); - - static sc_result ui_translate_sc2scn(const sc_event *event, sc_addr arg); + static sc_result ui_translate_sc2scn(const sc_event * event, sc_addr arg); protected: //! @copydoc uiTranslateFromSc::runImpl void runImpl(); /*! Translate one sc-element semantic neighborhood - * @param addr sc-addr of sc-element to translate - * @param isKeyword Keyword flag - * @return Returns string that json representaion of sc-element - */ + * @param addr sc-addr of sc-element to translate + * @param isKeyword Keyword flag + * @return Returns string that json representaion of sc-element + */ String translateElement(sc_addr addr, bool isKeyword); //! Check if specified sc-element included in output construction @@ -131,14 +128,12 @@ class uiSc2SCnJsonTranslator : public uiTranslateFromSc //! List of keywords tScAddrList mKeywordsList; //! Collection of objects information - typedef std::map tScElemetsInfoMap; + typedef std::map tScElemetsInfoMap; tScElemetsInfoMap mScElementsInfo; //! Pull of sc-elements information (used to prevent many memory allocations) - sScElementInfo *mScElementsInfoPool; + sScElementInfo * mScElementsInfoPool; //! List of articles root elements uiSCnSentenceNode::tSentenceNodeList mRootSentences; }; - - -#endif // _uiSc2SCnJsonTranslator_h_ +#endif // _uiSc2SCnJsonTranslator_h_ diff --git a/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.cpp b/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.cpp index 51ae6f00c8..1faea73546 100644 --- a/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.cpp +++ b/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.cpp @@ -18,7 +18,6 @@ uiSc2ScsTranslator::uiSc2ScsTranslator() uiSc2ScsTranslator::~uiSc2ScsTranslator() { - } void uiSc2ScsTranslator::runImpl() @@ -29,18 +28,17 @@ void uiSc2ScsTranslator::runImpl() bool first = true; // get command arguments (keywords) - sc_iterator5 *it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - mInputConstructionAddr, - sc_type_arc_pos_const_perm, - keynode_question_nrel_answer); + sc_iterator5 * it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + mInputConstructionAddr, + sc_type_arc_pos_const_perm, + keynode_question_nrel_answer); if (sc_iterator5_next(it5) == SC_TRUE) { - sc_iterator3 *it3 = sc_iterator3_f_a_a_new(s_default_ctx, - sc_iterator5_value(it5, 0), - sc_type_arc_pos_const_perm, - 0); + sc_iterator3 * it3 = + sc_iterator3_f_a_a_new(s_default_ctx, sc_iterator5_value(it5, 0), sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it3) == SC_TRUE) { sc_addr addr = sc_iterator3_value(it3, 2); @@ -69,7 +67,7 @@ void uiSc2ScsTranslator::runImpl() tScAddrToScTypeMap::iterator it, itEnd = mObjects.end(); for (it = mObjects.begin(); it != itEnd; ++it) { - const sc_addr &arc_addr = it->first; + const sc_addr & arc_addr = it->first; sc_type arc_type = it->second; // skip non arc objects @@ -79,16 +77,16 @@ void uiSc2ScsTranslator::runImpl() sc_addr arc_beg, arc_end; // get begin and end arc elements if (sc_memory_get_arc_begin(s_default_ctx, arc_addr, &arc_beg) != SC_RESULT_OK) - continue; //! TODO logging + continue; //! TODO logging if (isNeedToTranslate(arc_beg) == false) - continue; //! TODO logging + continue; //! TODO logging if (sc_memory_get_arc_end(s_default_ctx, arc_addr, &arc_end) != SC_RESULT_OK) - continue; //! TODO logging + continue; //! TODO logging if (isNeedToTranslate(arc_end) == false) - continue; //! TODO logging + continue; //! TODO logging sc_type beg_type, end_type; tScAddrToScTypeMap::iterator itTmp = mObjects.find(arc_beg); @@ -110,14 +108,13 @@ void uiSc2ScsTranslator::runImpl() ss << "[{ \"addr\": \"" << buildId(arc_beg) << "\", \"type\": " << beg_type << "}, "; ss << "{ \"addr\": \"" << buildId(arc_addr) << "\", \"type\": " << arc_type << "}, "; ss << "{ \"addr\": \"" << buildId(arc_end) << "\", \"type\": " << end_type << "}]"; - } ss << "]}"; mOutputData = ss.str(); } -void uiSc2ScsTranslator::resolveSystemIdentifier(const sc_addr &addr, String &idtf) +void uiSc2ScsTranslator::resolveSystemIdentifier(const sc_addr & addr, String & idtf) { tSystemIdentifiersMap::iterator it = mSystemIdentifiers.find(addr); if (it != mSystemIdentifiers.end()) @@ -130,9 +127,8 @@ void uiSc2ScsTranslator::resolveSystemIdentifier(const sc_addr &addr, String &id mSystemIdentifiers[addr] = idtf; } - // ------------------------------------------------------- -sc_result uiSc2ScsTranslator::ui_translate_sc2scs(const sc_event *event, sc_addr arg) +sc_result uiSc2ScsTranslator::ui_translate_sc2scs(const sc_event * event, sc_addr arg) { sc_addr cmd_addr, input_addr, format_addr; diff --git a/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.h b/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.h index b4ec950361..8a699e3f8d 100644 --- a/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.h +++ b/sc-kpm/sc-ui/translators/uiSc2ScsJsonTranslator.h @@ -19,14 +19,14 @@ class uiSc2ScsTranslator : public uiTranslateFromSc explicit uiSc2ScsTranslator(); virtual ~uiSc2ScsTranslator(); - static sc_result ui_translate_sc2scs(const sc_event *event, sc_addr arg); + static sc_result ui_translate_sc2scs(const sc_event * event, sc_addr arg); protected: //! @copydoc uiTranslateFromSc::runImpl void runImpl(); //! Resolve system identifier for specified sc-addr - void resolveSystemIdentifier(const sc_addr &addr, String &idtf); + void resolveSystemIdentifier(const sc_addr & addr, String & idtf); protected: //! Map of resolved system identifiers diff --git a/sc-kpm/sc-ui/translators/uiTranslatorFromSc.cpp b/sc-kpm/sc-ui/translators/uiTranslatorFromSc.cpp index 04bb6fd7e1..9a9c32ee34 100644 --- a/sc-kpm/sc-ui/translators/uiTranslatorFromSc.cpp +++ b/sc-kpm/sc-ui/translators/uiTranslatorFromSc.cpp @@ -10,15 +10,13 @@ uiTranslateFromSc::uiTranslateFromSc() { - } uiTranslateFromSc::~uiTranslateFromSc() { - } -void uiTranslateFromSc::translate(const sc_addr &input_addr, const sc_addr &format_addr) +void uiTranslateFromSc::translate(const sc_addr & input_addr, const sc_addr & format_addr) { mInputConstructionAddr = input_addr; mOutputFormatAddr = format_addr; @@ -28,8 +26,9 @@ void uiTranslateFromSc::translate(const sc_addr &input_addr, const sc_addr &form runImpl(); // write into sc-link - sc_stream *result_data_stream = 0; - result_data_stream = sc_stream_memory_new(mOutputData.c_str(), (sc_uint)mOutputData.size(), SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * result_data_stream = 0; + result_data_stream = + sc_stream_memory_new(mOutputData.c_str(), (sc_uint)mOutputData.size(), SC_STREAM_FLAG_READ, SC_FALSE); sc_addr result_addr = sc_memory_link_new(s_default_ctx); sc_memory_set_link_content(s_default_ctx, result_addr, result_data_stream); @@ -47,7 +46,7 @@ void uiTranslateFromSc::translate(const sc_addr &input_addr, const sc_addr &form void uiTranslateFromSc::collectObjects() { - sc_iterator3 *it = sc_iterator3_f_a_a_new(s_default_ctx, mInputConstructionAddr, sc_type_arc_pos_const_perm, 0); + sc_iterator3 * it = sc_iterator3_f_a_a_new(s_default_ctx, mInputConstructionAddr, sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it) == SC_TRUE) { sc_type el_type = 0; @@ -58,17 +57,16 @@ void uiTranslateFromSc::collectObjects() continue; mObjects[addr] = el_type; - } sc_iterator3_free(it); } -bool uiTranslateFromSc::isNeedToTranslate(const sc_addr &addr) const +bool uiTranslateFromSc::isNeedToTranslate(const sc_addr & addr) const { return mObjects.find(addr) != mObjects.end(); } -String uiTranslateFromSc::buildId(const sc_addr &addr) +String uiTranslateFromSc::buildId(const sc_addr & addr) { uint32_t v = addr.seg | (addr.offset << 16); StringStream ss; diff --git a/sc-kpm/sc-ui/translators/uiTranslatorFromSc.h b/sc-kpm/sc-ui/translators/uiTranslatorFromSc.h index 8c52434d2b..b8e883b510 100644 --- a/sc-kpm/sc-ui/translators/uiTranslatorFromSc.h +++ b/sc-kpm/sc-ui/translators/uiTranslatorFromSc.h @@ -19,10 +19,10 @@ class uiTranslateFromSc virtual ~uiTranslateFromSc(); /*! Run translation. - * @param input_addr sc-addr of sc-construction, that need to be translated - * @param format_addr sc-addr of output format - */ - void translate(const sc_addr &input_addr, const sc_addr &format_addr); + * @param input_addr sc-addr of sc-construction, that need to be translated + * @param format_addr sc-addr of output format + */ + void translate(const sc_addr & input_addr, const sc_addr & format_addr); protected: //! Collect objects that need to be translated @@ -32,11 +32,11 @@ class uiTranslateFromSc virtual void runImpl() = 0; //! Check if sc-element need to be translated - bool isNeedToTranslate(const sc_addr &addr) const; + bool isNeedToTranslate(const sc_addr & addr) const; public: //! Build id from specified sc-addr - static String buildId(const sc_addr &addr); + static String buildId(const sc_addr & addr); protected: //! Sc-addr of input construction @@ -51,4 +51,4 @@ class uiTranslateFromSc String mOutputData; }; -#endif // _uiTranslator_h_ +#endif // _uiTranslator_h_ diff --git a/sc-kpm/sc-ui/ui.cpp b/sc-kpm/sc-ui/ui.cpp index 4ecde9d09f..fbe2d7e208 100644 --- a/sc-kpm/sc-ui/ui.cpp +++ b/sc-kpm/sc-ui/ui.cpp @@ -38,7 +38,6 @@ _SC_EXT_EXTERN sc_result sc_module_initialize() _SC_EXT_EXTERN sc_result sc_module_shutdown() { - ui_shutdown_translators(); ui_shutdown_commands(); diff --git a/sc-kpm/sc-ui/ui.h b/sc-kpm/sc-ui/ui.h index 6bbe2d8822..11234566c4 100644 --- a/sc-kpm/sc-ui/ui.h +++ b/sc-kpm/sc-ui/ui.h @@ -14,9 +14,9 @@ extern "C" extern "C" { -// --------------- Module ---------------- -_SC_EXT_EXTERN sc_result sc_module_initialize(); -_SC_EXT_EXTERN sc_result sc_module_shutdown(); + // --------------- Module ---------------- + _SC_EXT_EXTERN sc_result sc_module_initialize(); + _SC_EXT_EXTERN sc_result sc_module_shutdown(); } #endif diff --git a/sc-kpm/sc-ui/uiCommands.cpp b/sc-kpm/sc-ui/uiCommands.cpp index 64b61867e9..1f10e3478b 100644 --- a/sc-kpm/sc-ui/uiCommands.cpp +++ b/sc-kpm/sc-ui/uiCommands.cpp @@ -12,9 +12,9 @@ #include // -------------------- Events ---------------------- -sc_event *event_ui_start_answer_translation = 0; -sc_event *event_ui_command_generate_instance = 0; -sc_event *event_ui_remove_displayed_answer = 0; +sc_event * event_ui_start_answer_translation = 0; +sc_event * event_ui_command_generate_instance = 0; +sc_event * event_ui_remove_displayed_answer = 0; struct sTemplateArcInfo { @@ -29,31 +29,31 @@ struct sTemplateArcInfo , end_addr(_end) , self_type(_type) { - } }; -typedef std::list < sTemplateArcInfo > tTemplArcsList; -typedef std::list < sc_addr > tElementsList; +typedef std::list tTemplArcsList; +typedef std::list tElementsList; // -------------------- Event handlers -------------- -sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) +sc_result ui_command_generate_instance(const sc_event * event, sc_addr arg) { sc_addr command_addr; sc_addr args_addr; - sc_iterator5 *it5 = (sc_iterator5*)null_ptr; - sc_iterator3 *it3 = (sc_iterator3*)null_ptr; + sc_iterator5 * it5 = (sc_iterator5 *)null_ptr; + sc_iterator3 * it3 = (sc_iterator3 *)null_ptr; if (sc_memory_get_arc_end(s_default_ctx, arg, &command_addr) != SC_RESULT_OK) return SC_RESULT_ERROR; // first of all we need to find command arguments - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - command_addr, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_rrel_command_arguments); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + command_addr, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_rrel_command_arguments); if (sc_iterator5_next(it5) != SC_TRUE) { @@ -64,7 +64,6 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) args_addr = sc_iterator5_value(it5, 2); sc_iterator5_free(it5); - int idx = 0; bool found = true; tScAddrVector arguments; @@ -72,12 +71,13 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) { found = false; // iterate arguments and append them into vector - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - args_addr, - sc_type_arc_pos_const_perm, - 0, - sc_type_arc_pos_const_perm, - ui_keynode_rrel_order[idx]); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + args_addr, + sc_type_arc_pos_const_perm, + 0, + sc_type_arc_pos_const_perm, + ui_keynode_rrel_order[idx]); if (sc_iterator5_next(it5) == SC_TRUE) { @@ -89,12 +89,13 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) } // get command class - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - command_addr, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_rrel_command); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + command_addr, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_rrel_command); if (sc_iterator5_next(it5) != SC_TRUE) { @@ -107,12 +108,13 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) sc_iterator5_free(it5); // get command template - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - new_command_class_addr, - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_nrel_command_template); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + new_command_class_addr, + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_nrel_command_template); if (sc_iterator5_next(it5) != SC_TRUE) { @@ -132,10 +134,7 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) tElementsList created_nodes; tTemplArcsList templ_arcs; bool isValid = true; - it3 = sc_iterator3_f_a_a_new(s_default_ctx, - new_command_templ_addr, - sc_type_arc_pos_const_perm, - 0); + it3 = sc_iterator3_f_a_a_new(s_default_ctx, new_command_templ_addr, sc_type_arc_pos_const_perm, 0); while (sc_iterator3_next(it3) == SC_TRUE && isValid) { templ_item_addr = sc_iterator3_value(it3, 2); @@ -203,7 +202,8 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) // append to set of failed commands sc_memory_element_free(s_default_ctx, arg); - sc_addr arc_addr = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_command_failed, command_addr); + sc_addr arc_addr = + sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_command_failed, command_addr); SYSTEM_ELEMENT(arc_addr); return SC_RESULT_ERROR_INVALID_PARAMS; @@ -227,7 +227,6 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) arc_end_addr = (*it).end_addr; arc_type = (*it).self_type; - it_arc_beg = templ_to_inst.find(arc_beg_addr); it_arc_end = templ_to_inst.find(arc_end_addr); @@ -235,7 +234,8 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) if (it_arc_beg != templ_to_inst.end() && it_arc_end != templ_to_inst.end()) { created = true; - new_arc_addr = sc_memory_arc_new(s_default_ctx, (arc_type & ~sc_type_var) | sc_type_const, (*it_arc_beg).second, (*it_arc_end).second); + new_arc_addr = sc_memory_arc_new( + s_default_ctx, (arc_type & ~sc_type_var) | sc_type_const, (*it_arc_beg).second, (*it_arc_end).second); templ_to_inst[arc_addr] = new_arc_addr; it = templ_arcs.erase(it); @@ -272,7 +272,7 @@ sc_result ui_command_generate_instance(const sc_event *event, sc_addr arg) return SC_RESULT_OK; } -sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) +sc_result ui_start_answer_translation(sc_event * event, sc_addr arg) { sc_addr question_addr; sc_addr answer_addr; @@ -281,19 +281,19 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) sc_addr format_addr; sc_addr trans_command_addr; sc_addr arc_addr; - sc_iterator5 *it5 = (sc_iterator5*)null_ptr; - sc_iterator3 *it3 = (sc_iterator3*)null_ptr; - + sc_iterator5 * it5 = (sc_iterator5 *)null_ptr; + sc_iterator3 * it3 = (sc_iterator3 *)null_ptr; if (sc_memory_get_arc_end(s_default_ctx, arg, &question_addr) != SC_RESULT_OK) return SC_RESULT_ERROR; - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - question_addr, - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_question_nrel_answer); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + question_addr, + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_question_nrel_answer); if (sc_iterator5_next(it5) == SC_FALSE) { sc_iterator5_free(it5); @@ -303,12 +303,13 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) answer_addr = sc_iterator5_value(it5, 2); // find author of this question - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - question_addr, - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_nrel_authors); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + question_addr, + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_nrel_authors); if (it5 == null_ptr) return SC_RESULT_ERROR; @@ -321,12 +322,13 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) if (sc_helper_check_arc(s_default_ctx, keynode_user, author_addr, sc_type_arc_pos_const_perm) == SC_TRUE) { // get answer output formats - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - question_addr, - sc_type_arc_common | sc_type_const, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_nrel_user_answer_formats); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + question_addr, + sc_type_arc_common | sc_type_const, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_nrel_user_answer_formats); if (it5 == null_ptr) return SC_RESULT_ERROR; @@ -336,10 +338,8 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) sc_iterator5_free(it5); // list all output formats and initialize translation - it3 = sc_iterator3_f_a_a_new(s_default_ctx, - output_formats_addr, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const); + it3 = sc_iterator3_f_a_a_new( + s_default_ctx, output_formats_addr, sc_type_arc_pos_const_perm, sc_type_node | sc_type_const); if (it3 == null_ptr) return SC_RESULT_ERROR; @@ -353,7 +353,8 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) arc_addr = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, trans_command_addr, answer_addr); SYSTEM_ELEMENT(arc_addr); - arc_addr = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_rrel_source_sc_construction, arc_addr); + arc_addr = sc_memory_arc_new( + s_default_ctx, sc_type_arc_pos_const_perm, keynode_rrel_source_sc_construction, arc_addr); SYSTEM_ELEMENT(arc_addr); arc_addr = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, trans_command_addr, format_addr); @@ -362,80 +363,80 @@ sc_result ui_start_answer_translation(sc_event *event, sc_addr arg) SYSTEM_ELEMENT(arc_addr); // add into translation command set - arc_addr = sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_command_translate_from_sc, trans_command_addr); + arc_addr = sc_memory_arc_new( + s_default_ctx, sc_type_arc_pos_const_perm, keynode_command_translate_from_sc, trans_command_addr); SYSTEM_ELEMENT(arc_addr); } sc_iterator3_free(it3); - - }else + } + else sc_iterator5_free(it5); - } - }else + } + else sc_iterator5_free(it5); - // get answer node return SC_RESULT_OK; } -sc_result ui_remove_displayed_answer(sc_event *event, sc_addr arg) +sc_result ui_remove_displayed_answer(sc_event * event, sc_addr arg) { sc_addr answer_addr; - sc_iterator5 *it5 = 0; - sc_iterator5 *it5Res = 0; - sc_iterator5 *it5Args = 0; + sc_iterator5 * it5 = 0; + sc_iterator5 * it5Res = 0; + sc_iterator5 * it5Args = 0; if (sc_memory_get_arc_end(s_default_ctx, arg, &answer_addr) != SC_RESULT_OK) return SC_RESULT_ERROR; // first of all delete translation command - it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - answer_addr, - sc_type_arc_pos_const_perm, - keynode_rrel_source_sc_construction); + it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + answer_addr, + sc_type_arc_pos_const_perm, + keynode_rrel_source_sc_construction); if (sc_iterator5_next(it5) == SC_TRUE) sc_memory_element_free(s_default_ctx, sc_iterator5_value(it5, 0)); sc_iterator5_free(it5); // remove translation result - it5 = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - answer_addr, - sc_type_arc_common | sc_type_const, - sc_type_link, - sc_type_arc_pos_const_perm, - keynode_nrel_translation); + it5 = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + answer_addr, + sc_type_arc_common | sc_type_const, + sc_type_link, + sc_type_arc_pos_const_perm, + keynode_nrel_translation); if (sc_iterator5_next(it5) == SC_TRUE) sc_memory_element_free(s_default_ctx, sc_iterator5_value(it5, 2)); sc_iterator5_free(it5); // find question, and remove all connected information - it5 = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - sc_type_node | sc_type_const, - sc_type_arc_common | sc_type_const, - answer_addr, - sc_type_arc_pos_const_perm, - keynode_question_nrel_answer); + it5 = sc_iterator5_a_a_f_a_f_new( + s_default_ctx, + sc_type_node | sc_type_const, + sc_type_arc_common | sc_type_const, + answer_addr, + sc_type_arc_pos_const_perm, + keynode_question_nrel_answer); if (sc_iterator5_next(it5) == SC_TRUE) { - it5Res = sc_iterator5_a_a_f_a_f_new(s_default_ctx, - 0, - 0, - sc_iterator5_value(it5, 0), - 0, - keynode_nrel_command_result); + it5Res = + sc_iterator5_a_a_f_a_f_new(s_default_ctx, 0, 0, sc_iterator5_value(it5, 0), 0, keynode_nrel_command_result); if (sc_iterator5_next(it5Res) == SC_TRUE) { - it5Args = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - sc_iterator5_value(it5Res, 0), - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_rrel_command_arguments); + it5Args = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + sc_iterator5_value(it5Res, 0), + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_rrel_command_arguments); if (sc_iterator5_next(it5Args) == SC_TRUE) sc_memory_element_free(s_default_ctx, sc_iterator5_value(it5Args, 2)); sc_iterator5_free(it5Args); @@ -457,17 +458,16 @@ sc_result ui_remove_displayed_answer(sc_event *event, sc_addr arg) // -------------------- Module ---------------------- sc_result ui_initialize_commands() { - /*event_ui_start_answer_translation = sc_event_new(keynode_question_finished, SC_EVENT_ADD_OUTPUT_ARC, 0, ui_start_answer_translation, 0); - if (event_ui_start_answer_translation == null) - return SC_RESULT_ERROR;*/ + /*event_ui_start_answer_translation = sc_event_new(keynode_question_finished, SC_EVENT_ADD_OUTPUT_ARC, 0, + ui_start_answer_translation, 0); if (event_ui_start_answer_translation == null) return SC_RESULT_ERROR;*/ - event_ui_command_generate_instance = sc_event_new(s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, ui_command_generate_instance, 0); + event_ui_command_generate_instance = sc_event_new( + s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, ui_command_generate_instance, 0); if (event_ui_command_generate_instance == null_ptr) return SC_RESULT_ERROR; - /*event_ui_remove_displayed_answer = sc_event_new(keynode_displayed_answer, SC_EVENT_ADD_OUTPUT_ARC, 0, ui_remove_displayed_answer, 0); - if (event_ui_remove_displayed_answer == null) - return SC_RESULT_ERROR;*/ + /*event_ui_remove_displayed_answer = sc_event_new(keynode_displayed_answer, SC_EVENT_ADD_OUTPUT_ARC, 0, + ui_remove_displayed_answer, 0); if (event_ui_remove_displayed_answer == null) return SC_RESULT_ERROR;*/ return SC_RESULT_OK; } @@ -476,13 +476,13 @@ void ui_shutdown_commands() { if (event_ui_start_answer_translation) sc_event_destroy(event_ui_start_answer_translation); - event_ui_start_answer_translation = (sc_event*)null_ptr; + event_ui_start_answer_translation = (sc_event *)null_ptr; if (event_ui_command_generate_instance) sc_event_destroy(event_ui_command_generate_instance); - event_ui_command_generate_instance = (sc_event*)null_ptr; + event_ui_command_generate_instance = (sc_event *)null_ptr; if (event_ui_remove_displayed_answer) sc_event_destroy(event_ui_remove_displayed_answer); - event_ui_remove_displayed_answer = (sc_event*)null_ptr; + event_ui_remove_displayed_answer = (sc_event *)null_ptr; } diff --git a/sc-kpm/sc-ui/uiCommands.h b/sc-kpm/sc-ui/uiCommands.h index c03875dafc..57ad8776c3 100644 --- a/sc-kpm/sc-ui/uiCommands.h +++ b/sc-kpm/sc-ui/uiCommands.h @@ -18,4 +18,4 @@ sc_result ui_initialize_commands(); //! Destroy event handlers for command operations void ui_shutdown_commands(); -#endif // _ui_command_h_ +#endif // _ui_command_h_ diff --git a/sc-kpm/sc-ui/uiDefines.h b/sc-kpm/sc-ui/uiDefines.h index 565641d1ce..bfea4c8958 100644 --- a/sc-kpm/sc-ui/uiDefines.h +++ b/sc-kpm/sc-ui/uiDefines.h @@ -7,8 +7,8 @@ #ifndef _uiDefines_h_ #define _uiDefines_h_ -#define SYSTEM_ELEMENT(el) if (sc_helper_check_arc(s_default_ctx, keynode_system_element, el, sc_type_arc_pos_const_perm) == SC_FALSE) \ - sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_system_element, el); - +#define SYSTEM_ELEMENT(el) \ + if (sc_helper_check_arc(s_default_ctx, keynode_system_element, el, sc_type_arc_pos_const_perm) == SC_FALSE) \ + sc_memory_arc_new(s_default_ctx, sc_type_arc_pos_const_perm, keynode_system_element, el); #endif diff --git a/sc-kpm/sc-ui/uiKeynodes.cpp b/sc-kpm/sc-ui/uiKeynodes.cpp index 0e4552dc68..4b01dd610a 100644 --- a/sc-kpm/sc-ui/uiKeynodes.cpp +++ b/sc-kpm/sc-ui/uiKeynodes.cpp @@ -13,7 +13,6 @@ extern "C" #include } - // ------------- Keynodes ---------------------- const char keynode_user_str[] = "ui_user"; const char keynode_command_translate_from_sc_str[] = "ui_command_translate_from_sc"; @@ -21,14 +20,12 @@ const char keynode_nrel_user_answer_formats_str[] = "ui_nrel_user_answer_formats const char keynode_rrel_source_sc_construction_str[] = "ui_rrel_source_sc_construction"; const char keynode_rrel_output_format_str[] = "ui_rrel_output_format"; - const char keynode_question_nrel_answer_str[] = "nrel_answer"; const char keynode_question_finished_str[] = "question_finished"; const char keynode_nrel_authors_str[] = "nrel_authors"; const char keynode_nrel_translation_str[] = "nrel_translation"; const char keynode_nrel_format_str[] = "nrel_format"; - const char keynode_command_generate_instance_str[] = "ui_command_generate_instance"; const char keynode_command_initiated_str[] = "ui_command_initiated"; const char keynode_command_finished_str[] = "ui_command_finished"; @@ -45,7 +42,6 @@ const char keynode_format_scn_json_str[] = "format_scn_json"; const char keynode_system_element_str[] = "system_element"; - sc_addr keynode_user; sc_addr keynode_command_translate_from_sc; sc_addr keynode_nrel_user_answer_formats; @@ -77,7 +73,6 @@ sc_addr keynode_system_element; sc_addr ui_keynode_rrel_order[RREL_ORDER_COUNT]; sc_addr ui_keynode_arg[UI_ARG_COUNT]; - // ------------------------------------------------- sc_bool initialize_keynodes() { @@ -115,7 +110,8 @@ sc_bool initialize_keynodes() if (sc_helper_resolve_system_identifier(s_default_ctx, ss.str().c_str(), &(ui_keynode_rrel_order[i])) == SC_FALSE) { ui_keynode_rrel_order[i] = sc_memory_node_new(s_default_ctx, 0); - if (sc_helper_set_system_identifier(s_default_ctx, ui_keynode_rrel_order[i], ss.str().c_str(), (sc_uint32)ss.str().size()) != SC_RESULT_OK) + if (sc_helper_set_system_identifier( + s_default_ctx, ui_keynode_rrel_order[i], ss.str().c_str(), (sc_uint32)ss.str().size()) != SC_RESULT_OK) return SC_FALSE; } } @@ -127,11 +123,11 @@ sc_bool initialize_keynodes() if (sc_helper_resolve_system_identifier(s_default_ctx, ss.str().c_str(), &(ui_keynode_arg[i])) == SC_FALSE) { ui_keynode_rrel_order[i] = sc_memory_node_new(s_default_ctx, 0); - if (sc_helper_set_system_identifier(s_default_ctx, ui_keynode_rrel_order[i], ss.str().c_str(), (sc_uint32)ss.str().size()) != SC_RESULT_OK) + if (sc_helper_set_system_identifier( + s_default_ctx, ui_keynode_rrel_order[i], ss.str().c_str(), (sc_uint32)ss.str().size()) != SC_RESULT_OK) return SC_FALSE; } } return SC_TRUE; } - diff --git a/sc-kpm/sc-ui/uiPrecompiled.h b/sc-kpm/sc-ui/uiPrecompiled.h index e3ca27c86d..0e7cdfbf59 100644 --- a/sc-kpm/sc-ui/uiPrecompiled.h +++ b/sc-kpm/sc-ui/uiPrecompiled.h @@ -17,4 +17,4 @@ extern "C" #include "sc-core/sc_helper.h" } -#endif // UI_PRECOMPILED_H +#endif // UI_PRECOMPILED_H diff --git a/sc-kpm/sc-ui/uiTranslators.cpp b/sc-kpm/sc-ui/uiTranslators.cpp index 0c716c3ae8..6a93dcef7e 100644 --- a/sc-kpm/sc-ui/uiTranslators.cpp +++ b/sc-kpm/sc-ui/uiTranslators.cpp @@ -12,15 +12,28 @@ #include "translators/uiSc2SCgJsonTranslator.h" #include "translators/uiSc2SCnJsonTranslator.h" -sc_event *ui_translator_sc2scs_event = (sc_event*)null_ptr; -sc_event *ui_translator_sc2scg_json_event = (sc_event*)null_ptr; -sc_event *ui_translator_sc2scn_json_event = (sc_event*)null_ptr; +sc_event * ui_translator_sc2scs_event = (sc_event *)null_ptr; +sc_event * ui_translator_sc2scg_json_event = (sc_event *)null_ptr; +sc_event * ui_translator_sc2scn_json_event = (sc_event *)null_ptr; void ui_initialize_translators() { - ui_translator_sc2scs_event = sc_event_new(s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, uiSc2ScsTranslator::ui_translate_sc2scs, 0); - ui_translator_sc2scg_json_event = sc_event_new(s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, uiSc2SCgJsonTranslator::ui_translate_sc2scg_json, 0); - ui_translator_sc2scn_json_event = sc_event_new(s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, uiSc2SCnJsonTranslator::ui_translate_sc2scn, 0); + ui_translator_sc2scs_event = sc_event_new( + s_default_ctx, keynode_command_initiated, SC_EVENT_ADD_OUTPUT_ARC, 0, uiSc2ScsTranslator::ui_translate_sc2scs, 0); + ui_translator_sc2scg_json_event = sc_event_new( + s_default_ctx, + keynode_command_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + uiSc2SCgJsonTranslator::ui_translate_sc2scg_json, + 0); + ui_translator_sc2scn_json_event = sc_event_new( + s_default_ctx, + keynode_command_initiated, + SC_EVENT_ADD_OUTPUT_ARC, + 0, + uiSc2SCnJsonTranslator::ui_translate_sc2scn, + 0); } void ui_shutdown_translators() @@ -33,19 +46,20 @@ void ui_shutdown_translators() sc_event_destroy(ui_translator_sc2scn_json_event); } -sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr *output_fmt_addr, sc_addr *source_addr) +sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr * output_fmt_addr, sc_addr * source_addr) { - sc_iterator5 *it = (sc_iterator5*)null_ptr; + sc_iterator5 * it = (sc_iterator5 *)null_ptr; sc_bool fmt_found = SC_FALSE; sc_bool source_found = SC_FALSE; // resolve output format - it = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - cmd_addr, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_rrel_output_format); + it = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + cmd_addr, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_rrel_output_format); while (sc_iterator5_next(it) == SC_TRUE) { @@ -59,12 +73,13 @@ sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr *outp return SC_RESULT_ERROR; // resolve input construction - it = sc_iterator5_f_a_a_a_f_new(s_default_ctx, - cmd_addr, - sc_type_arc_pos_const_perm, - sc_type_node | sc_type_const, - sc_type_arc_pos_const_perm, - keynode_rrel_source_sc_construction); + it = sc_iterator5_f_a_a_a_f_new( + s_default_ctx, + cmd_addr, + sc_type_arc_pos_const_perm, + sc_type_node | sc_type_const, + sc_type_arc_pos_const_perm, + keynode_rrel_source_sc_construction); while (sc_iterator5_next(it) == SC_TRUE) { @@ -80,10 +95,10 @@ sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr *outp return SC_RESULT_OK; } -sc_bool ui_translate_resolve_system_identifier(sc_addr el, String &sys_idtf) +sc_bool ui_translate_resolve_system_identifier(sc_addr el, String & sys_idtf) { sc_addr sys_idtf_addr; - sc_stream *idtf_stream = 0; + sc_stream * idtf_stream = 0; sc_uint32 idtf_length = 0; sc_uint32 read_bytes = 0; sc_bool result = SC_FALSE; diff --git a/sc-kpm/sc-ui/uiTranslators.h b/sc-kpm/sc-ui/uiTranslators.h index 8ea8cd1e73..a6e14903fc 100644 --- a/sc-kpm/sc-ui/uiTranslators.h +++ b/sc-kpm/sc-ui/uiTranslators.h @@ -27,7 +27,7 @@ void ui_shutdown_translators(); * @return If format and source construction resolved, then return SC_RESULT_OK; * otherwise return SC_RESULT_ERROR code */ -sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr *output_fmt_addr, sc_addr *source_addr); +sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr * output_fmt_addr, sc_addr * source_addr); /*! Resolve system identifier of specified sc-elmenet. This function * tries to find system identifier and return string, that represent it. @@ -38,6 +38,6 @@ sc_result ui_translate_command_resolve_arguments(sc_addr cmd_addr, sc_addr *outp * @return If system identifier was founeded, then return SC_TRUE. If it was generated, * then return SC_FALSE. If sys_idtf is null, then there are some errors in function. */ -sc_bool ui_translate_resolve_system_identifier(sc_addr el, String &sys_idtf); +sc_bool ui_translate_resolve_system_identifier(sc_addr el, String & sys_idtf); -#endif // _ui_translators_h_ +#endif // _ui_translators_h_ diff --git a/sc-kpm/sc-ui/uiTypes.cpp b/sc-kpm/sc-ui/uiTypes.cpp index e173e5417c..8ba416b1b2 100644 --- a/sc-kpm/sc-ui/uiTypes.cpp +++ b/sc-kpm/sc-ui/uiTypes.cpp @@ -7,7 +7,7 @@ #include "uiPrecompiled.h" #include "uiTypes.h" -bool operator < (const sc_addr &addr1, const sc_addr &addr2) +bool operator<(const sc_addr & addr1, const sc_addr & addr2) { if (addr1.seg != addr2.seg) return addr1.seg < addr2.seg; @@ -15,12 +15,12 @@ bool operator < (const sc_addr &addr1, const sc_addr &addr2) return addr1.offset < addr2.offset; } -bool operator == (const sc_addr &addr1, const sc_addr &addr2) +bool operator==(const sc_addr & addr1, const sc_addr & addr2) { return (addr1.seg == addr2.seg) && (addr1.offset == addr2.offset); } -bool operator != (const sc_addr &addr1, const sc_addr &addr2) +bool operator!=(const sc_addr & addr1, const sc_addr & addr2) { return (addr1.seg != addr2.seg) || (addr1.offset != addr2.offset); } diff --git a/sc-kpm/sc-ui/uiTypes.h b/sc-kpm/sc-ui/uiTypes.h index 291935755f..4e6fe60a54 100644 --- a/sc-kpm/sc-ui/uiTypes.h +++ b/sc-kpm/sc-ui/uiTypes.h @@ -28,13 +28,13 @@ typedef std::vector tScAddrVector; typedef std::map tScAddrToScTypeMap; typedef std::map tScAddrToScAddrMap; typedef std::pair tScAddrPair; -typedef std::list< tScAddrPair > tScAddrPairList; +typedef std::list tScAddrPairList; typedef std::map tStringStringMap; // --- operators --- -bool operator < (const sc_addr &addr1, const sc_addr &addr2); -bool operator == (const sc_addr &addr1, const sc_addr &addr2); -bool operator != (const sc_addr &addr1, const sc_addr &addr2); +bool operator<(const sc_addr & addr1, const sc_addr & addr2); +bool operator==(const sc_addr & addr1, const sc_addr & addr2); +bool operator!=(const sc_addr & addr1, const sc_addr & addr2); extern sc_memory_context * s_default_ctx; diff --git a/sc-kpm/sc-ui/uiUtils.h b/sc-kpm/sc-ui/uiUtils.h index 5c008e29d0..a418b35b37 100644 --- a/sc-kpm/sc-ui/uiUtils.h +++ b/sc-kpm/sc-ui/uiUtils.h @@ -22,4 +22,4 @@ extern "C" */ sc_result ui_check_cmd_type(sc_addr cmd_addr, sc_addr cmd_class); -#endif // _uiUtils_h_ +#endif // _uiUtils_h_ diff --git a/sc-kpm/sc-utils/CMakeLists.txt b/sc-kpm/sc-utils/CMakeLists.txt index 8f9cf9ac8c..0c063559f6 100644 --- a/sc-kpm/sc-utils/CMakeLists.txt +++ b/sc-kpm/sc-utils/CMakeLists.txt @@ -8,3 +8,7 @@ target_include_directories(sc-utils ) add_dependencies(sc-utils sc-core sc-kpm-common) target_link_libraries(sc-utils sc-kpm-common) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-utils) +endif () diff --git a/sc-kpm/sc-utils/utils.c b/sc-kpm/sc-utils/utils.c index 380626afa3..de69eaa241 100644 --- a/sc-kpm/sc-utils/utils.c +++ b/sc-kpm/sc-utils/utils.c @@ -11,7 +11,7 @@ sc_memory_context * s_default_ctx = 0; sc_memory_context * s_garbage_ctx = 0; -sc_event *event_garbage_deletion; +sc_event * event_garbage_deletion; _SC_EXT_EXTERN sc_result sc_module_initialize() { @@ -21,7 +21,8 @@ _SC_EXT_EXTERN sc_result sc_module_initialize() if (utils_keynodes_initialize() != SC_RESULT_OK) return SC_RESULT_ERROR; - event_garbage_deletion = sc_event_new(s_default_ctx, keynode_sc_garbage, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_garbage_delete, 0); + event_garbage_deletion = + sc_event_new(s_default_ctx, keynode_sc_garbage, SC_EVENT_ADD_OUTPUT_ARC, 0, agent_garbage_delete, 0); if (event_garbage_deletion == null_ptr) return SC_RESULT_ERROR; diff --git a/sc-kpm/sc-utils/utils_garbage_deletion.c b/sc-kpm/sc-utils/utils_garbage_deletion.c index b3ef05c8d4..feaeba3c21 100644 --- a/sc-kpm/sc-utils/utils_garbage_deletion.c +++ b/sc-kpm/sc-utils/utils_garbage_deletion.c @@ -7,7 +7,7 @@ #include "utils_garbage_deletion.h" #include "utils.h" -sc_result agent_garbage_delete(const sc_event *event, sc_addr arg) +sc_result agent_garbage_delete(const sc_event * event, sc_addr arg) { //! TODO: when sc-memory will start event in many threads (not in one), then need to check if element exists /// because it can be already deleted as an input or outout arc of element deleted in other thread @@ -28,7 +28,7 @@ sc_result agent_garbage_delete(const sc_event *event, sc_addr arg) else { sc_uint32 count = 0; - sc_iterator3 *it = sc_iterator3_f_a_a_new(s_garbage_ctx, addr, 0, 0); + sc_iterator3 * it = sc_iterator3_f_a_a_new(s_garbage_ctx, addr, 0, 0); while (sc_iterator3_next(it) == SC_TRUE) ++count; sc_iterator3_free(it); diff --git a/sc-kpm/sc-utils/utils_garbage_deletion.h b/sc-kpm/sc-utils/utils_garbage_deletion.h index f42fe274d8..3dea865d39 100644 --- a/sc-kpm/sc-utils/utils_garbage_deletion.h +++ b/sc-kpm/sc-utils/utils_garbage_deletion.h @@ -9,6 +9,6 @@ #include "sc-core/sc_memory_headers.h" -sc_result agent_garbage_delete(const sc_event *event, sc_addr arg); +sc_result agent_garbage_delete(const sc_event * event, sc_addr arg); #endif diff --git a/sc-kpm/scp/CMakeLists.txt b/sc-kpm/scp/CMakeLists.txt index d8e7b864ce..a011413068 100644 --- a/sc-kpm/scp/CMakeLists.txt +++ b/sc-kpm/scp/CMakeLists.txt @@ -22,3 +22,7 @@ target_include_directories(scp add_dependencies(scp sc-core) target_link_libraries(scp sc-core) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(scp) +endif () diff --git a/sc-memory/sc-core/CMakeLists.txt b/sc-memory/sc-core/CMakeLists.txt index 15103548e7..3a6a583b5e 100644 --- a/sc-memory/sc-core/CMakeLists.txt +++ b/sc-memory/sc-core/CMakeLists.txt @@ -10,3 +10,8 @@ target_include_directories(sc-core ) target_link_libraries(sc-core ${GLIB2_LIBRARIES} ${RocksDB_LIBRARIES} gcov) target_compile_definitions(sc-core PRIVATE "-DSC_MEMORY_SELF_BUILD") + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-core) +endif () + diff --git a/sc-memory/sc-core/sc-store/sc_config.c b/sc-memory/sc-core/sc-store/sc_config.c index b196c87cec..d79cd1f723 100644 --- a/sc-memory/sc-core/sc-store/sc_config.c +++ b/sc-memory/sc-core/sc-store/sc_config.c @@ -14,31 +14,29 @@ const char str_group_fm[] = "filememory"; const char str_key_max_loaded_segments[] = "max_loaded_segments"; const char str_key_fm_engine[] = "engine"; - // Maximum number of segments, that can be loaded into memory at one moment sc_uint config_max_loaded_segments = G_MAXUINT16; // Hash table, that contains all configuration options: ['/'] = -GHashTable *values_table = 0; +GHashTable * values_table = 0; // --- file memory --- const char fm_default_engine[] = "filesystem"; -const char *config_fm_engine = fm_default_engine; +const char * config_fm_engine = fm_default_engine; void value_table_destroy_key_value(gpointer data) { g_free(data); } -gchar* value_table_create_hash_key(const char *group, const char *key) +gchar * value_table_create_hash_key(const char * group, const char * key) { return g_strdup_printf("%s/%s", group, key); } - -void sc_config_initialize(const sc_char *file_path) +void sc_config_initialize(const sc_char * file_path) { - GKeyFile *key_file = 0; + GKeyFile * key_file = 0; key_file = g_key_file_new(); if ((file_path != null_ptr) && (g_key_file_load_from_file(key_file, file_path, G_KEY_FILE_NONE, 0) == TRUE)) { @@ -57,27 +55,26 @@ void sc_config_initialize(const sc_char *file_path) } // load all values into hash table - values_table = g_hash_table_new_full(g_str_hash, g_str_equal, value_table_destroy_key_value, value_table_destroy_key_value); + values_table = + g_hash_table_new_full(g_str_hash, g_str_equal, value_table_destroy_key_value, value_table_destroy_key_value); gsize groups_len = 0, i, j; - gchar **groups = g_key_file_get_groups(key_file, &groups_len); + gchar ** groups = g_key_file_get_groups(key_file, &groups_len); for (i = 0; i < groups_len; ++i) { // get all keys in group gsize keys_len = 0; - gchar **keys = g_key_file_get_keys(key_file, groups[i], &keys_len, 0); + gchar ** keys = g_key_file_get_keys(key_file, groups[i], &keys_len, 0); for (j = 0; j < keys_len; ++j) { // append keys into hash table - gchar *hash_key = value_table_create_hash_key(groups[i], keys[j]); + gchar * hash_key = value_table_create_hash_key(groups[i], keys[j]); g_hash_table_insert(values_table, hash_key, g_key_file_get_string(key_file, groups[i], keys[j], 0)); } g_strfreev(keys); - } g_strfreev(groups); - g_key_file_free(key_file); } @@ -94,27 +91,26 @@ sc_int32 sc_config_get_max_loaded_segments() return config_max_loaded_segments; } - -const char* sc_config_get_value_string(const char *group, const char *key) +const char * sc_config_get_value_string(const char * group, const char * key) { - gchar *hash_key = value_table_create_hash_key(group, key); - gconstpointer *res = g_hash_table_lookup(values_table, hash_key); + gchar * hash_key = value_table_create_hash_key(group, key); + gconstpointer * res = g_hash_table_lookup(values_table, hash_key); g_free(hash_key); - return (const char*)res; + return (const char *)res; } -int sc_config_get_value_int(const char *group, const char *key) +int sc_config_get_value_int(const char * group, const char * key) { - const char *str_value = sc_config_get_value_string(group, key); + const char * str_value = sc_config_get_value_string(group, key); if (str_value == 0) return 0; return atoi(str_value); } -sc_bool sc_config_get_value_boolean(const char *group, const char *key) +sc_bool sc_config_get_value_boolean(const char * group, const char * key) { - const char *str_value = sc_config_get_value_string(group, key); + const char * str_value = sc_config_get_value_string(group, key); if (str_value == 0) return SC_FALSE; @@ -124,16 +120,16 @@ sc_bool sc_config_get_value_boolean(const char *group, const char *key) return SC_FALSE; } -float sc_config_get_value_float(const char *group, const char *key) +float sc_config_get_value_float(const char * group, const char * key) { - const char *str_value = sc_config_get_value_string(group, key); + const char * str_value = sc_config_get_value_string(group, key); if (str_value == 0) return SC_FALSE; return (float)atof(str_value); } -const sc_char* sc_config_fm_engine() +const sc_char * sc_config_fm_engine() { return config_fm_engine; } diff --git a/sc-memory/sc-core/sc-store/sc_config.h b/sc-memory/sc-core/sc-store/sc_config.h index 9b1464a38a..58c268b89f 100644 --- a/sc-memory/sc-core/sc-store/sc_config.h +++ b/sc-memory/sc-core/sc-store/sc_config.h @@ -12,7 +12,7 @@ /*! Iniitalize sc-memory configuration from specified configuration file * @param file_path Path to configuration file */ -void sc_config_initialize(const sc_char *file_path); +void sc_config_initialize(const sc_char * file_path); /*! Shutdown sc-memory configuration. Free allocated data. */ @@ -23,37 +23,35 @@ void sc_config_shutdown(); sc_int32 sc_config_get_max_loaded_segments(); //! Returns file memory engine -const sc_char* sc_config_fm_engine(); - +const sc_char * sc_config_fm_engine(); // --- api for extensions --- /*! * Returns string value of \p key in specified \p group * @param group Name of configuration group * @param key Name of key to return value - * @returns Returns the value associated with the key as string, or null if the key was not found of could not be parsed. + * @returns Returns the value associated with the key as string, or null if the key was not found of could not be + * parsed. * @attention Returned value managed by sc_confing and shouldn't be freed */ -_SC_EXTERN const char* sc_config_get_value_string(const char *group, const char *key); +_SC_EXTERN const char * sc_config_get_value_string(const char * group, const char * key); /*! * Returns the value associated with the key as an integer, or 0 if the key was not found or could not be parsed. * @see sc_config_get_value_string */ -_SC_EXTERN int sc_config_get_value_int(const char *group, const char *key); +_SC_EXTERN int sc_config_get_value_int(const char * group, const char * key); /*! * Returns the value associated with the key as a boolean, or SC_FALSE if the key was not found or could not be parsed. * @see sc_config_get_value_string */ -_SC_EXTERN sc_bool sc_config_get_value_boolean(const char *group, const char *key); +_SC_EXTERN sc_bool sc_config_get_value_boolean(const char * group, const char * key); /*! * Returns the value associated with the key as a float, or 0.0 if the key was not found or could not be parsed. * @see sc_config_get_value_string */ -_SC_EXTERN float sc_config_get_value_float(const char *group, const char *key); - +_SC_EXTERN float sc_config_get_value_float(const char * group, const char * key); #endif - diff --git a/sc-memory/sc-core/sc-store/sc_defines.h b/sc-memory/sc-core/sc-store/sc_defines.h index 2cbff459ed..b21203a143 100644 --- a/sc-memory/sc-core/sc-store/sc_defines.h +++ b/sc-memory/sc-core/sc-store/sc_defines.h @@ -10,9 +10,9 @@ #include "sc_platform.h" #ifdef SC_DEBUG -# define SC_DEBUG_MODE 1 +# define SC_DEBUG_MODE 1 #else -# define SC_DEBUG_MODE 0 +# define SC_DEBUG_MODE 0 #endif /*! Bound empty slot serach @@ -26,60 +26,56 @@ #define MAX_PATH_LENGTH 1024 -#define SC_CONCURRENCY_LEVEL 32 // max number of independent threads that can work in parallel with memory -#define SC_SEGMENT_CACHE_SIZE 32 // size of segments cache +#define SC_CONCURRENCY_LEVEL 32 // max number of independent threads that can work in parallel with memory +#define SC_SEGMENT_CACHE_SIZE 32 // size of segments cache -#if defined (SC_MEMORY_SELF_BUILD) -# if defined (SC_PLATFORM_WIN) -# define _SC_EXTERN __declspec(dllexport) -# else -# define _SC_EXTERN -# endif +#if defined(SC_MEMORY_SELF_BUILD) +# if defined(SC_PLATFORM_WIN) +# define _SC_EXTERN __declspec(dllexport) +# else +# define _SC_EXTERN +# endif #else -# if defined (SC_PLATFORM_WIN) -# define _SC_EXTERN __declspec(dllimport) -# else -# define _SC_EXTERN -# endif +# if defined(SC_PLATFORM_WIN) +# define _SC_EXTERN __declspec(dllimport) +# else +# define _SC_EXTERN +# endif #endif -#if defined (SC_PLATFORM_WIN) -# if defined(__cplusplus) -# define _SC_EXT_EXTERN extern "C" __declspec(dllexport) -# else -# define _SC_EXT_EXTERN __declspec(dllexport) -# endif +#if defined(SC_PLATFORM_WIN) +# if defined(__cplusplus) +# define _SC_EXT_EXTERN extern "C" __declspec(dllexport) +# else +# define _SC_EXT_EXTERN __declspec(dllexport) +# endif #else -# define _SC_EXT_EXTERN +# define _SC_EXT_EXTERN #endif // -------------- Deprecation --------------- #if (SC_COMPILER == SC_COMPILER_MSVC) //__declspec(deprecated(__Message))// "Update you code to newest API version " #__Version " or later.")) -# define _SC_DEPRECATED_IMPL(__Version, __Message) __declspec(deprecated(__Message " Update you code to newest API version " #__Version " or later.")) +# define _SC_DEPRECATED_IMPL(__Version, __Message) \ + __declspec(deprecated(__Message " Update you code to newest API version " #__Version " or later.")) -# define PRAGMA_DISABLE_DEPRECATION_WARNINGS \ - __pragma (warning(push)) \ - __pragma (warning(disable:4995)) \ - __pragma (warning(disable:4996)) +# define PRAGMA_DISABLE_DEPRECATION_WARNINGS \ + __pragma(warning(push)) __pragma(warning(disable : 4995)) __pragma(warning(disable : 4996)) -# define PRAGMA_ENABLE_DEPRECATION_WARNINGS \ - __pragma (warning(pop)) +# define PRAGMA_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) #elif (SC_COMPILER == SC_COMPILER_CLANG) -# define _SC_DEPRECATED_IMPL(__Version, __Message) __attribute__((deprecated(__Message "Update you code to newest API version " #__Version " or later."))) +# define _SC_DEPRECATED_IMPL(__Version, __Message) \ + __attribute__((deprecated(__Message "Update you code to newest API version " #__Version " or later."))) #elif (SC_COMPILER == SC_COMPILER_GNU) -# define _SC_DEPRECATED_IMPL(__Version, __Message) +# define _SC_DEPRECATED_IMPL(__Version, __Message) #else -# define _SC_DEPRECATED_IMPL(__Version, __Message) +# define _SC_DEPRECATED_IMPL(__Version, __Message) #endif +#define SC_DEPRECATED(__Version, __Message) _SC_DEPRECATED_IMPL(__Version, __Message) -#define SC_DEPRECATED(__Version, __Message) _SC_DEPRECATED_IMPL(__Version, __Message) - - - -#endif // _sc_defines_h_ +#endif // _sc_defines_h_ diff --git a/sc-memory/sc-core/sc-store/sc_element.c b/sc-memory/sc-core/sc-store/sc_element.c index 17117b3e21..990989a34a 100644 --- a/sc-memory/sc-core/sc-store/sc_element.c +++ b/sc-memory/sc-core/sc-store/sc_element.c @@ -11,13 +11,13 @@ #include -void sc_element_set_type(sc_element *element, sc_type type) +void sc_element_set_type(sc_element * element, sc_type type) { g_assert(element != 0); element->flags.type = sc_flags_remove(type); } -sc_bool sc_element_is_checksum_empty(sc_element *element) +sc_bool sc_element_is_checksum_empty(sc_element * element) { g_assert(element->flags.type & sc_type_link); sc_uint32 i = 0; @@ -28,17 +28,17 @@ sc_bool sc_element_is_checksum_empty(sc_element *element) return SC_TRUE; } -sc_bool sc_element_is_request_deletion(sc_element *element) +sc_bool sc_element_is_request_deletion(sc_element * element) { return (element->flags.type & sc_flag_request_deletion) ? SC_TRUE : SC_FALSE; } -sc_bool sc_element_is_valid(sc_element *element) +sc_bool sc_element_is_valid(sc_element * element) { return (element->flags.type == 0 || element->flags.type & sc_flag_request_deletion) ? SC_FALSE : SC_TRUE; } -sc_uint16 sc_element_get_refs(sc_element_meta *element) +sc_uint16 sc_element_get_refs(sc_element_meta * element) { return element->ref_count; } diff --git a/sc-memory/sc-core/sc-store/sc_element.h b/sc-memory/sc-core/sc-store/sc_element.h index 11f4235d85..0da9127ae8 100644 --- a/sc-memory/sc-core/sc-store/sc_element.h +++ b/sc-memory/sc-core/sc-store/sc_element.h @@ -14,14 +14,13 @@ struct _sc_arc_info { sc_addr begin; sc_addr end; - sc_addr next_out_arc; // sc-addr of next output arc in list - sc_addr next_in_arc; // sc-addr of next input arc in list - sc_addr prev_out_arc; // sc-addr of pevious output arc in list - sc_addr prev_in_arc; // sc-addr of previous input arc in list + sc_addr next_out_arc; // sc-addr of next output arc in list + sc_addr next_in_arc; // sc-addr of next input arc in list + sc_addr prev_out_arc; // sc-addr of pevious output arc in list + sc_addr prev_in_arc; // sc-addr of previous input arc in list }; - -#define SC_CHECKSUM_LEN 32 //(sizeof(sc_arc_info) - sizeof(sc_uint32)) +#define SC_CHECKSUM_LEN 32 //(sizeof(sc_arc_info) - sizeof(sc_uint32)) /*! Structure to store content information * Data field store checksum for data, that stores in specified sc-link. @@ -60,14 +59,14 @@ struct _sc_content struct _sc_element_locks { - sc_uint8 out_inp:1; - sc_uint8 del:1; - sc_uint8 change:1; - sc_uint8 read:1; + sc_uint8 out_inp : 1; + sc_uint8 del : 1; + sc_uint8 change : 1; + sc_uint8 read : 1; }; -#define SC_ELID_REFS_MASK 0xffff -#define SC_IT_REFS_MASK (0xffff << 16) +#define SC_ELID_REFS_MASK 0xffff +#define SC_IT_REFS_MASK (0xffff << 16) struct _sc_element_flags { @@ -79,8 +78,8 @@ struct _sc_element_meta { union { - sc_element_locks locks; // bits access - sc_uint8 locks_data; // one byte + sc_element_locks locks; // bits access + sc_uint8 locks_data; // one byte }; sc_uint32 ref_count; @@ -100,11 +99,11 @@ struct _sc_element }; /// All functions must be called for locked sc-elements -void sc_element_set_type(sc_element *element, sc_type type); +void sc_element_set_type(sc_element * element, sc_type type); -sc_bool sc_element_is_checksum_empty(sc_element *element); +sc_bool sc_element_is_checksum_empty(sc_element * element); -sc_bool sc_element_is_request_deletion(sc_element *element); -sc_bool sc_element_is_valid(sc_element *element); +sc_bool sc_element_is_request_deletion(sc_element * element); +sc_bool sc_element_is_valid(sc_element * element); #endif diff --git a/sc-memory/sc-core/sc-store/sc_event.c b/sc-memory/sc-core/sc-store/sc_event.c index f184b3cd8c..1d13d12610 100644 --- a/sc-memory/sc-core/sc-store/sc_event.c +++ b/sc-memory/sc-core/sc-store/sc_event.c @@ -18,8 +18,8 @@ GMutex events_table_mutex; #define TABLE_KEY(__Addr) GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(__Addr)) // Pointer to hash table that contains events -GHashTable *events_table = 0; -sc_event_queue *event_queue = 0; +GHashTable * events_table = 0; +sc_event_queue * event_queue = 0; guint events_table_hash_func(gconstpointer pointer) { @@ -32,18 +32,18 @@ gboolean events_table_equal_func(gconstpointer a, gconstpointer b) } //! Inserts specified event into events table -sc_result insert_event_into_table(sc_event *event) +sc_result insert_event_into_table(sc_event * event) { - GSList *element_events_list = 0; + GSList * element_events_list = 0; EVENTS_TABLE_LOCK - // first of all, if table doesn't exist, then create it - if (events_table == null_ptr) - events_table = g_hash_table_new(events_table_hash_func, events_table_equal_func); + // first of all, if table doesn't exist, then create it + if (events_table == null_ptr) + events_table = g_hash_table_new(events_table_hash_func, events_table_equal_func); // if there are no events for specified sc-element, then create new events list - element_events_list = (GSList*)g_hash_table_lookup(events_table, TABLE_KEY(event->element)); + element_events_list = (GSList *)g_hash_table_lookup(events_table, TABLE_KEY(event->element)); element_events_list = g_slist_append(element_events_list, (gpointer)event); g_hash_table_insert(events_table, TABLE_KEY(event->element), (gpointer)element_events_list); @@ -53,14 +53,14 @@ sc_result insert_event_into_table(sc_event *event) } //! Remove specified sc-event from events table -sc_result remove_event_from_table(sc_event *event) +sc_result remove_event_from_table(sc_event * event) { - GSList *element_events_list = 0; + GSList * element_events_list = 0; g_assert(events_table != null_ptr); EVENTS_TABLE_LOCK - element_events_list = (GSList*)g_hash_table_lookup(events_table, TABLE_KEY(event->element)); + element_events_list = (GSList *)g_hash_table_lookup(events_table, TABLE_KEY(event->element)); if (element_events_list == null_ptr) { EVENTS_TABLE_UNLOCK @@ -119,7 +119,13 @@ sc_bool sc_event_unref(sc_event * evt) } // TODO: remove in 0.4.0 -sc_event* sc_event_new(sc_memory_context const * ctx, sc_addr el, sc_event_type type, sc_pointer data, fEventCallback callback, fDeleteCallback delete_callback) +sc_event * sc_event_new( + sc_memory_context const * ctx, + sc_addr el, + sc_event_type type, + sc_pointer data, + fEventCallback callback, + fDeleteCallback delete_callback) { g_assert(callback != null_ptr); @@ -127,8 +133,9 @@ sc_event* sc_event_new(sc_memory_context const * ctx, sc_addr el, sc_event_type return null_ptr; sc_access_levels levels; - sc_event *event = null_ptr; - if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + sc_event * event = null_ptr; + if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) return 0; sc_storage_element_ref(el); @@ -153,7 +160,13 @@ sc_event* sc_event_new(sc_memory_context const * ctx, sc_addr el, sc_event_type return event; } -sc_event* sc_event_new_ex(sc_memory_context const * ctx, sc_addr el, sc_event_type type, sc_pointer data, fEventCallbackEx callback, fDeleteCallback delete_callback) +sc_event * sc_event_new_ex( + sc_memory_context const * ctx, + sc_addr el, + sc_event_type type, + sc_pointer data, + fEventCallbackEx callback, + fDeleteCallback delete_callback) { g_assert(callback != null_ptr); @@ -161,8 +174,9 @@ sc_event* sc_event_new_ex(sc_memory_context const * ctx, sc_addr el, sc_event_ty return null_ptr; sc_access_levels levels; - sc_event *event = null_ptr; - if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + sc_event * event = null_ptr; + if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) return 0; sc_storage_element_ref(el); @@ -209,16 +223,16 @@ sc_result sc_event_destroy(sc_event * evt) sc_event_unlock(evt); unref: - { - sc_event_unref(evt); - } +{ + sc_event_unref(evt); +} // whait while will be available for a destroy while (SC_TRUE) { sc_event_lock(evt); sc_uint32 const refs = evt->ref_count; - if (refs == SC_EVENT_REQUEST_DESTROY) // no refs + if (refs == SC_EVENT_REQUEST_DESTROY) // no refs { sc_storage_element_unref(evt->element); if (evt->delete_callback != null_ptr) @@ -238,23 +252,23 @@ sc_result sc_event_destroy(sc_event * evt) sc_result sc_event_notify_element_deleted(sc_addr element) { - GSList *element_events_list = 0; - sc_event *evt = 0; + GSList * element_events_list = 0; + sc_event * evt = 0; EVENTS_TABLE_LOCK - // do nothing, if there are no registered events - if (events_table == null_ptr) - goto result; + // do nothing, if there are no registered events + if (events_table == null_ptr) + goto result; // lookup for all registered to specified sc-elemen events - element_events_list = (GSList*)g_hash_table_lookup(events_table, TABLE_KEY(element)); + element_events_list = (GSList *)g_hash_table_lookup(events_table, TABLE_KEY(element)); if (element_events_list) { g_hash_table_remove(events_table, TABLE_KEY(element)); while (element_events_list != null_ptr) { - evt = (sc_event*)element_events_list->data; + evt = (sc_event *)element_events_list->data; // mark event for deletion sc_event_lock(evt); @@ -267,14 +281,20 @@ sc_result sc_event_notify_element_deleted(sc_addr element) } result: - { - EVENTS_TABLE_UNLOCK; - } +{ + EVENTS_TABLE_UNLOCK; +} return SC_RESULT_OK; } -sc_result sc_event_emit(sc_memory_context * ctx, sc_addr el, sc_access_levels el_access, sc_event_type type, sc_addr edge, sc_addr other_el) +sc_result sc_event_emit( + sc_memory_context * ctx, + sc_addr el, + sc_access_levels el_access, + sc_event_type type, + sc_addr edge, + sc_addr other_el) { if (ctx->flags & SC_CONTEXT_FLAG_PENDING_EVENTS) { @@ -284,7 +304,7 @@ sc_result sc_event_emit(sc_memory_context * ctx, sc_addr el, sc_access_levels el params->type = type; params->edge = edge; params->other_el = other_el; - + sc_memory_context_pend_event(ctx, params); return SC_RESULT_OK; } @@ -292,10 +312,16 @@ sc_result sc_event_emit(sc_memory_context * ctx, sc_addr el, sc_access_levels el return sc_event_emit_impl(ctx, el, el_access, type, edge, other_el); } -sc_result sc_event_emit_impl(sc_memory_context const * ctx, sc_addr el, sc_access_levels el_access, sc_event_type type, sc_addr edge, sc_addr other_el) +sc_result sc_event_emit_impl( + sc_memory_context const * ctx, + sc_addr el, + sc_access_levels el_access, + sc_event_type type, + sc_addr edge, + sc_addr other_el) { - GSList *element_events_list = 0; - sc_event *event = 0; + GSList * element_events_list = 0; + sc_event * event = 0; g_assert(SC_ADDR_IS_NOT_EMPTY(el)); @@ -306,13 +332,12 @@ sc_result sc_event_emit_impl(sc_memory_context const * ctx, sc_addr el, sc_acces goto result; // lookup for all registered to specified sc-elemen events - element_events_list = (GSList*)g_hash_table_lookup(events_table, TABLE_KEY(el)); + element_events_list = (GSList *)g_hash_table_lookup(events_table, TABLE_KEY(el)); while (element_events_list != null_ptr) { - event = (sc_event*)element_events_list->data; + event = (sc_event *)element_events_list->data; - if (event->type == type && - sc_access_lvl_check_read(event->access_levels, el_access) && + if (event->type == type && sc_access_lvl_check_read(event->access_levels, el_access) && _sc_event_try_emit(event) == SC_TRUE) { g_assert(event->callback != null_ptr || event->callback_ex != null_ptr); @@ -323,26 +348,26 @@ sc_result sc_event_emit_impl(sc_memory_context const * ctx, sc_addr el, sc_acces } result: - { - EVENTS_TABLE_UNLOCK; - } +{ + EVENTS_TABLE_UNLOCK; +} return SC_RESULT_OK; } -sc_event_type sc_event_get_type(const sc_event *event) +sc_event_type sc_event_get_type(const sc_event * event) { g_assert(event != 0); return event->type; } -sc_pointer sc_event_get_data(const sc_event *event) +sc_pointer sc_event_get_data(const sc_event * event) { g_assert(event != 0); return event->data; } -sc_addr sc_event_get_element(const sc_event *event) +sc_addr sc_event_get_element(const sc_event * event) { g_assert(event != 0); return event->element; diff --git a/sc-memory/sc-core/sc-store/sc_event.h b/sc-memory/sc-core/sc-store/sc_event.h index aecb6f029a..1f64443c05 100644 --- a/sc-memory/sc-core/sc-store/sc_event.h +++ b/sc-memory/sc-core/sc-store/sc_event.h @@ -16,14 +16,13 @@ * - sc-addr of another end of added/remove edge * So it can be empty. */ -typedef sc_result (*fEventCallbackEx)(const sc_event *event, sc_addr arg, sc_addr other_el); +typedef sc_result (*fEventCallbackEx)(const sc_event * event, sc_addr arg, sc_addr other_el); /// Backward compatibility -typedef sc_result(*fEventCallback)(const sc_event *event, sc_addr arg); +typedef sc_result (*fEventCallback)(const sc_event * event, sc_addr arg); //! Delete listened element callback function type -typedef sc_result (*fDeleteCallback)(const sc_event *event); - +typedef sc_result (*fDeleteCallback)(const sc_event * event); /*! Subscribe for events from specified sc-element * @param el sc-addr of subscribed sc-element events @@ -35,24 +34,36 @@ typedef sc_result (*fDeleteCallback)(const sc_event *event); * @remarks Callback functions can be called from any thread, so they need to be a thread safe */ SC_DEPRECATED("0.3.0", "Use sc_event_new_ex instead of this function. This function will be removed in next release.") -_SC_EXTERN sc_event* sc_event_new(sc_memory_context const * ctx, sc_addr el, sc_event_type type, sc_pointer data, fEventCallback callback, fDeleteCallback delete_callback); +_SC_EXTERN sc_event * sc_event_new( + sc_memory_context const * ctx, + sc_addr el, + sc_event_type type, + sc_pointer data, + fEventCallback callback, + fDeleteCallback delete_callback); -_SC_EXTERN sc_event* sc_event_new_ex(sc_memory_context const * ctx, sc_addr el, sc_event_type type, sc_pointer data, fEventCallbackEx callback, fDeleteCallback delete_callback); +_SC_EXTERN sc_event * sc_event_new_ex( + sc_memory_context const * ctx, + sc_addr el, + sc_event_type type, + sc_pointer data, + fEventCallbackEx callback, + fDeleteCallback delete_callback); /*! Destroys specified sc-event * @param event Poitner to sc-event, that need to be destroyed * @return If event destoyed correctly, then return SC_OK; otherwise return SC_ERROR code. */ -_SC_EXTERN sc_result sc_event_destroy(sc_event *event); +_SC_EXTERN sc_result sc_event_destroy(sc_event * event); /*! Returns type of specified sc-event */ -_SC_EXTERN sc_event_type sc_event_get_type(const sc_event *event); +_SC_EXTERN sc_event_type sc_event_get_type(const sc_event * event); //! Returns data of specified sc-event -_SC_EXTERN sc_pointer sc_event_get_data(const sc_event *event); +_SC_EXTERN sc_pointer sc_event_get_data(const sc_event * event); //! Returns sc-addr of sc-element where event subscribed -_SC_EXTERN sc_addr sc_event_get_element(const sc_event *event); +_SC_EXTERN sc_addr sc_event_get_element(const sc_event * event); -#endif // SC_EVENT_H +#endif // SC_EVENT_H diff --git a/sc-memory/sc-core/sc-store/sc_event/sc_event_private.h b/sc-memory/sc-core/sc-store/sc_event/sc_event_private.h index e2b7904c08..5419ac8400 100644 --- a/sc-memory/sc-core/sc-store/sc_event/sc_event_private.h +++ b/sc-memory/sc-core/sc-store/sc_event/sc_event_private.h @@ -17,7 +17,7 @@ * After that destroy event. */ -#define SC_EVENT_REQUEST_DESTROY (1 << 31) +#define SC_EVENT_REQUEST_DESTROY (1 << 31) #define SC_EVENT_REF_COUNT_MASK (~SC_EVENT_REQUEST_DESTROY) /*! Structure that contains information about event @@ -42,17 +42,16 @@ struct _sc_event volatile sc_pointer thread_lock; //! Access levels sc_access_levels access_levels; - }; - //! Function to initialize sc-events module sc_bool sc_events_initialize(); //! Function to shutdown sc-events module void sc_events_shutdown(); -//! Waits while all emited events will be processed, then returns. After calling that function all new emited events will be ignored +//! Waits while all emited events will be processed, then returns. After calling that function all new emited events +//! will be ignored void sc_events_stop_processing(); /*! Notificate about sc-element deletion. @@ -73,11 +72,23 @@ sc_result sc_event_notify_element_deleted(sc_addr element); * If \p el is a target, then \p other_el is a source. * @return If event emitted without any errors, then return SC_OK; otherwise return SC_ERROR code */ -sc_result sc_event_emit(sc_memory_context * ctx, sc_addr el, sc_access_levels el_acces, sc_event_type type, sc_addr edge, sc_addr other_el); +sc_result sc_event_emit( + sc_memory_context * ctx, + sc_addr el, + sc_access_levels el_acces, + sc_event_type type, + sc_addr edge, + sc_addr other_el); /*! Emit event immediately */ -sc_result sc_event_emit_impl(sc_memory_context const * ctx, sc_addr el, sc_access_levels el_access, sc_event_type type, sc_addr edge, sc_addr other_el); +sc_result sc_event_emit_impl( + sc_memory_context const * ctx, + sc_addr el, + sc_access_levels el_access, + sc_event_type type, + sc_addr edge, + sc_addr other_el); /* Remove reference from event. * Remove reference from an event diff --git a/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.c b/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.c index d9e583baa2..507372f023 100644 --- a/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.c +++ b/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.c @@ -34,14 +34,13 @@ void sc_event_pool_worker_data_destroy(sc_event_pool_worker_data * data) g_free(data); } - void sc_event_pool_worker(gpointer data, gpointer user_data) { g_assert(data != null_ptr); - sc_event_pool_worker_data * work_data = (sc_event_pool_worker_data*)data; + sc_event_pool_worker_data * work_data = (sc_event_pool_worker_data *)data; g_assert(work_data->evt != null_ptr); - if (work_data->evt->callback != null_ptr) // TODO: cleanup in 0.4.0 + if (work_data->evt->callback != null_ptr) // TODO: cleanup in 0.4.0 { work_data->evt->callback(work_data->evt, work_data->edge_addr); } @@ -56,7 +55,7 @@ void sc_event_pool_worker(gpointer data, gpointer user_data) sc_event_queue * sc_event_queue_new() { - sc_event_queue *queue = g_new0(sc_event_queue, 1); + sc_event_queue * queue = g_new0(sc_event_queue, 1); queue->running = SC_TRUE; g_mutex_init(&queue->mutex); queue->thread_pool = g_thread_pool_new(sc_event_pool_worker, (gpointer)0, g_get_num_processors(), FALSE, 0); @@ -64,7 +63,7 @@ sc_event_queue * sc_event_queue_new() return queue; } -void sc_event_queue_stop_processing(sc_event_queue *queue) +void sc_event_queue_stop_processing(sc_event_queue * queue) { g_assert(queue != 0); @@ -80,10 +79,9 @@ void sc_event_queue_stop_processing(sc_event_queue *queue) queue->running = SC_FALSE; g_mutex_unlock(&queue->mutex); } - } -void sc_event_queue_destroy_wait(sc_event_queue *queue) +void sc_event_queue_destroy_wait(sc_event_queue * queue) { g_assert(queue != 0); @@ -111,11 +109,10 @@ void sc_event_queue_append(sc_event_queue * queue, sc_event * evt, sc_addr edge, g_mutex_unlock(&queue->mutex); } -void sc_event_queue_remove(sc_event_queue *queue, sc_event *event) +void sc_event_queue_remove(sc_event_queue * queue, sc_event * event) { g_assert(queue != 0); g_mutex_lock(&queue->mutex); g_mutex_unlock(&queue->mutex); } - diff --git a/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.h b/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.h index 12af3a9583..7356a0388f 100644 --- a/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.h +++ b/sc-memory/sc-core/sc-store/sc_event/sc_event_queue.h @@ -13,15 +13,14 @@ struct _sc_event_queue { GMutex mutex; - sc_bool running; // flag that determine if queue is running - GRecMutex proc_mutex; // mutex to lock event for process - GThreadPool *thread_pool; // thread pool that used for a workers + sc_bool running; // flag that determine if queue is running + GRecMutex proc_mutex; // mutex to lock event for process + GThreadPool * thread_pool; // thread pool that used for a workers }; - struct _sc_event_queue_item { - sc_event *event; + sc_event * event; sc_addr edge; sc_addr other_el; }; @@ -30,15 +29,15 @@ typedef struct _sc_event_queue sc_event_queue; typedef struct _sc_event_queue_item sc_event_queue_item; //! Create new sc-event queue -sc_event_queue* sc_event_queue_new(); +sc_event_queue * sc_event_queue_new(); //! Stop events processing -void sc_event_queue_stop_processing(sc_event_queue *queue); +void sc_event_queue_stop_processing(sc_event_queue * queue); //! Destroys event queue. It waits until all events in queue will be processed -void sc_event_queue_destroy_wait(sc_event_queue *queue); +void sc_event_queue_destroy_wait(sc_event_queue * queue); //! Appends \p event to queue -void sc_event_queue_append(sc_event_queue *queue, sc_event *event, sc_addr edge, sc_addr other_el); +void sc_event_queue_append(sc_event_queue * queue, sc_event * event, sc_addr edge, sc_addr other_el); #endif diff --git a/sc-memory/sc-core/sc-store/sc_fm_engine.cpp b/sc-memory/sc-core/sc-store/sc_fm_engine.cpp index 6812e7989e..4dfc8af25a 100644 --- a/sc-memory/sc-core/sc-store/sc_fm_engine.cpp +++ b/sc-memory/sc-core/sc-store/sc_fm_engine.cpp @@ -30,14 +30,13 @@ using MutexGuard = std::lock_guard; namespace { - bool CreateDBInstance() { rocksdb::Options options; options.create_if_missing = true; -// options.error_if_exists = true; + // options.error_if_exists = true; -// _sc_fm_remove_dir(gInstancePath.c_str()); + // _sc_fm_remove_dir(gInstancePath.c_str()); _sc_fs_mkdirs(gInstancePath.c_str()); rocksdb::Status status = rocksdb::DB::Open(options, gInstancePath, &gDBInstance); if (!status.ok()) @@ -50,7 +49,7 @@ void DestroyDBInstance() { assert(gDBInstance); gDBInstance->SyncWAL(); -// gDBInstance->Close(); + // gDBInstance->Close(); delete gDBInstance; gDBInstance = nullptr; @@ -77,8 +76,7 @@ std::string DataToStringBuffer(AddrsVector const & addrs) uint8_t const * pSize = (uint8_t const *)(&size); uint8_t const * pData = (uint8_t const *)(addrs.data()); - return std::string(pSize, pSize + sizeof(size)) + - std::string(pData, pData + sizeof(sc_addr) * size); + return std::string(pSize, pSize + sizeof(size)) + std::string(pData, pData + sizeof(sc_addr) * size); } AddrsVector StringBufferToData(std::string const & data) @@ -97,12 +95,12 @@ AddrsVector StringBufferToData(std::string const & data) #define SC_RES(expr) (expr) ? SC_RESULT_OK : SC_RESULT_ERROR; -} +} // namespace sc_result sc_fm_init(const sc_char * repo_path) { MutexGuard lock(gMutex); - gInstancePath = std::string (repo_path) + "/file_memory"; + gInstancePath = std::string(repo_path) + "/file_memory"; return SC_RES(CreateDBInstance()); } @@ -124,7 +122,7 @@ sc_stream * sc_fm_read_stream_new(const sc_check_sum * check_sum) if (status.ok()) { - sc_char * data = (sc_char*)malloc(value.size()); + sc_char * data = (sc_char *)malloc(value.size()); if (data == nullptr) return nullptr; @@ -148,8 +146,7 @@ sc_result sc_fm_write_stream(const sc_check_sum * check_sum, const sc_stream * s if (res != SC_RESULT_OK) return SC_RESULT_ERROR_IO; - - + sc_char buffer[1024]; std::string data; @@ -164,20 +161,20 @@ sc_result sc_fm_write_stream(const sc_check_sum * check_sum, const sc_stream * s assert(gDBInstance); rocksdb::WriteOptions options; -// options.sync = true; + // options.sync = true; rocksdb::Status status = gDBInstance->Put(options, MakeContentKey(check_sum), data); return SC_RES(status.ok()); } -sc_result sc_fm_addr_ref_append(sc_addr addr, const sc_check_sum *check_sum) +sc_result sc_fm_addr_ref_append(sc_addr addr, const sc_check_sum * check_sum) { MutexGuard lock(gMutex); assert(gDBInstance); std::string const key = MakeAddrsKey(check_sum); - std::string value; + std::string value; rocksdb::ReadOptions readOptions; rocksdb::Status status = gDBInstance->Get(readOptions, key, &value); @@ -195,14 +192,14 @@ sc_result sc_fm_addr_ref_append(sc_addr addr, const sc_check_sum *check_sum) return SC_RES(status.ok()); } -sc_result sc_fm_addr_ref_remove(sc_addr addr, const sc_check_sum *check_sum) +sc_result sc_fm_addr_ref_remove(sc_addr addr, const sc_check_sum * check_sum) { MutexGuard lock(gMutex); assert(gDBInstance); std::string const key = MakeAddrsKey(check_sum); - std::string value; + std::string value; rocksdb::ReadOptions readOptions; rocksdb::Status status = gDBInstance->Get(readOptions, key, &value); @@ -235,14 +232,14 @@ sc_result sc_fm_addr_ref_remove(sc_addr addr, const sc_check_sum *check_sum) return SC_RES(status.ok()); } -sc_result sc_fm_find(const sc_check_sum *check_sum, sc_addr **result, sc_uint32 *result_count) +sc_result sc_fm_find(const sc_check_sum * check_sum, sc_addr ** result, sc_uint32 * result_count) { MutexGuard lock(gMutex); assert(gDBInstance); - + std::string const key = MakeAddrsKey(check_sum); - std::string value; + std::string value; rocksdb::ReadOptions readOptions; rocksdb::Status status = gDBInstance->Get(readOptions, key, &value); @@ -255,7 +252,7 @@ sc_result sc_fm_find(const sc_check_sum *check_sum, sc_addr **result, sc_uint32 *result_count = sc_uint32(addrs.size()); size_t const resultBytes = sizeof(sc_addr) * addrs.size(); - *result = (sc_addr*)malloc(resultBytes); + *result = (sc_addr *)malloc(resultBytes); memcpy(*result, addrs.data(), resultBytes); return SC_RESULT_OK; @@ -281,7 +278,7 @@ sc_result sc_fm_save() assert(gDBInstance); rocksdb::FlushOptions options; options.wait = true; - + rocksdb::Status status = gDBInstance->Flush(options); return SC_RES(status.ok()); } diff --git a/sc-memory/sc-core/sc-store/sc_fm_engine.h b/sc-memory/sc-core/sc-store/sc_fm_engine.h index c5904b270a..9de1b5926c 100644 --- a/sc-memory/sc-core/sc-store/sc_fm_engine.h +++ b/sc-memory/sc-core/sc-store/sc_fm_engine.h @@ -25,4 +25,4 @@ sc_result sc_fm_clear(); sc_result sc_fm_save(); sc_result sc_fm_clean_state(); -#endif // _sc_fm_engine_h_ +#endif // _sc_fm_engine_h_ diff --git a/sc-memory/sc-core/sc-store/sc_fs_storage.c b/sc-memory/sc-core/sc-store/sc_fs_storage.c index 6bc3564aa4..4800ab8a05 100644 --- a/sc-memory/sc-core/sc-store/sc_fs_storage.c +++ b/sc-memory/sc-core/sc-store/sc_fs_storage.c @@ -20,30 +20,24 @@ #define BuffSize 256 * 1024 -gchar *repo_path = 0; -gchar segments_path[MAX_PATH_LENGTH]; // Path to file, where stored segments in correct state +gchar * repo_path = 0; +gchar segments_path[MAX_PATH_LENGTH]; // Path to file, where stored segments in correct state #define SC_DIR_PERMISSIONS -1 -const gchar *seg_meta = "_meta"; -const gchar *addr_key_group = "addrs"; +const gchar * seg_meta = "_meta"; +const gchar * addr_key_group = "addrs"; // ---------------------------------------------- -void _get_segment_path(const gchar *path_dir, - sc_uint id, - sc_uint max_path_len, - gchar *res) +void _get_segment_path(const gchar * path_dir, sc_uint id, sc_uint max_path_len, gchar * res) { g_snprintf(res, max_path_len, "%s/%.10d", path_dir, id); } -void _get_segment_checksum_path(const gchar *path, - sc_uint max_path_len, - gchar * res) +void _get_segment_checksum_path(const gchar * path, sc_uint max_path_len, gchar * res) { g_snprintf(res, max_path_len, "%s.checksum", path); } - int _checksum_type() { return G_CHECKSUM_SHA512; @@ -64,18 +58,18 @@ guint8 * _checksum_seg(sc_segment const * seg) if (checksum) { g_checksum_reset(checksum); - g_checksum_update(checksum, (guchar*)(&seg->elements[0]), SC_SEG_ELEMENTS_SIZE_BYTE); + g_checksum_update(checksum, (guchar *)(&seg->elements[0]), SC_SEG_ELEMENTS_SIZE_BYTE); length = _checksum_get_size(); result = g_new0(guint8, length); g_checksum_get_digest(checksum, result, &length); - g_assert( length == _checksum_get_size() ); + g_assert(length == _checksum_get_size()); } return result; } -void _sc_fm_remove_dir(const char *path) +void _sc_fm_remove_dir(const char * path) { char tmp_path[MAX_PATH_LENGTH]; gchar const * fname = 0; @@ -85,7 +79,7 @@ void _sc_fm_remove_dir(const char *path) return; dir = g_dir_open(path, 0, 0); - g_assert( dir != (GDir*)0 ); + g_assert(dir != (GDir *)0); // calculate files fname = g_dir_read_name(dir); @@ -111,7 +105,7 @@ void _sc_fm_remove_dir(const char *path) } // ---------------------------------------------- -sc_bool _sc_fs_mkdirs(const char *path) +sc_bool _sc_fs_mkdirs(const char * path) { #if SC_PLATFORM_LINUX || SC_PLATFORM_MAC int const mode = 0755; @@ -124,12 +118,12 @@ sc_bool _sc_fs_mkdirs(const char *path) return SC_TRUE; } -sc_bool sc_fs_storage_initialize(const gchar *path, sc_bool clear) +sc_bool sc_fs_storage_initialize(const gchar * path, sc_bool clear) { g_message("Initialize sc-storage from path: %s", path); g_snprintf(segments_path, MAX_PATH_LENGTH, "%s/segments.scdb", path); repo_path = g_strdup(path); - + sc_fm_init(repo_path); // clear repository if needs @@ -150,7 +144,7 @@ sc_bool sc_fs_storage_initialize(const gchar *path, sc_bool clear) return SC_TRUE; } -sc_bool sc_fs_storage_shutdown(sc_segment **segments, sc_bool save_segments) +sc_bool sc_fs_storage_shutdown(sc_segment ** segments, sc_bool save_segments) { g_message("Shutdown sc-storage"); @@ -168,7 +162,7 @@ sc_bool sc_fs_storage_shutdown(sc_segment **segments, sc_bool save_segments) return res; } -sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_num) +sc_bool sc_fs_storage_read_from_path(sc_segment ** segments, sc_uint32 * segments_num) { if (g_file_test(repo_path, G_FILE_TEST_IS_DIR) == FALSE) { @@ -206,7 +200,9 @@ sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_ return SC_FALSE; } - if ((g_io_channel_read_chars(in_file, (gchar*)&header_size, sizeof(header_size), &bytes_num, null_ptr) != G_IO_STATUS_NORMAL) || (bytes_num != sizeof(header_size))) + if ((g_io_channel_read_chars(in_file, (gchar *)&header_size, sizeof(header_size), &bytes_num, null_ptr) != + G_IO_STATUS_NORMAL) || + (bytes_num != sizeof(header_size))) { g_critical("Can't read header size"); return SC_FALSE; @@ -218,7 +214,9 @@ sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_ return SC_FALSE; } - if ((g_io_channel_read_chars(in_file, (gchar*)&header, sizeof(header), &bytes_num, null_ptr) != G_IO_STATUS_NORMAL) || (bytes_num != sizeof(header))) + if ((g_io_channel_read_chars(in_file, (gchar *)&header, sizeof(header), &bytes_num, null_ptr) != + G_IO_STATUS_NORMAL) || + (bytes_num != sizeof(header))) { g_critical("Can't read header of segments: %s", segments_path); return SC_FALSE; @@ -239,7 +237,7 @@ sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_ seg = sc_segment_new(i); segments[i] = seg; - g_io_channel_read_chars(in_file, (gchar*)seg->elements, SC_SEG_ELEMENTS_SIZE_BYTE, &bytes_num, null_ptr); + g_io_channel_read_chars(in_file, (gchar *)seg->elements, SC_SEG_ELEMENTS_SIZE_BYTE, &bytes_num, null_ptr); sc_segment_loaded(seg); if (bytes_num != SC_SEG_ELEMENTS_SIZE_BYTE) { @@ -247,7 +245,7 @@ sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_ is_valid = SC_FALSE; break; } - g_checksum_update(checksum, (guchar*)seg->elements, SC_SEG_ELEMENTS_SIZE_BYTE); + g_checksum_update(checksum, (guchar *)seg->elements, SC_SEG_ELEMENTS_SIZE_BYTE); } if (is_valid == SC_TRUE) @@ -257,7 +255,8 @@ sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_ if (bytes_num != SC_STORAGE_SEG_CHECKSUM_SIZE) is_valid = SC_FALSE; else - is_valid = (memcmp(calculated_checksum, header.checksum, SC_STORAGE_SEG_CHECKSUM_SIZE) == 0) ? SC_TRUE : SC_FALSE; + is_valid = + (memcmp(calculated_checksum, header.checksum, SC_STORAGE_SEG_CHECKSUM_SIZE) == 0) ? SC_TRUE : SC_FALSE; } if (is_valid == SC_FALSE) @@ -302,10 +301,10 @@ static GIOChannel * _open_tmp_file(gchar ** tmp_file_name) return result; } -sc_bool sc_fs_storage_write_to_path(sc_segment **segments) +sc_bool sc_fs_storage_write_to_path(sc_segment ** segments) { sc_uint32 idx = 0, header_size = 0; - const sc_segment *segment = 0; + const sc_segment * segment = 0; sc_fs_storage_segments_header header; GChecksum * checksum = null_ptr; GIOChannel * output = null_ptr; @@ -340,9 +339,9 @@ sc_bool sc_fs_storage_write_to_path(sc_segment **segments) { segment = segments[idx]; if (segment == null_ptr) - break; // stop save, because we allocate segment in order + break; // stop save, because we allocate segment in order - g_checksum_update(checksum, (guchar*)segment->elements, SC_SEG_ELEMENTS_SIZE_BYTE); + g_checksum_update(checksum, (guchar *)segment->elements, SC_SEG_ELEMENTS_SIZE_BYTE); } header.segments_num = idx; @@ -350,14 +349,17 @@ sc_bool sc_fs_storage_write_to_path(sc_segment **segments) g_checksum_get_digest(checksum, header.checksum, &bytes); header_size = sizeof(header); - if (g_io_channel_write_chars(output, (gchar*)&header_size, sizeof(header_size), &bytes, null_ptr) != G_IO_STATUS_NORMAL || bytes != sizeof(header_size)) + if (g_io_channel_write_chars(output, (gchar *)&header_size, sizeof(header_size), &bytes, null_ptr) != + G_IO_STATUS_NORMAL || + bytes != sizeof(header_size)) { g_error("Can't write header size: %s", tmp_filename); result = SC_FALSE; goto clean; } - if (g_io_channel_write_chars(output, (gchar*)&header, header_size, &bytes, null_ptr) != G_IO_STATUS_NORMAL || bytes != header_size) + if (g_io_channel_write_chars(output, (gchar *)&header, header_size, &bytes, null_ptr) != G_IO_STATUS_NORMAL || + bytes != header_size) { g_error("Can't write header: %s", tmp_filename); result = SC_FALSE; @@ -369,7 +371,9 @@ sc_bool sc_fs_storage_write_to_path(sc_segment **segments) segment = segments[idx]; g_assert(segment != null_ptr); - if (g_io_channel_write_chars(output, (gchar*)segment->elements, SC_SEG_ELEMENTS_SIZE_BYTE, &bytes, null_ptr) != G_IO_STATUS_NORMAL || bytes != SC_SEG_ELEMENTS_SIZE_BYTE) + if (g_io_channel_write_chars(output, (gchar *)segment->elements, SC_SEG_ELEMENTS_SIZE_BYTE, &bytes, null_ptr) != + G_IO_STATUS_NORMAL || + bytes != SC_SEG_ELEMENTS_SIZE_BYTE) { g_error("Can't write segment %d into %s", idx, tmp_filename); result = SC_FALSE; @@ -399,20 +403,19 @@ sc_bool sc_fs_storage_write_to_path(sc_segment **segments) } clean: - { - if (tmp_filename) - g_free(tmp_filename); - if (checksum) - g_checksum_free(checksum); - if (output) - g_io_channel_shutdown(output, TRUE, null_ptr); - } +{ + if (tmp_filename) + g_free(tmp_filename); + if (checksum) + g_checksum_free(checksum); + if (output) + g_io_channel_shutdown(output, TRUE, null_ptr); +} return result; } - -sc_result sc_fs_storage_write_content(sc_addr addr, const sc_check_sum *check_sum, const sc_stream *stream) +sc_result sc_fs_storage_write_content(sc_addr addr, const sc_check_sum * check_sum, const sc_stream * stream) { if (sc_fm_write_stream(check_sum, stream) == SC_RESULT_OK) { @@ -424,28 +427,27 @@ sc_result sc_fs_storage_write_content(sc_addr addr, const sc_check_sum *check_su return SC_RESULT_ERROR_IO; } -sc_result sc_fs_storage_add_content_addr(sc_addr addr, const sc_check_sum *check_sum) +sc_result sc_fs_storage_add_content_addr(sc_addr addr, const sc_check_sum * check_sum) { return sc_fm_addr_ref_append(addr, check_sum); } -sc_result sc_fs_storage_remove_content_addr(sc_addr addr, const sc_check_sum *check_sum) +sc_result sc_fs_storage_remove_content_addr(sc_addr addr, const sc_check_sum * check_sum) { return sc_fm_addr_ref_remove(addr, check_sum); } -sc_result sc_fs_storage_find_links_with_content(const sc_check_sum *check_sum, sc_addr **result, sc_uint32 *result_count) +sc_result sc_fs_storage_find_links_with_content( + const sc_check_sum * check_sum, + sc_addr ** result, + sc_uint32 * result_count) { return sc_fm_find(check_sum, result, result_count); } -sc_result sc_fs_storage_get_checksum_content(const sc_check_sum *check_sum, sc_stream **stream) +sc_result sc_fs_storage_get_checksum_content(const sc_check_sum * check_sum, sc_stream ** stream) { *stream = sc_fm_read_stream_new(check_sum); return stream ? SC_RESULT_OK : SC_RESULT_ERROR_IO; } - - - - diff --git a/sc-memory/sc-core/sc-store/sc_fs_storage.h b/sc-memory/sc-core/sc-store/sc_fs_storage.h index bc7f075031..6bd2599b20 100644 --- a/sc-memory/sc-core/sc-store/sc_fs_storage.h +++ b/sc-memory/sc-core/sc-store/sc_fs_storage.h @@ -18,22 +18,22 @@ typedef struct _sc_fs_storage_segments_header sc_uint32 version; sc_uint16 segments_num; sc_uint64 timestamp; - sc_uint8 checksum[SC_STORAGE_SEG_CHECKSUM_SIZE]; // buffer size for sha 512 + sc_uint8 checksum[SC_STORAGE_SEG_CHECKSUM_SIZE]; // buffer size for sha 512 } sc_fs_storage_segments_header; -void _sc_fm_remove_dir(const char *path); -sc_bool _sc_fs_mkdirs(const char *path); +void _sc_fm_remove_dir(const char * path); +sc_bool _sc_fs_mkdirs(const char * path); /*! Initialize file system storage in specified path * @param path Path to store on file system. * @param clear Flag to initialize empty storage */ -sc_bool sc_fs_storage_initialize(const char *path, sc_bool clear); +sc_bool sc_fs_storage_initialize(const char * path, sc_bool clear); /*! Shutdown file system storage */ -sc_bool sc_fs_storage_shutdown(sc_segment **segments, sc_bool save_segments); +sc_bool sc_fs_storage_shutdown(sc_segment ** segments, sc_bool save_segments); /*! Load segments from file system storage * @@ -41,13 +41,13 @@ sc_bool sc_fs_storage_shutdown(sc_segment **segments, sc_bool save_segments); * @param segments_num Pointer to container for number of segments * It will be contain pointers to loaded segments. */ -sc_bool sc_fs_storage_read_from_path(sc_segment **segments, sc_uint32 *segments_num); +sc_bool sc_fs_storage_read_from_path(sc_segment ** segments, sc_uint32 * segments_num); /*! Save segments to file system * * @param segments Pointer to array that contains segment pointers to save. */ -sc_bool sc_fs_storage_write_to_path(sc_segment **segments); +sc_bool sc_fs_storage_write_to_path(sc_segment ** segments); // ------------------------------------------------- /*! Write specified stream as content @@ -56,21 +56,21 @@ sc_bool sc_fs_storage_write_to_path(sc_segment **segments); * @param stream Pointer to stream that contains data for saving * @return If content saved, then return SC_RESULT_OK; otherwise return one of error code */ -sc_result sc_fs_storage_write_content(sc_addr addr, const sc_check_sum *check_sum, const sc_stream *stream); +sc_result sc_fs_storage_write_content(sc_addr addr, const sc_check_sum * check_sum, const sc_stream * stream); /*! Add new sc-addr to content backward links * @param addr sc-addr to append to backward links * @param check_sum Checksum of content * @return If sc-addr has been written to backward links, then return SC_RESULT_OK; otherwise return error code */ -sc_result sc_fs_storage_add_content_addr(sc_addr addr, const sc_check_sum *check_sum); +sc_result sc_fs_storage_add_content_addr(sc_addr addr, const sc_check_sum * check_sum); /*! Remove sc-addr from content backward links * @param addr sc-addr to remove from backward links * @param check_sum Checksum of content * @return If sc-addr has been removed from backward links, then return SC_RESULT_OK; otherwise return error code */ -sc_result sc_fs_storage_remove_content_addr(sc_addr addr, const sc_check_sum *check_sum); +sc_result sc_fs_storage_remove_content_addr(sc_addr addr, const sc_check_sum * check_sum); /*! Search sc-link addrs by specified checksum * @param check_sum Checksum for search @@ -82,7 +82,10 @@ sc_result sc_fs_storage_remove_content_addr(sc_addr addr, const sc_check_sum *ch * sc-addrs * @attention \p result array need to be free after usage */ -sc_result sc_fs_storage_find_links_with_content(const sc_check_sum *check_sum, sc_addr **result, sc_uint32 *result_count); +sc_result sc_fs_storage_find_links_with_content( + const sc_check_sum * check_sum, + sc_addr ** result, + sc_uint32 * result_count); /*! Returns stream that contains content with specified checksum * @param check_sum Pointer to checksum for content data returning @@ -90,7 +93,6 @@ sc_result sc_fs_storage_find_links_with_content(const sc_check_sum *check_sum, s * @attention Returned pointer to stream need to be free after usage * @return If data by specified checksum found, then return SC_RESULT_OK; otherwise return SC_ERROR */ -sc_result sc_fs_storage_get_checksum_content(const sc_check_sum *check_sum, sc_stream **stream); - +sc_result sc_fs_storage_get_checksum_content(const sc_check_sum * check_sum, sc_stream ** stream); #endif diff --git a/sc-memory/sc-core/sc-store/sc_iterator.c b/sc-memory/sc-core/sc-store/sc_iterator.c index b03ff69769..03740276af 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator.c +++ b/sc-memory/sc-core/sc-store/sc_iterator.c @@ -8,16 +8,16 @@ #include -GSList *time_stamps_list = 0; -sc_uint32 time_stamps_count = 0; // store cached value to prevent sequence length calculation +GSList * time_stamps_list = 0; +sc_uint32 time_stamps_count = 0; // store cached value to prevent sequence length calculation #if SC_INTERNAL_THREADS_SUPPORT - GStaticMutex time_stamp_list_mutex = G_STATIC_MUTEX_INIT; -# define TIMESTAMP_LIST_LOCK g_static_mutex_lock(&time_stamp_list_mutex); -# define TIMESTAMP_LIST_UNLOCK g_static_mutex_unlock(&time_stamp_list_mutex); +GStaticMutex time_stamp_list_mutex = G_STATIC_MUTEX_INIT; +# define TIMESTAMP_LIST_LOCK g_static_mutex_lock(&time_stamp_list_mutex); +# define TIMESTAMP_LIST_UNLOCK g_static_mutex_unlock(&time_stamp_list_mutex); #else -# define TIMESTAMP_LIST_LOCK -# define TIMESTAMP_LIST_UNLOCK +# define TIMESTAMP_LIST_LOCK +# define TIMESTAMP_LIST_UNLOCK #endif gint _list_compare(gconstpointer a, gconstpointer b) @@ -25,10 +25,10 @@ gint _list_compare(gconstpointer a, gconstpointer b) sc_uint32 a_time = GPOINTER_TO_UINT(a); sc_uint32 b_time = GPOINTER_TO_UINT(b); - if (a_time == b_time) return 0; - if (a_time < b_time) return -1; + if (a_time == b_time) + return 0; + if (a_time < b_time) + return -1; return 1; } - - diff --git a/sc-memory/sc-core/sc-store/sc_iterator.h b/sc-memory/sc-core/sc-store/sc_iterator.h index 4100ac5911..bd321ff8a2 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator.h +++ b/sc-memory/sc-core/sc-store/sc_iterator.h @@ -16,4 +16,4 @@ * iterators. */ -#endif // SC_ITERATOR_H +#endif // SC_ITERATOR_H diff --git a/sc-memory/sc-core/sc-store/sc_iterator3.c b/sc-memory/sc-core/sc-store/sc_iterator3.c index 6b428c769d..50075032be 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator3.c +++ b/sc-memory/sc-core/sc-store/sc_iterator3.c @@ -13,12 +13,13 @@ const sc_uint32 s_max_iterator_lock_attempts = 10; -sc_iterator3* sc_iterator3_f_a_a_new(const sc_memory_context *ctx, sc_addr el, sc_type arc_type, sc_type end_type) +sc_iterator3 * sc_iterator3_f_a_a_new(const sc_memory_context * ctx, sc_addr el, sc_type arc_type, sc_type end_type) { sc_access_levels levels; sc_iterator_param p1, p2, p3; - if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) return 0; p1.is_type = SC_FALSE; @@ -33,12 +34,13 @@ sc_iterator3* sc_iterator3_f_a_a_new(const sc_memory_context *ctx, sc_addr el, s return sc_iterator3_new(ctx, sc_iterator3_f_a_a, p1, p2, p3); } -sc_iterator3* sc_iterator3_a_a_f_new(const sc_memory_context *ctx, sc_type beg_type, sc_type arc_type, sc_addr el) +sc_iterator3 * sc_iterator3_a_a_f_new(const sc_memory_context * ctx, sc_type beg_type, sc_type arc_type, sc_addr el) { sc_access_levels levels; sc_iterator_param p1, p2, p3; - if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) return 0; p1.is_type = SC_TRUE; @@ -53,11 +55,13 @@ sc_iterator3* sc_iterator3_a_a_f_new(const sc_memory_context *ctx, sc_type beg_t return sc_iterator3_new(ctx, sc_iterator3_a_a_f, p1, p2, p3); } -sc_iterator3* sc_iterator3_f_a_f_new(const sc_memory_context *ctx, sc_addr el_beg, sc_type arc_type, sc_addr el_end) +sc_iterator3 * sc_iterator3_f_a_f_new(const sc_memory_context * ctx, sc_addr el_beg, sc_type arc_type, sc_addr el_end) { sc_access_levels levels; - if (sc_storage_get_access_levels(ctx, el_beg, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || - sc_storage_get_access_levels(ctx, el_end, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, el_beg, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels) || + sc_storage_get_access_levels(ctx, el_end, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } @@ -76,10 +80,15 @@ sc_iterator3* sc_iterator3_f_a_f_new(const sc_memory_context *ctx, sc_addr el_be return sc_iterator3_new(ctx, sc_iterator3_f_a_f, p1, p2, p3); } -sc_iterator3 * sc_iterator3_a_f_a_new(sc_memory_context const * ctx, sc_type beg_type, sc_addr arc_addr, sc_type end_type) +sc_iterator3 * sc_iterator3_a_f_a_new( + sc_memory_context const * ctx, + sc_type beg_type, + sc_addr arc_addr, + sc_type end_type) { sc_access_levels levels; - if (sc_storage_get_access_levels(ctx, arc_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, arc_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } @@ -98,11 +107,17 @@ sc_iterator3 * sc_iterator3_a_f_a_new(sc_memory_context const * ctx, sc_type beg return sc_iterator3_new(ctx, sc_iterator3_a_f_a, p1, p2, p3); } -sc_iterator3 * sc_iterator3_f_f_a_new(sc_memory_context const * ctx, sc_addr beg_addr, sc_addr edge_addr, sc_type end_type) +sc_iterator3 * sc_iterator3_f_f_a_new( + sc_memory_context const * ctx, + sc_addr beg_addr, + sc_addr edge_addr, + sc_type end_type) { sc_access_levels levels; - if (sc_storage_get_access_levels(ctx, beg_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || - sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, beg_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels) || + sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } @@ -121,11 +136,17 @@ sc_iterator3 * sc_iterator3_f_f_a_new(sc_memory_context const * ctx, sc_addr beg return sc_iterator3_new(ctx, sc_iterator3_f_f_a, p1, p2, p3); } -sc_iterator3 * sc_iterator3_a_f_f_new(sc_memory_context const * ctx, sc_type beg_type, sc_addr edge_addr, sc_addr end_addr) +sc_iterator3 * sc_iterator3_a_f_f_new( + sc_memory_context const * ctx, + sc_type beg_type, + sc_addr edge_addr, + sc_addr end_addr) { sc_access_levels levels; - if (sc_storage_get_access_levels(ctx, end_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || - sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, end_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels) || + sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } @@ -144,12 +165,19 @@ sc_iterator3 * sc_iterator3_a_f_f_new(sc_memory_context const * ctx, sc_type beg return sc_iterator3_new(ctx, sc_iterator3_a_f_f, p1, p2, p3); } -sc_iterator3 * sc_iterator3_f_f_f_new(sc_memory_context const * ctx, sc_addr beg_addr, sc_addr edge_addr, sc_addr end_addr) +sc_iterator3 * sc_iterator3_f_f_f_new( + sc_memory_context const * ctx, + sc_addr beg_addr, + sc_addr edge_addr, + sc_addr end_addr) { sc_access_levels levels; - if (sc_storage_get_access_levels(ctx, beg_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || - sc_storage_get_access_levels(ctx, end_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || - sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) + if (sc_storage_get_access_levels(ctx, beg_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels) || + sc_storage_get_access_levels(ctx, end_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels) || + sc_storage_get_access_levels(ctx, edge_addr, &levels) != SC_RESULT_OK || + !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } @@ -168,17 +196,15 @@ sc_iterator3 * sc_iterator3_f_f_f_new(sc_memory_context const * ctx, sc_addr beg return sc_iterator3_new(ctx, sc_iterator3_f_f_f, p1, p2, p3); } -sc_bool _sc_iterator_ref_element(const sc_memory_context *ctx, sc_addr addr) +sc_bool _sc_iterator_ref_element(const sc_memory_context * ctx, sc_addr addr) { - sc_element *el = 0; + sc_element * el = 0; sc_uint16 a = 0; while (a < 1000) { STORAGE_CHECK_CALL(sc_storage_element_lock(addr, &el)); - if (el != null_ptr && - sc_element_is_request_deletion(el) == SC_FALSE && - el->flags.type != 0) + if (el != null_ptr && sc_element_is_request_deletion(el) == SC_FALSE && el->flags.type != 0) { sc_storage_element_ref(addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(addr)); @@ -193,78 +219,70 @@ sc_bool _sc_iterator_ref_element(const sc_memory_context *ctx, sc_addr addr) return SC_FALSE; } -sc_iterator3* sc_iterator3_new(const sc_memory_context *ctx, sc_iterator3_type type, sc_iterator_param p1, sc_iterator_param p2, sc_iterator_param p3) +sc_iterator3 * sc_iterator3_new( + const sc_memory_context * ctx, + sc_iterator3_type type, + sc_iterator_param p1, + sc_iterator_param p2, + sc_iterator_param p3) { // check types if (type >= sc_iterator3_count) - return (sc_iterator3*)0; + return (sc_iterator3 *)0; // check params with template switch (type) { - case sc_iterator3_f_a_a: - if (p1.is_type || !p2.is_type || !p3.is_type || - _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE - ) + if (p1.is_type || !p2.is_type || !p3.is_type || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_a_a_f: - if (!p1.is_type || !p2.is_type || p3.is_type || - _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE - ) + if (!p1.is_type || !p2.is_type || p3.is_type || _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_f_a_f: - if (p1.is_type || !p2.is_type || p3.is_type || - _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || - _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE - ) + if (p1.is_type || !p2.is_type || p3.is_type || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || + _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_a_f_a: - if (!p1.is_type || p2.is_type || !p3.is_type || - _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE - ) + if (!p1.is_type || p2.is_type || !p3.is_type || _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_f_f_a: - if (p1.is_type || p2.is_type || !p3.is_type || - _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || + if (p1.is_type || p2.is_type || !p3.is_type || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_a_f_f: - if (!p1.is_type || p2.is_type || p3.is_type || - _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE || + if (!p1.is_type || p2.is_type || p3.is_type || _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE || _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; case sc_iterator3_f_f_f: - if (p1.is_type || p2.is_type || p3.is_type || - _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || - _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE || - _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE) + if (p1.is_type || p2.is_type || p3.is_type || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || + _sc_iterator_ref_element(ctx, p2.addr) != SC_TRUE || _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE) { - return (sc_iterator3*)0; + return (sc_iterator3 *)0; } break; @@ -272,7 +290,7 @@ sc_iterator3* sc_iterator3_new(const sc_memory_context *ctx, sc_iterator3_type t break; }; - sc_iterator3 *it = g_new0(sc_iterator3, 1); + sc_iterator3 * it = g_new0(sc_iterator3, 1); it->params[0] = p1; it->params[1] = p2; @@ -285,14 +303,14 @@ sc_iterator3* sc_iterator3_new(const sc_memory_context *ctx, sc_iterator3_type t return it; } -void sc_iterator3_free(sc_iterator3 *it) +void sc_iterator3_free(sc_iterator3 * it) { if (it == null_ptr) return; if ((it->finished == SC_FALSE) && SC_ADDR_IS_NOT_EMPTY(it->results[1])) { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->results[1], &el)); g_assert(el != null_ptr); sc_storage_element_unref(it->results[1]); @@ -337,7 +355,7 @@ void sc_iterator3_free(sc_iterator3 *it) g_free(it); } -sc_bool sc_iterator_param_compare(sc_element *el, sc_addr addr, sc_iterator_param param) +sc_bool sc_iterator_param_compare(sc_element * el, sc_addr addr, sc_iterator_param param) { g_assert(el != 0); @@ -349,8 +367,7 @@ sc_bool sc_iterator_param_compare(sc_element *el, sc_addr addr, sc_iterator_para return SC_FALSE; } - -sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) +sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 * it) { sc_addr arc_addr; SC_ADDR_MAKE_EMPTY(arc_addr); @@ -360,7 +377,7 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) // try to find first output arc if (SC_ADDR_IS_EMPTY(it->results[1])) { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->params[0].addr, &el)); g_assert(el != null_ptr); arc_addr = el->first_out_arc; @@ -368,7 +385,7 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) } else { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->results[1], &el)); g_assert(el != null_ptr); arc_addr = el->arc.next_out_arc; @@ -379,7 +396,7 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) // iterate throught output arcs while (SC_ADDR_IS_NOT_EMPTY(arc_addr)) { - sc_element *el = 0; + sc_element * el = 0; // lock required elements to prevent deadlock with deletion while (el == null_ptr) STORAGE_CHECK_CALL(sc_storage_element_lock_try(arc_addr, s_max_iterator_lock_attempts, &el)); @@ -404,8 +421,7 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) if (sc_iterator_compare_type(arc_type, it->params[1].type) && sc_iterator_compare_type(el_type, it->params[2].type) && sc_access_lvl_check_read(it->ctx->access_levels, arc_access) && - sc_access_lvl_check_read(it->ctx->access_levels, end_access) - ) + sc_access_lvl_check_read(it->ctx->access_levels, end_access)) { // store found result it->results[1] = arc_addr; @@ -413,7 +429,8 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) return SC_TRUE; } - } else + } + else { sc_storage_element_unref(arc_addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(arc_addr)); @@ -428,7 +445,7 @@ sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) return SC_FALSE; } -sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) +sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 * it) { sc_addr arc_addr; @@ -440,7 +457,7 @@ sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) // try to find first input arc if (SC_ADDR_IS_EMPTY(it->results[1])) { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->params[2].addr, &el)); g_assert(el != null_ptr); arc_addr = el->first_in_arc; @@ -448,7 +465,7 @@ sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) } else { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->results[1], &el)); g_assert(el != null_ptr); arc_addr = el->arc.next_in_arc; @@ -459,7 +476,7 @@ sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) // trying to find input arc, that created before iterator, and wasn't deleted while (SC_ADDR_IS_NOT_EMPTY(arc_addr)) { - sc_element *el = 0; + sc_element * el = 0; while (el == null_ptr) STORAGE_CHECK_CALL(sc_storage_element_lock_try(arc_addr, s_max_iterator_lock_attempts, &el)); @@ -474,16 +491,15 @@ sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) STORAGE_CHECK_CALL(sc_storage_element_unlock(arc_addr)); - if (SC_ADDR_IS_EQUAL(it->params[0].addr, arc_begin) && - sc_iterator_compare_type(arc_type, it->params[1].type) && - sc_access_lvl_check_read(it->ctx->access_levels, arc_access) - ) + if (SC_ADDR_IS_EQUAL(it->params[0].addr, arc_begin) && sc_iterator_compare_type(arc_type, it->params[1].type) && + sc_access_lvl_check_read(it->ctx->access_levels, arc_access)) { // store found result it->results[1] = arc_addr; return SC_TRUE; } - } else + } + else { sc_storage_element_unref(arc_addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(arc_addr)); @@ -498,24 +514,25 @@ sc_bool _sc_iterator3_f_a_f_next(sc_iterator3 *it) return SC_FALSE; } -sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 *it) +sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 * it) { sc_addr arc_addr; SC_ADDR_MAKE_EMPTY(arc_addr) - it->results[2] = it->params[2].addr; + it->results[2] = it->params[2].addr; // try to find first input arc if (SC_ADDR_IS_EMPTY(it->results[1])) { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->params[2].addr, &el)); g_assert(el != null_ptr); arc_addr = el->first_in_arc; STORAGE_CHECK_CALL(sc_storage_element_unlock(it->params[2].addr)); - }else + } + else { - sc_element *el = 0; + sc_element * el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->results[1], &el)); g_assert(el != null_ptr); arc_addr = el->arc.next_in_arc; @@ -526,7 +543,7 @@ sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 *it) // trying to find input arc, that created before iterator, and wasn't deleted while (SC_ADDR_IS_NOT_EMPTY(arc_addr)) { - sc_element *el = 0; + sc_element * el = 0; while (el == null_ptr) STORAGE_CHECK_CALL(sc_storage_element_lock_try(arc_addr, s_max_iterator_lock_attempts, &el)); @@ -550,8 +567,7 @@ sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 *it) if (sc_iterator_compare_type(arc_type, it->params[1].type) && sc_iterator_compare_type(el_type, it->params[0].type) && sc_access_lvl_check_read(it->ctx->access_levels, arc_access) && - sc_access_lvl_check_read(it->ctx->access_levels, begin_access) - ) + sc_access_lvl_check_read(it->ctx->access_levels, begin_access)) { // store found result it->results[1] = arc_addr; @@ -559,7 +575,8 @@ sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 *it) return SC_TRUE; } - } else + } + else { sc_storage_element_unref(arc_addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(arc_addr)); @@ -670,14 +687,13 @@ sc_bool _sc_iterator3_f_f_f_next(sc_iterator3 * it) return SC_FALSE; } -sc_bool sc_iterator3_next(sc_iterator3 *it) +sc_bool sc_iterator3_next(sc_iterator3 * it) { if ((it == null_ptr) || (it->finished == SC_TRUE)) return SC_FALSE; switch (it->type) { - case sc_iterator3_f_a_a: return _sc_iterator3_f_a_a_next(it); @@ -706,7 +722,7 @@ sc_bool sc_iterator3_next(sc_iterator3 *it) return SC_FALSE; } -sc_addr sc_iterator3_value(sc_iterator3 *it, sc_uint vid) +sc_addr sc_iterator3_value(sc_iterator3 * it, sc_uint vid) { g_assert(it != 0); g_assert(vid < 3); diff --git a/sc-memory/sc-core/sc-store/sc_iterator3.h b/sc-memory/sc-core/sc-store/sc_iterator3.h index e2255c0a50..242b53ecc0 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator3.h +++ b/sc-memory/sc-core/sc-store/sc_iterator3.h @@ -11,14 +11,13 @@ #include "sc_types.h" #include "sc_element.h" - //! sc-iterator types typedef enum { - sc_iterator3_f_a_a = 0, // outgoing edges - sc_iterator3_a_a_f, // ingoing edges - sc_iterator3_f_a_f, // edge between source and target - sc_iterator3_a_f_a, // find source/target elements of edge + sc_iterator3_f_a_a = 0, // outgoing edges + sc_iterator3_a_a_f, // ingoing edges + sc_iterator3_f_a_f, // edge between source and target + sc_iterator3_a_f_a, // find source/target elements of edge // just for clean template search sc_iterator3_f_f_a, sc_iterator3_a_f_f, @@ -43,10 +42,10 @@ struct _sc_iterator_param */ struct _sc_iterator3 { - sc_iterator3_type type; // iterator type (search template) + sc_iterator3_type type; // iterator type (search template) sc_iterator_param params[3]; // parameters array sc_addr results[3]; // results array (same size as params) - const sc_memory_context *ctx; // pointer to used memory context + const sc_memory_context * ctx; // pointer to used memory context sc_bool finished; }; @@ -56,7 +55,11 @@ struct _sc_iterator3 * @param end_type Type of end element for output arcs, to iterate * @return If iterator created, then return pointer to it; otherwise return null */ -_SC_EXTERN sc_iterator3 * sc_iterator3_f_a_a_new(sc_memory_context const * ctx, sc_addr el, sc_type arc_type, sc_type end_type); +_SC_EXTERN sc_iterator3 * sc_iterator3_f_a_a_new( + sc_memory_context const * ctx, + sc_addr el, + sc_type arc_type, + sc_type end_type); /*! Create iterator to find input arcs for specified element * @param beg_type Type of begin element for input arcs, to iterate @@ -64,7 +67,11 @@ _SC_EXTERN sc_iterator3 * sc_iterator3_f_a_a_new(sc_memory_context const * ctx, * @param el sc-addr of element to iterate input arcs * @return If iterator created, then return pointer to it; otherwise return null */ -_SC_EXTERN sc_iterator3 * sc_iterator3_a_a_f_new(sc_memory_context const * ctx, sc_type beg_type, sc_type arc_type, sc_addr el); +_SC_EXTERN sc_iterator3 * sc_iterator3_a_a_f_new( + sc_memory_context const * ctx, + sc_type beg_type, + sc_type arc_type, + sc_addr el); /*! Create iterator to find arcs between two specified elements * @param el_beg sc-addr of begin element @@ -72,25 +79,51 @@ _SC_EXTERN sc_iterator3 * sc_iterator3_a_a_f_new(sc_memory_context const * ctx, * @param el_end sc-addr of end element * @return If iterator created, then return pointer to it; otherwise return null */ -_SC_EXTERN sc_iterator3 * sc_iterator3_f_a_f_new(sc_memory_context const * ctx, sc_addr el_beg, sc_type arc_type, sc_addr el_end); +_SC_EXTERN sc_iterator3 * sc_iterator3_f_a_f_new( + sc_memory_context const * ctx, + sc_addr el_beg, + sc_type arc_type, + sc_addr el_end); /*! Create iterator to determine edge source and target */ -_SC_EXTERN sc_iterator3 * sc_iterator3_a_f_a_new(sc_memory_context const * ctx, sc_type beg_type, sc_addr arc_addr, sc_type end_type); +_SC_EXTERN sc_iterator3 * sc_iterator3_a_f_a_new( + sc_memory_context const * ctx, + sc_type beg_type, + sc_addr arc_addr, + sc_type end_type); // Requried for clean template search algorithm -_SC_EXTERN sc_iterator3 * sc_iterator3_f_f_a_new(sc_memory_context const * ctx, sc_addr beg_addr, sc_addr edge_addr, sc_type end_type); -_SC_EXTERN sc_iterator3 * sc_iterator3_a_f_f_new(sc_memory_context const * ctx, sc_type beg_type, sc_addr edge_addr, sc_addr end_addr); -_SC_EXTERN sc_iterator3 * sc_iterator3_f_f_f_new(sc_memory_context const * ctx, sc_addr beg_addr, sc_addr edge_addr, sc_addr end_addr); +_SC_EXTERN sc_iterator3 * sc_iterator3_f_f_a_new( + sc_memory_context const * ctx, + sc_addr beg_addr, + sc_addr edge_addr, + sc_type end_type); +_SC_EXTERN sc_iterator3 * sc_iterator3_a_f_f_new( + sc_memory_context const * ctx, + sc_type beg_type, + sc_addr edge_addr, + sc_addr end_addr); +_SC_EXTERN sc_iterator3 * sc_iterator3_f_f_f_new( + sc_memory_context const * ctx, + sc_addr beg_addr, + sc_addr edge_addr, + sc_addr end_addr); /*! Create new sc-iterator-3 * @param type Iterator type (search template) * @param p1 First iterator parameter * @param p2 Second iterator parameter * @param p3 Third iterator parameter - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator3 * sc_iterator3_new(sc_memory_context const * ctx, sc_iterator3_type type, sc_iterator_param p1, sc_iterator_param p2, sc_iterator_param p3); +_SC_EXTERN sc_iterator3 * sc_iterator3_new( + sc_memory_context const * ctx, + sc_iterator3_type type, + sc_iterator_param p1, + sc_iterator_param p2, + sc_iterator_param p3); /*! Destroy iterator and free allocated memory * @param it Pointer to sc-iterator that need to be destroyed diff --git a/sc-memory/sc-core/sc-store/sc_iterator5.c b/sc-memory/sc-core/sc-store/sc_iterator5.c index 51702b6f2a..7f97aeb6d5 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator5.c +++ b/sc-memory/sc-core/sc-store/sc_iterator5.c @@ -9,39 +9,45 @@ #include -sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_iterator5_type type, sc_iterator_param p1, sc_iterator_param p2, sc_iterator_param p3, sc_iterator_param p4, sc_iterator_param p5) +sc_iterator5 * sc_iterator5_new( + const sc_memory_context * ctx, + sc_iterator5_type type, + sc_iterator_param p1, + sc_iterator_param p2, + sc_iterator_param p3, + sc_iterator_param p4, + sc_iterator_param p5) { - // check params with template switch (type) { case sc_iterator5_f_a_a_a_f: if (p1.is_type || !p2.is_type || !p3.is_type || !p4.is_type || p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; case sc_iterator5_a_a_f_a_f: if (!p1.is_type || !p2.is_type || p3.is_type || !p4.is_type || p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; case sc_iterator5_f_a_f_a_f: if (p1.is_type || !p2.is_type || p3.is_type || !p4.is_type || p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; case sc_iterator5_f_a_f_a_a: if (p1.is_type || !p2.is_type || p3.is_type || !p4.is_type || !p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; case sc_iterator5_f_a_a_a_a: if (p1.is_type || !p2.is_type || !p3.is_type || !p4.is_type || !p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; case sc_iterator5_a_a_f_a_a: if (!p1.is_type || !p2.is_type || p3.is_type || !p4.is_type || !p5.is_type) - return (sc_iterator5*)null_ptr; + return (sc_iterator5 *)null_ptr; break; }; - sc_iterator5 *it = g_new0(sc_iterator5, 1); + sc_iterator5 * it = g_new0(sc_iterator5, 1); it->params[0] = p1; it->params[1] = p2; @@ -56,7 +62,7 @@ sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_iterator5_type t switch (type) { case sc_iterator5_f_a_a_a_f: - it->it_main = sc_iterator3_f_a_a_new(ctx, p1.addr ,p2.type, p3.type); + it->it_main = sc_iterator3_f_a_a_new(ctx, p1.addr, p2.type, p3.type); it->it_attr = null_ptr; it->results[0] = p1.addr; it->results[4] = p5.addr; @@ -81,7 +87,7 @@ sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_iterator5_type t it->results[2] = p3.addr; break; case sc_iterator5_a_a_f_a_a: - it->it_main = sc_iterator3_a_a_f_new(ctx, p1.type,p2.type,p3.addr); + it->it_main = sc_iterator3_a_a_f_new(ctx, p1.type, p2.type, p3.addr); it->it_attr = null_ptr; it->results[2] = p3.addr; break; @@ -101,9 +107,15 @@ sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_iterator5_type t return it; } -sc_iterator5* sc_iterator5_f_a_a_a_f_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_type p3, sc_type p4, sc_addr p5) +sc_iterator5 * sc_iterator5_f_a_a_a_f_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_type p3, + sc_type p4, + sc_addr p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_FALSE; _p1.addr = p1; _p2.is_type = SC_TRUE; @@ -118,9 +130,15 @@ sc_iterator5* sc_iterator5_f_a_a_a_f_new(const sc_memory_context *ctx, sc_addr p return sc_iterator5_new(ctx, sc_iterator5_f_a_a_a_f, _p1, _p2, _p3, _p4, _p5); } -sc_iterator5* sc_iterator5_a_a_f_a_f_new(const sc_memory_context *ctx, sc_type p1, sc_type p2, sc_addr p3, sc_type p4, sc_addr p5) +sc_iterator5 * sc_iterator5_a_a_f_a_f_new( + const sc_memory_context * ctx, + sc_type p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_addr p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_TRUE; _p1.type = p1; _p2.is_type = SC_TRUE; @@ -135,9 +153,15 @@ sc_iterator5* sc_iterator5_a_a_f_a_f_new(const sc_memory_context *ctx, sc_type p return sc_iterator5_new(ctx, sc_iterator5_a_a_f_a_f, _p1, _p2, _p3, _p4, _p5); } -sc_iterator5* sc_iterator5_f_a_f_a_f_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_addr p3, sc_type p4, sc_addr p5) +sc_iterator5 * sc_iterator5_f_a_f_a_f_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_addr p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_FALSE; _p1.addr = p1; _p2.is_type = SC_TRUE; @@ -152,9 +176,15 @@ sc_iterator5* sc_iterator5_f_a_f_a_f_new(const sc_memory_context *ctx, sc_addr p return sc_iterator5_new(ctx, sc_iterator5_f_a_f_a_f, _p1, _p2, _p3, _p4, _p5); } -sc_iterator5* sc_iterator5_f_a_f_a_a_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_addr p3, sc_type p4, sc_type p5) +sc_iterator5 * sc_iterator5_f_a_f_a_a_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_type p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_FALSE; _p1.addr = p1; _p2.is_type = SC_TRUE; @@ -169,9 +199,15 @@ sc_iterator5* sc_iterator5_f_a_f_a_a_new(const sc_memory_context *ctx, sc_addr p return sc_iterator5_new(ctx, sc_iterator5_f_a_f_a_a, _p1, _p2, _p3, _p4, _p5); } -sc_iterator5* sc_iterator5_f_a_a_a_a_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_type p3, sc_type p4, sc_type p5) +sc_iterator5 * sc_iterator5_f_a_a_a_a_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_type p3, + sc_type p4, + sc_type p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_FALSE; _p1.addr = p1; _p2.is_type = SC_TRUE; @@ -186,9 +222,15 @@ sc_iterator5* sc_iterator5_f_a_a_a_a_new(const sc_memory_context *ctx, sc_addr p return sc_iterator5_new(ctx, sc_iterator5_f_a_a_a_a, _p1, _p2, _p3, _p4, _p5); } -sc_iterator5* sc_iterator5_a_a_f_a_a_new(const sc_memory_context *ctx, sc_type p1, sc_type p2, sc_addr p3, sc_type p4, sc_type p5) +sc_iterator5 * sc_iterator5_a_a_f_a_a_new( + const sc_memory_context * ctx, + sc_type p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_type p5) { - sc_iterator_param _p1,_p2,_p3,_p4,_p5; + sc_iterator_param _p1, _p2, _p3, _p4, _p5; _p1.is_type = SC_TRUE; _p1.type = p1; _p2.is_type = SC_TRUE; @@ -203,8 +245,7 @@ sc_iterator5* sc_iterator5_a_a_f_a_a_new(const sc_memory_context *ctx, sc_type p return sc_iterator5_new(ctx, sc_iterator5_a_a_f_a_a, _p1, _p2, _p3, _p4, _p5); } - -void sc_iterator5_free(sc_iterator5 *it) +void sc_iterator5_free(sc_iterator5 * it) { if (it == null_ptr) return; @@ -216,9 +257,8 @@ void sc_iterator5_free(sc_iterator5 *it) g_free(it); } -sc_bool _sc_iterator5_a_a_f_a_f_next(sc_iterator5 *it) +sc_bool _sc_iterator5_a_a_f_a_f_next(sc_iterator5 * it) { - SC_ADDR_MAKE_EMPTY(it->results[0]) SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[3]) @@ -226,8 +266,8 @@ sc_bool _sc_iterator5_a_a_f_a_f_next(sc_iterator5 *it) if (it->it_attr != null_ptr && sc_iterator3_next(it->it_attr)) { it->results[0] = it->it_main->results[0]; - it->results[1]=it->it_main->results[1]; - it->results[3]=it->it_attr->results[1]; + it->results[1] = it->it_main->results[1]; + it->results[3] = it->it_attr->results[1]; return SC_TRUE; } else @@ -249,10 +289,7 @@ sc_bool _sc_iterator5_a_a_f_a_f_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_f_a_f_new(it->ctx, - it->params[4].addr, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_f_a_f_new(it->ctx, it->params[4].addr, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -265,7 +302,7 @@ sc_bool _sc_iterator5_a_a_f_a_f_next(sc_iterator5 *it) return SC_FALSE; } -sc_bool _sc_iterator5_f_a_a_a_f_next(sc_iterator5 *it) +sc_bool _sc_iterator5_f_a_a_a_f_next(sc_iterator5 * it) { SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[2]) @@ -297,10 +334,7 @@ sc_bool _sc_iterator5_f_a_a_a_f_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_f_a_f_new(it->ctx, - it->params[4].addr, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_f_a_f_new(it->ctx, it->params[4].addr, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -313,7 +347,7 @@ sc_bool _sc_iterator5_f_a_a_a_f_next(sc_iterator5 *it) return SC_FALSE; } -sc_bool _sc_iterator5_f_a_f_a_f_next(sc_iterator5 *it) +sc_bool _sc_iterator5_f_a_f_a_f_next(sc_iterator5 * it) { SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[3]) @@ -343,10 +377,7 @@ sc_bool _sc_iterator5_f_a_f_a_f_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_f_a_f_new(it->ctx, - it->params[4].addr, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_f_a_f_new(it->ctx, it->params[4].addr, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -358,7 +389,7 @@ sc_bool _sc_iterator5_f_a_f_a_f_next(sc_iterator5 *it) return SC_FALSE; } -sc_bool _sc_iterator5_f_a_f_a_a_next(sc_iterator5 *it) +sc_bool _sc_iterator5_f_a_f_a_a_next(sc_iterator5 * it) { SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[3]) @@ -390,10 +421,7 @@ sc_bool _sc_iterator5_f_a_f_a_a_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_a_a_f_new(it->ctx, - it->params[4].type, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_a_a_f_new(it->ctx, it->params[4].type, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -406,7 +434,7 @@ sc_bool _sc_iterator5_f_a_f_a_a_next(sc_iterator5 *it) return SC_FALSE; } -sc_bool _sc_iterator5_f_a_a_a_a_next(sc_iterator5 *it) +sc_bool _sc_iterator5_f_a_a_a_a_next(sc_iterator5 * it) { SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[2]) @@ -440,10 +468,7 @@ sc_bool _sc_iterator5_f_a_a_a_a_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_a_a_f_new(it->ctx, - it->params[4].type, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_a_a_f_new(it->ctx, it->params[4].type, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -457,9 +482,8 @@ sc_bool _sc_iterator5_f_a_a_a_a_next(sc_iterator5 *it) return SC_FALSE; } -sc_bool _sc_iterator5_a_a_f_a_a_next(sc_iterator5 *it) +sc_bool _sc_iterator5_a_a_f_a_a_next(sc_iterator5 * it) { - SC_ADDR_MAKE_EMPTY(it->results[1]) SC_ADDR_MAKE_EMPTY(it->results[0]) SC_ADDR_MAKE_EMPTY(it->results[3]) @@ -491,10 +515,7 @@ sc_bool _sc_iterator5_a_a_f_a_a_next(sc_iterator5 *it) if (!sc_iterator3_next(it->it_main)) return SC_FALSE; - it->it_attr = sc_iterator3_a_a_f_new(it->ctx, - it->params[4].type, - it->params[3].type, - it->it_main->results[1]); + it->it_attr = sc_iterator3_a_a_f_new(it->ctx, it->params[4].type, it->params[3].type, it->it_main->results[1]); if (it->it_attr == null_ptr) return SC_FALSE; } @@ -508,8 +529,7 @@ sc_bool _sc_iterator5_a_a_f_a_a_next(sc_iterator5 *it) return SC_FALSE; } - -sc_bool sc_iterator5_next(sc_iterator5 *it) +sc_bool sc_iterator5_next(sc_iterator5 * it) { if (it == null_ptr) return SC_FALSE; @@ -538,7 +558,7 @@ sc_bool sc_iterator5_next(sc_iterator5 *it) return SC_FALSE; } -sc_addr sc_iterator5_value(sc_iterator5 *it, sc_uint vid) +sc_addr sc_iterator5_value(sc_iterator5 * it, sc_uint vid) { g_assert(it != 0); g_assert(vid < 5); diff --git a/sc-memory/sc-core/sc-store/sc_iterator5.h b/sc-memory/sc-core/sc-store/sc_iterator5.h index efa8f926eb..6c95c7d2f4 100644 --- a/sc-memory/sc-core/sc-store/sc_iterator5.h +++ b/sc-memory/sc-core/sc-store/sc_iterator5.h @@ -27,16 +27,22 @@ struct _sc_iterator5 sc_iterator5_type type; // iterator type (search template) sc_iterator_param params[5]; // parameters array sc_addr results[5]; // results array (same size as params) - sc_iterator3* it_main; // iterator of main arc - sc_iterator3* it_attr; // iterator of attribute arc + sc_iterator3 * it_main; // iterator of main arc + sc_iterator3 * it_attr; // iterator of attribute arc sc_uint32 time_stamp; // iterator time stamp - const sc_memory_context *ctx; // pointer to used memory context + const sc_memory_context * ctx; // pointer to used memory context }; typedef struct _sc_iterator5 sc_iterator5; -_SC_EXTERN sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_iterator5_type type, - sc_iterator_param p1, sc_iterator_param p2, sc_iterator_param p3, sc_iterator_param p4, sc_iterator_param p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_new( + const sc_memory_context * ctx, + sc_iterator5_type type, + sc_iterator_param p1, + sc_iterator_param p2, + sc_iterator_param p3, + sc_iterator_param p4, + sc_iterator_param p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -45,9 +51,16 @@ _SC_EXTERN sc_iterator5* sc_iterator5_new(const sc_memory_context *ctx, sc_itera * @param p3 sc-addr of third element in construction * @param p4 4th element type * @param p5 sc-addr of 5th element in construction - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_a_a_f_a_f_new(const sc_memory_context *ctx, sc_type p1, sc_type p2, sc_addr p3, sc_type p4, sc_addr p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_a_a_f_a_f_new( + const sc_memory_context * ctx, + sc_type p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_addr p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -56,9 +69,16 @@ _SC_EXTERN sc_iterator5* sc_iterator5_a_a_f_a_f_new(const sc_memory_context *ctx * @param p3 Third element type * @param p4 4-th element type * @param p5 sc-addr of 5th element in construction - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_f_a_a_a_f_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_type p3, sc_type p4, sc_addr p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_f_a_a_a_f_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_type p3, + sc_type p4, + sc_addr p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -67,9 +87,16 @@ _SC_EXTERN sc_iterator5* sc_iterator5_f_a_a_a_f_new(const sc_memory_context *ctx * @param p3 sc-addr of third element in construction * @param p4 4-th element type * @param p5 sc-addr of 5th element in construction - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_f_a_f_a_f_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_addr p3, sc_type p4, sc_addr p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_f_a_f_a_f_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_addr p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -78,9 +105,16 @@ _SC_EXTERN sc_iterator5* sc_iterator5_f_a_f_a_f_new(const sc_memory_context *ctx * @param p3 sc-addr of first element in construction * @param p4 4-th element type * @param p5 5-th element type - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_f_a_f_a_a_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_addr p3, sc_type p4, sc_type p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_f_a_f_a_a_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_type p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -89,9 +123,16 @@ _SC_EXTERN sc_iterator5* sc_iterator5_f_a_f_a_a_new(const sc_memory_context *ctx * @param p3 Third element type * @param p4 4-th element type * @param p5 5-th element type - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_f_a_a_a_a_new(const sc_memory_context *ctx, sc_addr p1, sc_type p2, sc_type p3, sc_type p4, sc_type p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_f_a_a_a_a_new( + const sc_memory_context * ctx, + sc_addr p1, + sc_type p2, + sc_type p3, + sc_type p4, + sc_type p5); /*! Create new sc-iterator5 * @param type Iterator type (search template) @@ -100,27 +141,34 @@ _SC_EXTERN sc_iterator5* sc_iterator5_f_a_a_a_a_new(const sc_memory_context *ctx * @param p3 sc-addr of third element in construction * @param p4 4-th element type * @param p5 5-th element type - * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a sc-iterator-3, then return 0 + * @return Pointer to created iterator. If parameters invalid for specified iterator type, or type is not a + * sc-iterator-3, then return 0 */ -_SC_EXTERN sc_iterator5* sc_iterator5_a_a_f_a_a_new(const sc_memory_context *ctx, sc_type p1, sc_type p2, sc_addr p3, sc_type p4, sc_type p5); +_SC_EXTERN sc_iterator5 * sc_iterator5_a_a_f_a_a_new( + const sc_memory_context * ctx, + sc_type p1, + sc_type p2, + sc_addr p3, + sc_type p4, + sc_type p5); /*! Go to next iterator result * @param it Pointer to iterator that we need to go next result * @return Return SC_TRUE, if iterator moved to new results; otherwise return SC_FALSE. * example: while(sc_iterator_next(it)) { } */ -_SC_EXTERN sc_bool sc_iterator5_next(sc_iterator5 *it); +_SC_EXTERN sc_bool sc_iterator5_next(sc_iterator5 * it); /*! Get iterator value * @param it Pointer to iterator for getting value * @param vid Value id (can't be more that 5 for sc-iterator5) * @return Return sc-addr of search result value */ -_SC_EXTERN sc_addr sc_iterator5_value(sc_iterator5 *it, sc_uint vid); +_SC_EXTERN sc_addr sc_iterator5_value(sc_iterator5 * it, sc_uint vid); /*! Destroy iterator and free allocated memory * @param it Pointer to sc-iterator that need to be destroyed */ -_SC_EXTERN void sc_iterator5_free(sc_iterator5 *it); +_SC_EXTERN void sc_iterator5_free(sc_iterator5 * it); -#endif // SC_ITERATOR5_H +#endif // SC_ITERATOR5_H diff --git a/sc-memory/sc-core/sc-store/sc_link_helpers.c b/sc-memory/sc-core/sc-store/sc_link_helpers.c index 4f0b04a5a5..be38547f2e 100644 --- a/sc-memory/sc-core/sc-store/sc_link_helpers.c +++ b/sc-memory/sc-core/sc-store/sc_link_helpers.c @@ -14,12 +14,12 @@ #define SC_DEFAULT_CHECKSUM G_CHECKSUM_SHA256 -sc_bool sc_link_calculate_checksum(const sc_stream *stream, sc_check_sum *check_sum) +sc_bool sc_link_calculate_checksum(const sc_stream * stream, sc_check_sum * check_sum) { sc_char buffer[1024]; sc_uint32 data_read; - const gchar *result = 0; - GChecksum *checksum = g_checksum_new(SC_DEFAULT_CHECKSUM); + const gchar * result = 0; + GChecksum * checksum = g_checksum_new(SC_DEFAULT_CHECKSUM); g_assert(stream != 0); g_assert(check_sum != 0); @@ -35,7 +35,7 @@ sc_bool sc_link_calculate_checksum(const sc_stream *stream, sc_check_sum *check_ return SC_FALSE; } - g_checksum_update(checksum, (guchar*)buffer, data_read); + g_checksum_update(checksum, (guchar *)buffer, data_read); } // store results @@ -52,13 +52,10 @@ sc_bool sc_link_calculate_checksum(const sc_stream *stream, sc_check_sum *check_ return SC_TRUE; } -sc_bool sc_link_self_container_calculate_checksum(sc_element *el, sc_check_sum *sum) +sc_bool sc_link_self_container_calculate_checksum(sc_element * el, sc_check_sum * sum) { - sc_stream *stream = sc_stream_memory_new(&el->content.data[1], el->content.data[0], SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * stream = sc_stream_memory_new(&el->content.data[1], el->content.data[0], SC_STREAM_FLAG_READ, SC_FALSE); sc_bool r = sc_link_calculate_checksum(stream, sum); sc_stream_free(stream); return r; } - - - diff --git a/sc-memory/sc-core/sc-store/sc_link_helpers.h b/sc-memory/sc-core/sc-store/sc_link_helpers.h index e545f572c0..6c68d23250 100644 --- a/sc-memory/sc-core/sc-store/sc_link_helpers.h +++ b/sc-memory/sc-core/sc-store/sc_link_helpers.h @@ -10,21 +10,18 @@ #include "sc_types.h" #include "sc_stream.h" - /*! Caclulates checksum for data in stream * @param stream Pointer to data stream for checksum calculation * @param check_sum Pointer to stucture, that contains calculated checksum * @return If checksum calculated, then return SC_TRUE; otherwise return SC_FALSE */ -sc_bool sc_link_calculate_checksum(const sc_stream *stream, sc_check_sum *check_sum); - +sc_bool sc_link_calculate_checksum(const sc_stream * stream, sc_check_sum * check_sum); /*! Calculates checksum for sc-link, when it is self container for it's data * @param el Pointer to sc-link * @param sum Pointer to checksum structure to contain result * @return If checksum calculated, then return SC_TRUE; otherwise return SC_FALSE */ -sc_bool sc_link_self_container_calculate_checksum(sc_element *el, sc_check_sum *sum); - +sc_bool sc_link_self_container_calculate_checksum(sc_element * el, sc_check_sum * sum); #endif diff --git a/sc-memory/sc-core/sc-store/sc_platform.h b/sc-memory/sc-core/sc-store/sc_platform.h index 57fd4fcdc8..72b5718846 100644 --- a/sc-memory/sc-core/sc-store/sc_platform.h +++ b/sc-memory/sc-core/sc-store/sc_platform.h @@ -8,49 +8,47 @@ #define _sc_platform_h_ // Determine compiler -#define SC_COMPILER 0 -#define SC_COMPILER_GNU 1 -#define SC_COMPILER_CLANG 2 -#define SC_COMPILER_MSVC 3 +#define SC_COMPILER 0 +#define SC_COMPILER_GNU 1 +#define SC_COMPILER_CLANG 2 +#define SC_COMPILER_MSVC 3 #if defined(__clang__) -# undef SC_COMPILER -# define SC_COMPILER SC_COMPILER_CLANG -#elif defined(__GNUC__) || defined(__GNUG__) // after clang, possible it also has the same defines (need to research) -# undef SC_COMPILER -# define SC_COMPILER SC_COMPILER_GNU +# undef SC_COMPILER +# define SC_COMPILER SC_COMPILER_CLANG +#elif defined(__GNUC__) || defined(__GNUG__) // after clang, possible it also has the same defines (need to research) +# undef SC_COMPILER +# define SC_COMPILER SC_COMPILER_GNU #elif defined(_MSC_VER) -# undef SC_COMPILER -# define SC_COMPILER SC_COMPILER_MSVC +# undef SC_COMPILER +# define SC_COMPILER SC_COMPILER_MSVC #else -# error "Unsupported compiler" +# error "Unsupported compiler" #endif - // Determine platform -#define SC_PLATFORM 0 -#define SC_PLATFORM_WIN32 1 -#define SC_PLATFORM_LINUX 2 -#define SC_PLATFORM_MAC 3 -#define SC_PLATFORM_IOS 4 -#define SC_PLATFORM_ANDROID 5 - +#define SC_PLATFORM 0 +#define SC_PLATFORM_WIN32 1 +#define SC_PLATFORM_LINUX 2 +#define SC_PLATFORM_MAC 3 +#define SC_PLATFORM_IOS 4 +#define SC_PLATFORM_ANDROID 5 #if (defined(__WIN32__) || defined(_WIN32)) && !defined(__ANDROID__) -# undef SC_PLATFORM -# define SC_PLATFORM SC_PLATFORM_WIN32 -#elif defined(__APPLE_CC__) -# undef SC_PLATFORM -# define SC_PLATFORM SC_PLATFORM_MAC +# undef SC_PLATFORM +# define SC_PLATFORM SC_PLATFORM_WIN32 +#elif defined(__APPLE_CC__) +# undef SC_PLATFORM +# define SC_PLATFORM SC_PLATFORM_MAC /* TODO: add iOS support # if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 60000 || __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000 */ #elif defined(__ANDROID__) -# undef SC_PLATFORM -# define SC_PLATFORM SC_PLATFORM_ANDROID -#else // let all other platform right now is a linux platforms -# undef SC_PLATFORM -# define SC_PLATFORM SC_PLATFORM_LINUX +# undef SC_PLATFORM +# define SC_PLATFORM SC_PLATFORM_ANDROID +#else // let all other platform right now is a linux platforms +# undef SC_PLATFORM +# define SC_PLATFORM SC_PLATFORM_LINUX #endif #define SC_IS_PLATFORM_WIN32 (SC_PLATFORM == SC_PLATFORM_WIN32) @@ -59,4 +57,4 @@ #define SC_IS_PLATFORM_IOS (SC_PLATFORM == SC_PLATFORM_IOS) #define SC_IS_PLATFORM_ANDROID (SC_PLATFORM == SC_PLATFORM_ANDROID) -#endif // _sc_platform_h_ \ No newline at end of file +#endif // _sc_platform_h_ \ No newline at end of file diff --git a/sc-memory/sc-core/sc-store/sc_segment.c b/sc-memory/sc-core/sc-store/sc_segment.c index 21c9acd1bf..b6a0802b75 100644 --- a/sc-memory/sc-core/sc-store/sc_segment.c +++ b/sc-memory/sc-core/sc-store/sc_segment.c @@ -11,19 +11,19 @@ #include -#define MAX_LOCK_SLEEP 10 // microseconds -#define LOCK_SLEEP() //{ g_usleep(g_random_int() % MAX_LOCK_SLEEP); } +#define MAX_LOCK_SLEEP 10 // microseconds +#define LOCK_SLEEP() //{ g_usleep(g_random_int() % MAX_LOCK_SLEEP); } -sc_segment* sc_segment_new(sc_addr_seg num) +sc_segment * sc_segment_new(sc_addr_seg num) { - sc_segment *segment = g_new0(sc_segment, 1); + sc_segment * segment = g_new0(sc_segment, 1); // initialize empty count for sections sc_uint16 count = SC_SEGMENT_ELEMENTS_COUNT / SC_CONCURRENCY_LEVEL; sc_uint16 i, c = count * SC_CONCURRENCY_LEVEL; for (i = 0; i < SC_CONCURRENCY_LEVEL; ++i) { - sc_segment_section *section = &(segment->sections[i]); + sc_segment_section * section = &(segment->sections[i]); section->empty_offset = i; section->empty_count = ((c + i) <= SC_SEGMENT_ELEMENTS_COUNT) ? count + 1 : count; } @@ -71,37 +71,37 @@ void sc_segment_loaded(sc_segment * seg) } } -void sc_segment_free(sc_segment *segment) +void sc_segment_free(sc_segment * segment) { - g_assert( segment != 0); + g_assert(segment != 0); g_free(segment); } -void sc_segment_erase_element(sc_segment *seg, sc_uint16 offset) +void sc_segment_erase_element(sc_segment * seg, sc_uint16 offset) { g_assert(g_atomic_pointer_get(&seg->sections[offset % SC_CONCURRENCY_LEVEL].thread_lock) != 0); g_atomic_int_dec_and_test(&seg->elements_count); - g_assert( seg != (sc_segment*)0 ); - g_assert( offset < SC_SEGMENT_ELEMENTS_COUNT ); + g_assert(seg != (sc_segment *)0); + g_assert(offset < SC_SEGMENT_ELEMENTS_COUNT); memset(&seg->elements[offset], 0, sizeof(sc_element)); - sc_segment_section *section = &(seg->sections[offset % SC_CONCURRENCY_LEVEL]); + sc_segment_section * section = &(seg->sections[offset % SC_CONCURRENCY_LEVEL]); g_atomic_int_inc(§ion->empty_count); g_atomic_int_set(§ion->empty_offset, offset); g_assert(offset != 0 || seg->num != 0); } -sc_uint32 sc_segment_get_elements_count(sc_segment *seg) +sc_uint32 sc_segment_get_elements_count(sc_segment * seg) { g_assert(seg != null_ptr); return g_atomic_int_get(&seg->elements_count); } -sc_bool sc_segment_has_empty_slot(sc_segment *segment) +sc_bool sc_segment_has_empty_slot(sc_segment * segment) { g_assert(segment != null_ptr); if (segment->num == 0) @@ -110,7 +110,7 @@ sc_bool sc_segment_has_empty_slot(sc_segment *segment) return g_atomic_int_get(&segment->elements_count) < SC_SEGMENT_ELEMENTS_COUNT; } -void sc_segment_collect_elements_stat(sc_segment *seg, sc_stat *stat) +void sc_segment_collect_elements_stat(sc_segment * seg, sc_stat * stat) { sc_int32 i; for (i = 0; i < SC_CONCURRENCY_LEVEL; ++i) @@ -143,11 +143,10 @@ void sc_segment_collect_elements_stat(sc_segment *seg, sc_stat *stat) j += SC_CONCURRENCY_LEVEL; } sc_segment_section_unlock(section); - } } -sc_element_meta* sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset) +sc_element_meta * sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset) { g_assert(seg != null_ptr); g_assert(seg->sections[offset % SC_CONCURRENCY_LEVEL].thread_lock == sc_thread()); @@ -157,7 +156,7 @@ sc_element_meta* sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset) } // --------------------------- -sc_element* sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segment *seg, sc_addr_offset *offset) +sc_element * sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segment * seg, sc_addr_offset * offset) { sc_uint16 max_attempts = 1; while (sc_segment_has_empty_slot(seg) == SC_TRUE) @@ -184,7 +183,7 @@ sc_element* sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segm // trying to find empty element in section g_assert(idx >= 0 && idx < SC_SEGMENT_ELEMENTS_COUNT); - g_assert(seg->num + idx > 0); // not empty addr + g_assert(seg->num + idx > 0); // not empty addr // need to find new empty element sc_int32 j = idx + SC_CONCURRENCY_LEVEL; @@ -211,20 +210,18 @@ sc_element* sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segm j -= SC_CONCURRENCY_LEVEL; } - } sc_segment_section_unlock(section); continue; -result: - { - g_assert(g_atomic_int_get(§ion->empty_count) >= 0); - *offset = idx; - return &seg->elements[*offset]; - } + result: + { + g_assert(g_atomic_int_get(§ion->empty_count) >= 0); + *offset = idx; + return &seg->elements[*offset]; + } } - } if (max_attempts < SC_CONCURRENCY_LEVEL) @@ -236,42 +233,42 @@ sc_element* sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segm return null_ptr; } -sc_element* sc_segment_lock_element(sc_segment *seg, sc_addr_offset offset) +sc_element * sc_segment_lock_element(sc_segment * seg, sc_addr_offset offset) { g_assert(offset < SC_SEGMENT_ELEMENTS_COUNT && seg != null_ptr); - sc_segment_section *section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; + sc_segment_section * section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; sc_segment_section_lock(section); return &seg->elements[offset]; } -sc_element* sc_segment_lock_element_try(sc_segment *seg, sc_addr_offset offset, sc_uint16 max_attempts) +sc_element * sc_segment_lock_element_try(sc_segment * seg, sc_addr_offset offset, sc_uint16 max_attempts) { g_assert(offset < SC_SEGMENT_ELEMENTS_COUNT && seg != null_ptr); - sc_segment_section *section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; + sc_segment_section * section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; if (sc_segment_section_lock_try(section, max_attempts) == SC_TRUE) return &seg->elements[offset]; - return (sc_element*)0; + return (sc_element *)0; } -void sc_segment_unlock_element(sc_segment *seg, sc_addr_offset offset) +void sc_segment_unlock_element(sc_segment * seg, sc_addr_offset offset) { g_assert(offset < SC_SEGMENT_ELEMENTS_COUNT && seg != null_ptr); - sc_segment_section *section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; + sc_segment_section * section = &seg->sections[offset % SC_CONCURRENCY_LEVEL]; sc_segment_section_unlock(section); } -void sc_segment_section_lock(sc_segment_section *section) +void sc_segment_section_lock(sc_segment_section * section) { sc_pointer const thread = sc_thread(); lock: +{ + while (g_atomic_int_compare_and_exchange(§ion->internal_lock, 0, 1) == FALSE) { - while (g_atomic_int_compare_and_exchange(§ion->internal_lock, 0, 1) == FALSE) - { - LOCK_SLEEP(); - } + LOCK_SLEEP(); } +} if (g_atomic_pointer_get(§ion->thread_lock) != 0 && g_atomic_pointer_get(§ion->thread_lock) != thread) { @@ -285,7 +282,7 @@ void sc_segment_section_lock(sc_segment_section *section) g_atomic_int_set(§ion->internal_lock, 0); } -sc_bool sc_segment_section_lock_try(sc_segment_section *section, sc_uint16 max_attempts) +sc_bool sc_segment_section_lock_try(sc_segment_section * section, sc_uint16 max_attempts) { sc_pointer const thread = sc_thread(); @@ -293,14 +290,14 @@ sc_bool sc_segment_section_lock_try(sc_segment_section *section, sc_uint16 max_a sc_uint16 attempts = 0; lock: +{ + while (g_atomic_int_compare_and_exchange(§ion->internal_lock, 0, 1) == FALSE) { - while (g_atomic_int_compare_and_exchange(§ion->internal_lock, 0, 1) == FALSE) - { - LOCK_SLEEP(); - if (max_attempts < attempts++) - return SC_FALSE; - } + LOCK_SLEEP(); + if (max_attempts < attempts++) + return SC_FALSE; } +} if (g_atomic_pointer_get(§ion->thread_lock) != 0 && g_atomic_pointer_get(§ion->thread_lock) != thread) { @@ -318,7 +315,7 @@ sc_bool sc_segment_section_lock_try(sc_segment_section *section, sc_uint16 max_a return SC_TRUE; } -void sc_segment_section_unlock(sc_segment_section *section) +void sc_segment_section_unlock(sc_segment_section * section) { g_assert(section != null_ptr); @@ -348,4 +345,3 @@ void sc_segment_unlock(sc_segment * seg) for (i = 0; i < SC_CONCURRENCY_LEVEL; ++i) sc_segment_section_unlock(&seg->sections[i]); } - diff --git a/sc-memory/sc-core/sc-store/sc_segment.h b/sc-memory/sc-core/sc-store/sc_segment.h index 6491c4f598..6e2b09b4a7 100644 --- a/sc-memory/sc-core/sc-store/sc_segment.h +++ b/sc-memory/sc-core/sc-store/sc_segment.h @@ -18,11 +18,11 @@ //! Structure to store segment locks typedef struct _sc_segment_section { - volatile sc_pointer thread_lock; // pointer to thread, that locked section - sc_int empty_count; // use 32-bit value for atomic operations - sc_int empty_offset; // use 32-bit value for atomic operations - sc_int internal_lock; // - sc_int lock_count; // count of recursive locks + volatile sc_pointer thread_lock; // pointer to thread, that locked section + sc_int empty_count; // use 32-bit value for atomic operations + sc_int empty_offset; // use 32-bit value for atomic operations + sc_int internal_lock; // + sc_int lock_count; // count of recursive locks } sc_segment_section; /*! Structure for segment storing @@ -31,45 +31,46 @@ struct _sc_segment { sc_element_meta meta[SC_SEGMENT_ELEMENTS_COUNT]; sc_element elements[SC_SEGMENT_ELEMENTS_COUNT]; - sc_addr_seg num; // number of this segment in memory + sc_addr_seg num; // number of this segment in memory sc_segment_section sections[SC_CONCURRENCY_LEVEL]; - sc_uint elements_count; // number of sc-element in the segment + sc_uint elements_count; // number of sc-element in the segment }; /*! Create new segment with specified size. * @param num Number of created intance in sc-memory */ -sc_segment* sc_segment_new(sc_addr_seg num); +sc_segment * sc_segment_new(sc_addr_seg num); -//! Need to be called after segment data loaded. This function update all meta info that need to correct work (sections empty offsets, and others) +//! Need to be called after segment data loaded. This function update all meta info that need to correct work (sections +//! empty offsets, and others) void sc_segment_loaded(sc_segment * seg); -void sc_segment_free(sc_segment *segment); +void sc_segment_free(sc_segment * segment); //! Remove element from specified segment. @note sc-element need to be locked -void sc_segment_erase_element(sc_segment *seg, sc_uint16 offset); +void sc_segment_erase_element(sc_segment * seg, sc_uint16 offset); //! Returns number of stored sc-elements in segment -sc_uint32 sc_segment_get_elements_count(sc_segment *seg); +sc_uint32 sc_segment_get_elements_count(sc_segment * seg); /*! Deletes garbage in specified segment * @param oldet_time_stamp Oldest timestamp, that can be used * @param seg Poitnet to segment to delete garbage * @returns Returns number of freed cells */ -//sc_uint32 sc_segment_free_garbage(sc_segment *seg, sc_uint32 oldest_time_stamp); +// sc_uint32 sc_segment_free_garbage(sc_segment *seg, sc_uint32 oldest_time_stamp); /*! Check if segment has any empty slots * @param segment Pointer to segment for check * @returns If \p segment has any empty slots, then return SC_TRUE; otherwise return SC_FALSE */ -sc_bool sc_segment_has_empty_slot(sc_segment *segment); +sc_bool sc_segment_has_empty_slot(sc_segment * segment); //! Collects segment elements statistics void sc_segment_collect_elements_stat(sc_segment * seg, sc_stat * stat); //! Returns pointer to sc-element metainfo -sc_element_meta* sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset); +sc_element_meta * sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset); // ---------------------- locks -------------------------- /*! Function to lock any empty element @@ -78,37 +79,37 @@ sc_element_meta* sc_segment_get_meta(sc_segment * seg, sc_addr_offset offset); * @returns Returns pointer to locked empty element. If there are no any empty element found, * then returns 0 */ -sc_element* sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segment *seg, sc_addr_offset *offset); +sc_element * sc_segment_lock_empty_element(sc_memory_context const * ctx, sc_segment * seg, sc_addr_offset * offset); /*! Function to lock specified element in segment * @param seg Pointer to segment to lock element * @param offset Offset of element to lock * @returns Returns pointer to locked sc-element */ -sc_element* sc_segment_lock_element(sc_segment *seg, sc_addr_offset offset); +sc_element * sc_segment_lock_element(sc_segment * seg, sc_addr_offset offset); //! Try to lock sc-element with maximum attempts -sc_element* sc_segment_lock_element_try(sc_segment *seg, sc_addr_offset offset, sc_uint16 max_attempts); +sc_element * sc_segment_lock_element_try(sc_segment * seg, sc_addr_offset offset, sc_uint16 max_attempts); /*! Function to unlock specified element in segment * @param seg Pointer to segment for element unlocking * @param offset Offset of sc-element in segment */ -void sc_segment_unlock_element(sc_segment *seg, sc_addr_offset offset); +void sc_segment_unlock_element(sc_segment * seg, sc_addr_offset offset); //! Locks segment section. This funciton doesn't returns control, while part wouldn't be locked. -void sc_segment_section_lock(sc_segment_section *section); -/*! Try to lock segment section. If section already locked, then this function returns false; otherwise it locks section and returns true +void sc_segment_section_lock(sc_segment_section * section); +/*! Try to lock segment section. If section already locked, then this function returns false; otherwise it locks section + * and returns true * @params section Pointer to segment section to lock * @param max_attempts Maximum number of lock attempts */ -sc_bool sc_segment_section_lock_try(sc_segment_section *section, sc_uint16 max_attempts); +sc_bool sc_segment_section_lock_try(sc_segment_section * section, sc_uint16 max_attempts); //! Unlocks specified segment part -void sc_segment_section_unlock(sc_segment_section *section); +void sc_segment_section_unlock(sc_segment_section * section); // Lock whole segment void sc_segment_lock(sc_segment * seg); void sc_segment_unlock(sc_segment * seg); - #endif diff --git a/sc-memory/sc-core/sc-store/sc_storage.c b/sc-memory/sc-core/sc-store/sc_storage.c index 64a3a67ef4..233cf04c8d 100644 --- a/sc-memory/sc-core/sc-store/sc_storage.c +++ b/sc-memory/sc-core/sc-store/sc_storage.c @@ -23,7 +23,7 @@ #include // segments array -sc_segment **segments = 0; +sc_segment ** segments = 0; // number of segments sc_uint32 segments_num = 0; @@ -32,9 +32,9 @@ const sc_uint16 s_max_storage_cache_attempts = 10; sc_bool is_initialized = SC_FALSE; -sc_memory_context *segments_cache_lock_ctx = 0; +sc_memory_context * segments_cache_lock_ctx = 0; sc_int32 segments_cache_count = 0; -sc_segment* segments_cache[SC_SEGMENT_CACHE_SIZE]; // cache of segments that have empty elements +sc_segment * segments_cache[SC_SEGMENT_CACHE_SIZE]; // cache of segments that have empty elements GMutex s_mutex_free; GMutex s_mutex_save; @@ -43,10 +43,12 @@ GMutex s_mutex_save; void _sc_segment_cache_lock(const sc_memory_context * ctx) { - while (g_atomic_pointer_compare_and_exchange(&segments_cache_lock_ctx, (sc_memory_context*) 0, ctx) == FALSE) {} + while (g_atomic_pointer_compare_and_exchange(&segments_cache_lock_ctx, (sc_memory_context *)0, ctx) == FALSE) + { + } } -void _sc_segment_cache_unlock(const sc_memory_context *ctx) +void _sc_segment_cache_unlock(const sc_memory_context * ctx) { g_assert(g_atomic_pointer_get(&segments_cache_lock_ctx) == ctx); g_atomic_pointer_set(&segments_cache_lock_ctx, 0); @@ -58,7 +60,8 @@ void _sc_segment_cache_append(sc_segment * seg) sc_int32 i, idx = CONCURRENCY_TO_CACHE_IDX(cidx); for (i = 0; i < SC_SEGMENT_CACHE_SIZE; ++i) { - if (g_atomic_pointer_compare_and_exchange(&segments_cache[(idx + i) % SC_SEGMENT_CACHE_SIZE], (sc_segment*) 0, seg) == TRUE) + if (g_atomic_pointer_compare_and_exchange( + &segments_cache[(idx + i) % SC_SEGMENT_CACHE_SIZE], (sc_segment *)0, seg) == TRUE) { g_atomic_int_inc(&segments_cache_count); break; @@ -66,7 +69,7 @@ void _sc_segment_cache_append(sc_segment * seg) } } -void _sc_segment_cache_remove(const sc_memory_context *ctx, sc_segment *seg) +void _sc_segment_cache_remove(const sc_memory_context * ctx, sc_segment * seg) { sc_int32 i, idx = CONCURRENCY_TO_CACHE_IDX(ctx->id); for (i = 0; i < SC_SEGMENT_CACHE_SIZE; ++i) @@ -92,7 +95,7 @@ void _sc_segment_cache_update() sc_int32 i; for (i = 0; i < g_atomic_int_get(&segments_num); ++i) { - sc_segment *s = g_atomic_pointer_get(&(segments[i])); + sc_segment * s = g_atomic_pointer_get(&(segments[i])); // need to check pointer, because segments_num increments earlier, then segments appends into array if (s != null_ptr) { @@ -105,13 +108,13 @@ void _sc_segment_cache_update() } } -sc_segment* _sc_segment_cache_get(const sc_memory_context *ctx) +sc_segment * _sc_segment_cache_get(const sc_memory_context * ctx) { _sc_segment_cache_lock(ctx); g_mutex_lock(&s_mutex_save); - sc_segment *seg = 0; + sc_segment * seg = 0; if (g_atomic_int_get(&segments_cache_count) > 0) { sc_int32 i, idx = CONCURRENCY_TO_CACHE_IDX(ctx->id); @@ -133,23 +136,22 @@ sc_segment* _sc_segment_cache_get(const sc_memory_context *ctx) _sc_segment_cache_append(seg); result: - { - _sc_segment_cache_unlock(ctx); - g_mutex_unlock(&s_mutex_save); - } +{ + _sc_segment_cache_unlock(ctx); + g_mutex_unlock(&s_mutex_save); +} return seg; } - // ----------------------------------------------------------------------------- -sc_bool sc_storage_initialize(const char *path, sc_bool clear) +sc_bool sc_storage_initialize(const char * path, sc_bool clear) { - g_assert( segments == (sc_segment**)0 ); - g_assert( !is_initialized ); + g_assert(segments == (sc_segment **)0); + g_assert(!is_initialized); - segments = g_new0(sc_segment*, SC_ADDR_SEG_MAX); + segments = g_new0(sc_segment *, SC_ADDR_SEG_MAX); sc_bool res = sc_fs_storage_initialize(path, clear); if (res == SC_FALSE) @@ -160,7 +162,7 @@ sc_bool sc_storage_initialize(const char *path, sc_bool clear) is_initialized = SC_TRUE; - memset(&(segments_cache[0]), 0, sizeof(sc_segment*) * SC_SEGMENT_CACHE_SIZE); + memset(&(segments_cache[0]), 0, sizeof(sc_segment *) * SC_SEGMENT_CACHE_SIZE); return SC_TRUE; } @@ -168,19 +170,19 @@ sc_bool sc_storage_initialize(const char *path, sc_bool clear) void sc_storage_shutdown(sc_bool save_state) { sc_uint idx = 0; - g_assert( segments != (sc_segment**)0 ); - + g_assert(segments != (sc_segment **)0); sc_fs_storage_shutdown(segments, save_state); for (idx = 0; idx < SC_ADDR_SEG_MAX; idx++) { - if (segments[idx] == null_ptr) continue; // skip segments, that are not loaded + if (segments[idx] == null_ptr) + continue; // skip segments, that are not loaded sc_segment_free(segments[idx]); } g_free(segments); - segments = (sc_segment**)0; + segments = (sc_segment **)0; segments_num = 0; is_initialized = SC_FALSE; @@ -192,9 +194,9 @@ sc_bool sc_storage_is_initialized() return is_initialized; } -sc_bool sc_storage_is_element(const sc_memory_context *ctx, sc_addr addr) +sc_bool sc_storage_is_element(const sc_memory_context * ctx, sc_addr addr) { - sc_element *el = 0; + sc_element * el = 0; sc_bool res = SC_TRUE; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -208,11 +210,11 @@ sc_bool sc_storage_is_element(const sc_memory_context *ctx, sc_addr addr) return res; } -sc_element* sc_storage_append_el_into_segments(const sc_memory_context *ctx, sc_addr *addr) +sc_element * sc_storage_append_el_into_segments(const sc_memory_context * ctx, sc_addr * addr) { - sc_segment * seg = (sc_segment*)0x1; + sc_segment * seg = (sc_segment *)0x1; - g_assert( addr != 0 ); + g_assert(addr != 0); SC_ADDR_MAKE_EMPTY(*addr); if (g_atomic_int_get(&segments_num) >= sc_config_get_max_loaded_segments()) @@ -222,12 +224,12 @@ sc_element* sc_storage_append_el_into_segments(const sc_memory_context *ctx, sc_ // try to find segment with empty slots while (seg != 0) { - sc_segment *seg = _sc_segment_cache_get(ctx); + sc_segment * seg = _sc_segment_cache_get(ctx); if (seg == null_ptr) break; - sc_element *el = sc_segment_lock_empty_element(ctx, seg, &addr->offset); + sc_element * el = sc_segment_lock_empty_element(ctx, seg, &addr->offset); if (el != null_ptr) { addr->seg = seg->num; @@ -247,10 +249,10 @@ sc_element* sc_storage_append_el_into_segments(const sc_memory_context *ctx, sc_ return null_ptr; } -sc_addr sc_storage_element_new_access(const sc_memory_context *ctx, sc_type type, sc_access_levels access_levels) +sc_addr sc_storage_element_new_access(const sc_memory_context * ctx, sc_type type, sc_access_levels access_levels) { sc_addr addr; - sc_element *res = 0; + sc_element * res = 0; res = sc_storage_append_el_into_segments(ctx, &addr); if (res != null_ptr) @@ -267,16 +269,16 @@ sc_addr sc_storage_element_new_access(const sc_memory_context *ctx, sc_type type return addr; } -sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) +sc_result sc_storage_element_free(sc_memory_context * ctx, sc_addr addr) { GHashTable *remove_table = 0, *lock_table = 0; - GSList *remove_list = 0; + GSList * remove_list = 0; sc_result result = SC_RESULT_OK; g_mutex_lock(&s_mutex_free); // first of all we need to collect and lock all elements - sc_element *el; + sc_element * el; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) { g_mutex_unlock(&s_mutex_free); @@ -329,7 +331,7 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) if (el->flags.type & sc_type_arc_mask) { // lock begin and end elements of arc - sc_element *el2 = 0; + sc_element * el2 = 0; p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(el->arc.begin)); if ((el2 = g_hash_table_lookup(lock_table, p_addr)) == null_ptr) { @@ -400,7 +402,7 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) while (SC_ADDR_IS_NOT_EMPTY(_addr)) { gpointer p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(_addr)); - sc_element *el2 = g_hash_table_lookup(remove_table, p_addr); + sc_element * el2 = g_hash_table_lookup(remove_table, p_addr); if (el2 == null_ptr) { @@ -424,7 +426,7 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) while (SC_ADDR_IS_NOT_EMPTY(_addr)) { gpointer p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(_addr)); - sc_element *el2 = g_hash_table_lookup(remove_table, p_addr); + sc_element * el2 = g_hash_table_lookup(remove_table, p_addr); if (el2 == null_ptr) { @@ -492,7 +494,7 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) if (SC_ADDR_IS_NOT_EMPTY(prev_arc)) { p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(prev_arc)); - sc_element *prev_el_arc = g_hash_table_lookup(lock_table, p_addr); + sc_element * prev_el_arc = g_hash_table_lookup(lock_table, p_addr); g_assert(prev_el_arc != null_ptr); prev_el_arc->arc.next_out_arc = next_arc; } @@ -500,12 +502,12 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) if (SC_ADDR_IS_NOT_EMPTY(next_arc)) { p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(next_arc)); - sc_element *next_el_arc = g_hash_table_lookup(lock_table, p_addr); + sc_element * next_el_arc = g_hash_table_lookup(lock_table, p_addr); g_assert(next_el_arc != null_ptr); next_el_arc->arc.prev_out_arc = prev_arc; } - sc_element *b_el = g_hash_table_lookup(lock_table, GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(el->arc.begin))); + sc_element * b_el = g_hash_table_lookup(lock_table, GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(el->arc.begin))); sc_bool need_unlock = SC_FALSE; if (b_el == null_ptr) { @@ -527,7 +529,7 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) if (SC_ADDR_IS_NOT_EMPTY(prev_arc)) { p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(prev_arc)); - sc_element *prev_el_arc = g_hash_table_lookup(lock_table, p_addr); + sc_element * prev_el_arc = g_hash_table_lookup(lock_table, p_addr); g_assert(prev_el_arc != null_ptr); prev_el_arc->arc.next_in_arc = next_arc; } @@ -535,13 +537,13 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) if (SC_ADDR_IS_NOT_EMPTY(next_arc)) { p_addr = GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(next_arc)); - sc_element *next_el_arc = g_hash_table_lookup(lock_table, p_addr); + sc_element * next_el_arc = g_hash_table_lookup(lock_table, p_addr); g_assert(next_el_arc != null_ptr); next_el_arc->arc.prev_in_arc = prev_arc; } need_unlock = SC_FALSE; - sc_element *e_el = g_hash_table_lookup(lock_table, GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(el->arc.end))); + sc_element * e_el = g_hash_table_lookup(lock_table, GUINT_TO_POINTER(SC_ADDR_LOCAL_TO_INT(el->arc.end))); if (e_el == null_ptr) { STORAGE_CHECK_CALL(sc_storage_element_lock(el->arc.end, &e_el)); @@ -589,14 +591,14 @@ sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr) return result; } -sc_addr sc_storage_node_new(const sc_memory_context *ctx, sc_type type) +sc_addr sc_storage_node_new(const sc_memory_context * ctx, sc_type type) { return sc_storage_node_new_ext(ctx, type, ctx->access_levels); } -sc_addr sc_storage_node_new_ext(const sc_memory_context *ctx, sc_type type, sc_access_levels access_levels) +sc_addr sc_storage_node_new_ext(const sc_memory_context * ctx, sc_type type, sc_access_levels access_levels) { - g_assert( !(sc_type_arc_mask & type) ); + g_assert(!(sc_type_arc_mask & type)); sc_addr addr; sc_element * locked_el = sc_storage_append_el_into_segments(ctx, &addr); @@ -613,12 +615,12 @@ sc_addr sc_storage_node_new_ext(const sc_memory_context *ctx, sc_type type, sc_a return addr; } -sc_addr sc_storage_link_new(const sc_memory_context *ctx, sc_bool is_const) +sc_addr sc_storage_link_new(const sc_memory_context * ctx, sc_bool is_const) { return sc_storage_link_new_ext(ctx, ctx->access_levels, is_const); } -sc_addr sc_storage_link_new_ext(const sc_memory_context *ctx, sc_access_levels access_levels, sc_bool is_const) +sc_addr sc_storage_link_new_ext(const sc_memory_context * ctx, sc_access_levels access_levels, sc_bool is_const) { sc_addr addr; @@ -637,16 +639,21 @@ sc_addr sc_storage_link_new_ext(const sc_memory_context *ctx, sc_access_levels a return addr; } -sc_addr sc_storage_arc_new(sc_memory_context *ctx, sc_type type, sc_addr beg, sc_addr end) +sc_addr sc_storage_arc_new(sc_memory_context * ctx, sc_type type, sc_addr beg, sc_addr end) { return sc_storage_arc_new_ext(ctx, type, beg, end, ctx->access_levels); } -sc_addr sc_storage_arc_new_ext(sc_memory_context *ctx, sc_type type, sc_addr beg, sc_addr end, sc_access_levels access_levels) +sc_addr sc_storage_arc_new_ext( + sc_memory_context * ctx, + sc_type type, + sc_addr beg, + sc_addr end, + sc_access_levels access_levels) { sc_addr addr; - g_assert( !(sc_type_node & type) ); + g_assert(!(sc_type_node & type)); sc_result r; SC_ADDR_MAKE_EMPTY(addr); @@ -658,7 +665,7 @@ sc_addr sc_storage_arc_new_ext(sc_memory_context *ctx, sc_type type, sc_addr beg { sc_element *beg_el = 0, *end_el = 0; sc_element *f_out_arc = 0, *f_in_arc = 0; - sc_element *tmp_el = 0; + sc_element * tmp_el = 0; sc_bool should_break = SC_FALSE; // try to lock begin and end elements @@ -739,25 +746,25 @@ sc_addr sc_storage_arc_new_ext(sc_memory_context *ctx, sc_type type, sc_addr beg beg_el->first_out_arc = addr; end_el->first_in_arc = addr; -unlock: + unlock: + { + if (beg_el) { - if (beg_el) - { - if (f_out_arc) - sc_storage_element_unlock(first_out_arc); - sc_storage_element_unlock(beg); - } - if (end_el) - { - if (f_in_arc) - sc_storage_element_unlock(first_in_arc); - sc_storage_element_unlock(end); - } - - if (tmp_el) - sc_storage_element_unlock(addr); + if (f_out_arc) + sc_storage_element_unlock(first_out_arc); + sc_storage_element_unlock(beg); + } + if (end_el) + { + if (f_in_arc) + sc_storage_element_unlock(first_in_arc); + sc_storage_element_unlock(end); } + if (tmp_el) + sc_storage_element_unlock(addr); + } + if (should_break == SC_TRUE) break; } @@ -765,9 +772,9 @@ sc_addr sc_storage_arc_new_ext(sc_memory_context *ctx, sc_type type, sc_addr beg return addr; } -sc_result sc_storage_get_element_type(const sc_memory_context *ctx, sc_addr addr, sc_type *result) +sc_result sc_storage_get_element_type(const sc_memory_context * ctx, sc_addr addr, sc_type * result) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result r = SC_RESULT_OK; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -785,15 +792,15 @@ sc_result sc_storage_get_element_type(const sc_memory_context *ctx, sc_addr addr r = SC_RESULT_ERROR_NO_READ_RIGHTS; unlock: - { - sc_storage_element_unlock(addr); - } +{ + sc_storage_element_unlock(addr); +} return r; } -sc_result sc_storage_change_element_subtype(const sc_memory_context *ctx, sc_addr addr, sc_type type) +sc_result sc_storage_change_element_subtype(const sc_memory_context * ctx, sc_addr addr, sc_type type) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result r = SC_RESULT_OK; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -814,15 +821,15 @@ sc_result sc_storage_change_element_subtype(const sc_memory_context *ctx, sc_add r = SC_RESULT_ERROR_NO_WRITE_RIGHTS; unlock: - { - sc_storage_element_unlock(addr); - } +{ + sc_storage_element_unlock(addr); +} return r; } -sc_result sc_storage_get_arc_begin(const sc_memory_context *ctx, sc_addr addr, sc_addr *result) +sc_result sc_storage_get_arc_begin(const sc_memory_context * ctx, sc_addr addr, sc_addr * result) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result res = SC_RESULT_ERROR_INVALID_TYPE; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -841,19 +848,20 @@ sc_result sc_storage_get_arc_begin(const sc_memory_context *ctx, sc_addr addr, s *result = el->arc.begin; res = SC_RESULT_OK; } - } else + } + else res = SC_RESULT_ERROR_NO_READ_RIGHTS; unlock: - { - sc_storage_element_unlock(addr); - } +{ + sc_storage_element_unlock(addr); +} return res; } -sc_result sc_storage_get_arc_end(const sc_memory_context *ctx, sc_addr addr, sc_addr *result) +sc_result sc_storage_get_arc_end(const sc_memory_context * ctx, sc_addr addr, sc_addr * result) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result res = SC_RESULT_ERROR_INVALID_TYPE; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -872,19 +880,24 @@ sc_result sc_storage_get_arc_end(const sc_memory_context *ctx, sc_addr addr, sc_ *result = el->arc.end; res = SC_RESULT_OK; } - } else + } + else res = SC_RESULT_ERROR_NO_READ_RIGHTS; unlock: - { - sc_storage_element_unlock(addr); - } +{ + sc_storage_element_unlock(addr); +} return res; } -sc_result sc_storage_get_arc_info(sc_memory_context const * ctx, sc_addr addr, sc_addr * result_begin_addr, sc_addr * result_end_addr) +sc_result sc_storage_get_arc_info( + sc_memory_context const * ctx, + sc_addr addr, + sc_addr * result_begin_addr, + sc_addr * result_end_addr) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result res = SC_RESULT_ERROR_INVALID_TYPE; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -909,15 +922,15 @@ sc_result sc_storage_get_arc_info(sc_memory_context const * ctx, sc_addr addr, s res = SC_RESULT_ERROR_NO_READ_RIGHTS; unlock: - { - sc_storage_element_unlock(addr); - } +{ + sc_storage_element_unlock(addr); +} return res; } -sc_result sc_storage_set_link_content(sc_memory_context *ctx, sc_addr addr, const sc_stream *stream) +sc_result sc_storage_set_link_content(sc_memory_context * ctx, sc_addr addr, const sc_stream * stream) { - sc_element *el; + sc_element * el; sc_check_sum check_sum; sc_result result = SC_RESULT_ERROR; sc_access_levels access_lvl; @@ -1000,16 +1013,16 @@ sc_result sc_storage_set_link_content(sc_memory_context *ctx, sc_addr addr, cons sc_event_emit(ctx, addr, access_lvl, SC_EVENT_CONTENT_CHANGED, empty, empty); unlock: - { - STORAGE_CHECK_CALL(sc_storage_element_unlock(addr)); - } +{ + STORAGE_CHECK_CALL(sc_storage_element_unlock(addr)); +} return result; } -sc_result sc_storage_get_link_content(const sc_memory_context *ctx, sc_addr addr, sc_stream **stream) +sc_result sc_storage_get_link_content(const sc_memory_context * ctx, sc_addr addr, sc_stream ** stream) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result res = SC_RESULT_ERROR; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -1040,15 +1053,17 @@ sc_result sc_storage_get_link_content(const sc_memory_context *ctx, sc_addr addr if (len != 0) { g_assert(len < SC_CHECKSUM_LEN); - gchar *buff = g_new0(gchar, len); + gchar * buff = g_new0(gchar, len); memcpy(buff, &el->content.data[1], len); *stream = sc_stream_memory_new(buff, len, SC_STREAM_FLAG_READ, SC_TRUE); - } else + } + else { *stream = 0; } res = SC_RESULT_OK; - } else + } + else { // prepare checksum sc_check_sum checksum; @@ -1059,14 +1074,18 @@ sc_result sc_storage_get_link_content(const sc_memory_context *ctx, sc_addr addr } unlock: - { - STORAGE_CHECK_CALL(sc_storage_element_unlock(addr)); - } +{ + STORAGE_CHECK_CALL(sc_storage_element_unlock(addr)); +} return res; } -sc_result sc_storage_find_links_with_content(const sc_memory_context *ctx, const sc_stream *stream, sc_addr **result, sc_uint32 *result_count) +sc_result sc_storage_find_links_with_content( + const sc_memory_context * ctx, + const sc_stream * stream, + sc_addr ** result, + sc_uint32 * result_count) { g_assert(stream != 0); sc_check_sum check_sum; @@ -1088,7 +1107,7 @@ sc_result sc_storage_find_links_with_content(const sc_memory_context *ctx, const *result = g_new0(sc_addr, tmp_res_count); for (i = 0; i < tmp_res_count; ++i) { - sc_element *el = 0; + sc_element * el = 0; if (sc_storage_element_lock(tmp_res[i], &el) != SC_RESULT_OK) { @@ -1122,9 +1141,13 @@ sc_result sc_storage_find_links_with_content(const sc_memory_context *ctx, const return r; } -sc_result sc_storage_set_access_levels(const sc_memory_context *ctx, sc_addr addr, sc_access_levels access_levels, sc_access_levels * new_value) +sc_result sc_storage_set_access_levels( + const sc_memory_context * ctx, + sc_addr addr, + sc_access_levels access_levels, + sc_access_levels * new_value) { - sc_element *el = 0; + sc_element * el = 0; sc_result r = SC_RESULT_OK; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -1144,9 +1167,9 @@ sc_result sc_storage_set_access_levels(const sc_memory_context *ctx, sc_addr add return r; } -sc_result sc_storage_get_access_levels(const sc_memory_context *ctx, sc_addr addr, sc_access_levels * result) +sc_result sc_storage_get_access_levels(const sc_memory_context * ctx, sc_addr addr, sc_access_levels * result) { - sc_element *el = null_ptr; + sc_element * el = null_ptr; sc_result r = SC_RESULT_OK; if (sc_storage_element_lock(addr, &el) != SC_RESULT_OK) @@ -1163,12 +1186,11 @@ sc_result sc_storage_get_access_levels(const sc_memory_context *ctx, sc_addr add return r; } - -sc_result sc_storage_get_elements_stat(sc_stat *stat) +sc_result sc_storage_get_elements_stat(sc_stat * stat) { /// @todo implement function - g_assert( stat != (sc_stat*)0 ); + g_assert(stat != (sc_stat *)0); memset(stat, 0, sizeof(sc_stat)); stat->segments_count = sc_storage_get_segments_count(); @@ -1176,7 +1198,7 @@ sc_result sc_storage_get_elements_stat(sc_stat *stat) sc_int32 i; for (i = 0; i < g_atomic_int_get(&segments_num); ++i) { - sc_segment *seg = segments[i]; + sc_segment * seg = segments[i]; sc_segment_collect_elements_stat(seg, stat); } @@ -1195,15 +1217,15 @@ sc_result sc_storage_erase_element_from_segment(sc_addr addr) } // ------------------------------ -sc_element_meta* sc_storage_get_element_meta(sc_addr addr) +sc_element_meta * sc_storage_get_element_meta(sc_addr addr) { g_assert(addr.seg < SC_ADDR_SEG_MAX); - sc_segment *segment = g_atomic_pointer_get(&segments[addr.seg]); + sc_segment * segment = g_atomic_pointer_get(&segments[addr.seg]); g_assert(segment != null_ptr); return sc_segment_get_meta(segment, addr.offset); } -sc_result sc_storage_element_lock(sc_addr addr, sc_element **el) +sc_result sc_storage_element_lock(sc_addr addr, sc_element ** el) { if (addr.seg >= SC_ADDR_SEG_MAX) { @@ -1211,7 +1233,7 @@ sc_result sc_storage_element_lock(sc_addr addr, sc_element **el) return SC_RESULT_ERROR; } - sc_segment *segment = g_atomic_pointer_get(&segments[addr.seg]); + sc_segment * segment = g_atomic_pointer_get(&segments[addr.seg]); if (segment == 0) { *el = 0; @@ -1222,7 +1244,7 @@ sc_result sc_storage_element_lock(sc_addr addr, sc_element **el) return SC_RESULT_OK; } -sc_result sc_storage_element_lock_try(sc_addr addr, sc_uint16 max_attempts, sc_element **el) +sc_result sc_storage_element_lock_try(sc_addr addr, sc_uint16 max_attempts, sc_element ** el) { if (addr.seg >= SC_ADDR_SEG_MAX) { @@ -1230,7 +1252,7 @@ sc_result sc_storage_element_lock_try(sc_addr addr, sc_uint16 max_attempts, sc_e return SC_RESULT_ERROR; } - sc_segment *segment = g_atomic_pointer_get(&segments[addr.seg]); + sc_segment * segment = g_atomic_pointer_get(&segments[addr.seg]); if (segment == 0) { *el = 0; diff --git a/sc-memory/sc-core/sc-store/sc_storage.h b/sc-memory/sc-core/sc-store/sc_storage.h index b1aaf71939..4623a8a5c1 100644 --- a/sc-memory/sc-core/sc-store/sc_storage.h +++ b/sc-memory/sc-core/sc-store/sc_storage.h @@ -12,16 +12,23 @@ #include "sc_stream.h" #if SC_DEBUG_MODE -# define STORAGE_CHECK_CALL(x) {sc_result __r = x; g_assert(__r == SC_RESULT_OK); } +# define STORAGE_CHECK_CALL(x) \ + { \ + sc_result __r = x; \ + g_assert(__r == SC_RESULT_OK); \ + } #else -# define STORAGE_CHECK_CALL(x) { x; } +# define STORAGE_CHECK_CALL(x) \ + { \ + x; \ + } #endif /*! Initialize sc storage in specified path * @param path Path to repository * @param clear Flag to clear initialize empty storage */ -sc_bool sc_storage_initialize(const char *path, sc_bool clear); +sc_bool sc_storage_initialize(const char * path, sc_bool clear); //! Shutdown sc storage void sc_storage_shutdown(sc_bool save_state); @@ -34,43 +41,43 @@ sc_bool sc_storage_is_initialized(); * @return Return pointer to created sc-element data. If sc-element wasn't appended, then return 0. * @note Returned sc-element is locked */ -sc_element* sc_storage_append_el_into_segments(const sc_memory_context *ctx, sc_addr *addr); +sc_element * sc_storage_append_el_into_segments(const sc_memory_context * ctx, sc_addr * addr); /*! Check if sc-element with specified sc-addr exist * @param addr sc-addr of element * @return Returns SC_TRUE, if sc-element with \p addr exist; otherwise return false. * If element deleted, then return SC_FALSE. */ -sc_bool sc_storage_is_element(const sc_memory_context *ctx, sc_addr addr); +sc_bool sc_storage_is_element(const sc_memory_context * ctx, sc_addr addr); /*! Create new sc-element in storage. * Only for internal usage. */ -sc_addr sc_storage_element_new_access(const sc_memory_context *ctx, sc_type type, sc_access_levels access_levels); +sc_addr sc_storage_element_new_access(const sc_memory_context * ctx, sc_type type, sc_access_levels access_levels); /*! Remove sc-element from storage * @param addr sc-addr of element to erase * @return If input params are correct and element erased, then return SC_OK; * otherwise return SC_ERROR */ -sc_result sc_storage_element_free(sc_memory_context *ctx, sc_addr addr); +sc_result sc_storage_element_free(sc_memory_context * ctx, sc_addr addr); /*! Create new sc-node * @param type Type of new sc-node * @return Return sc-addr of created sc-node or empty sc-addr if sc-node wasn't created */ -sc_addr sc_storage_node_new(const sc_memory_context *ctx, sc_type type); +sc_addr sc_storage_node_new(const sc_memory_context * ctx, sc_type type); //! Create new sc-node with specified access level -sc_addr sc_storage_node_new_ext(const sc_memory_context *ctx, sc_type type, sc_access_levels access_levels); +sc_addr sc_storage_node_new_ext(const sc_memory_context * ctx, sc_type type, sc_access_levels access_levels); /*! Create new sc-link * @return Return sc-addr of created sc-link or empty sc-addr if sc-link wasn't created */ -sc_addr sc_storage_link_new(const sc_memory_context *ctx, sc_bool is_const); +sc_addr sc_storage_link_new(const sc_memory_context * ctx, sc_bool is_const); //! Create sc-link with specified access levels -sc_addr sc_storage_link_new_ext(const sc_memory_context *ctx, sc_access_levels access_levels, sc_bool is_const); +sc_addr sc_storage_link_new_ext(const sc_memory_context * ctx, sc_access_levels access_levels, sc_bool is_const); /*! Create new sc-arc. * @param type Type of new sc-arc @@ -82,7 +89,12 @@ sc_addr sc_storage_link_new_ext(const sc_memory_context *ctx, sc_access_levels a sc_addr sc_storage_arc_new(sc_memory_context * ctx, sc_type type, sc_addr beg, sc_addr end); //! Create new sc-arc with specified access levels -sc_addr sc_storage_arc_new_ext(sc_memory_context * ctx, sc_type type, sc_addr beg, sc_addr end, sc_access_levels access_levels); +sc_addr sc_storage_arc_new_ext( + sc_memory_context * ctx, + sc_type type, + sc_addr beg, + sc_addr end, + sc_access_levels access_levels); /*! Get type of sc-element with specified sc-addr * @param addr sc-addr of element to get type @@ -118,7 +130,11 @@ sc_result sc_storage_get_arc_end(sc_memory_context const * ctx, sc_addr addr, sc /*! Like a sc_storage_get_arc_begin and sc_storage_get_arc_end call * @see sc_storage_get_arc_begin, @see sc_storage_get_arc_end */ -sc_result sc_storage_get_arc_info(sc_memory_context const * ctx, sc_addr addr, sc_addr * result_begin_addr, sc_addr * result_end_addr); +sc_result sc_storage_get_arc_info( + sc_memory_context const * ctx, + sc_addr addr, + sc_addr * result_begin_addr, + sc_addr * result_end_addr); /*! Setup content data for specified sc-link * @param addr sc-addr of sc-link to setup content @@ -131,7 +147,7 @@ sc_result sc_storage_get_arc_info(sc_memory_context const * ctx, sc_addr addr, s *
  • SC_ERROR - unknown error
  • * */ -sc_result sc_storage_set_link_content(sc_memory_context * ctx, sc_addr addr, const sc_stream *stream); +sc_result sc_storage_set_link_content(sc_memory_context * ctx, sc_addr addr, const sc_stream * stream); /*! Returns content data from specified sc-link * @param addr sc-addr of sc-link to get content data @@ -144,7 +160,7 @@ sc_result sc_storage_set_link_content(sc_memory_context * ctx, sc_addr addr, con *
  • SC_ERROR - unknown error
  • * */ -sc_result sc_storage_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream **stream); +sc_result sc_storage_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream ** stream); /*! Search sc-link addrs by specified data * @param stream Pointert to stream that contains data for search @@ -156,16 +172,25 @@ sc_result sc_storage_get_link_content(sc_memory_context const * ctx, sc_addr add * sc-addrs * @attention \p result array need to be free after usage */ -sc_result sc_storage_find_links_with_content(sc_memory_context const * ctx, sc_stream const * stream, sc_addr ** result, sc_uint32 * result_count); +sc_result sc_storage_find_links_with_content( + sc_memory_context const * ctx, + sc_stream const * stream, + sc_addr ** result, + sc_uint32 * result_count); -/*! Setup new access levels to sc-element. New access levels will be a minimum from context access levels and parameter \b access_levels +/*! Setup new access levels to sc-element. New access levels will be a minimum from context access levels and parameter + * \b access_levels * @param addr sc-addr of sc-element to change access levels * @param access_levels new access levels * @param new_value new value of access levels for sc-element. This parameter can be NULL * * @return Returns SC_RESULT_OK, when access level changed; otherwise it returns error code */ -sc_result sc_storage_set_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels access_levels, sc_access_levels * new_value); +sc_result sc_storage_set_access_levels( + sc_memory_context const * ctx, + sc_addr addr, + sc_access_levels access_levels, + sc_access_levels * new_value); //! Get access levels of sc-element sc_result sc_storage_get_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels * result); @@ -178,18 +203,18 @@ sc_uint sc_storage_get_segments_count(); * @return If statictics info collect without any errors, then return SC_OK; * otherwise return SC_ERROR */ -sc_result sc_storage_get_elements_stat(sc_stat *stat); +sc_result sc_storage_get_elements_stat(sc_stat * stat); sc_result sc_storage_erase_element_from_segment(sc_addr addr); - // ----- Locks ----- //! Returns pointer to sc-element metainfo -sc_element_meta* sc_storage_get_element_meta(sc_addr addr); +sc_element_meta * sc_storage_get_element_meta(sc_addr addr); //! Locks specified sc-element. Pointer to locked sc-element stores in el -sc_result sc_storage_element_lock(sc_addr addr, sc_element **el); -//! Try to lock sc-element by maximum attempts. If element wasn't locked and there are no errors, then el pointer will have null value. -sc_result sc_storage_element_lock_try(sc_addr addr, sc_uint16 max_attempts, sc_element **el); +sc_result sc_storage_element_lock(sc_addr addr, sc_element ** el); +//! Try to lock sc-element by maximum attempts. If element wasn't locked and there are no errors, then el pointer will +//! have null value. +sc_result sc_storage_element_lock_try(sc_addr addr, sc_uint16 max_attempts, sc_element ** el); //! Unlocks specified sc-element sc_result sc_storage_element_unlock(sc_addr addr); @@ -205,4 +230,3 @@ sc_bool sc_storage_element_unref(sc_addr addr); sc_result sc_storage_save(); #endif - diff --git a/sc-memory/sc-core/sc-store/sc_stream.c b/sc-memory/sc-core/sc-store/sc_stream.c index 34eefba8a1..c1b275a8b3 100644 --- a/sc-memory/sc-core/sc-store/sc_stream.c +++ b/sc-memory/sc-core/sc-store/sc_stream.c @@ -9,8 +9,7 @@ #include - -sc_result sc_stream_free(sc_stream *stream) +sc_result sc_stream_free(sc_stream * stream) { g_assert(stream != 0); @@ -23,7 +22,7 @@ sc_result sc_stream_free(sc_stream *stream) return SC_RESULT_OK; } -sc_result sc_stream_read_data(const sc_stream *stream, sc_char *data, sc_uint32 data_len, sc_uint32 *read_bytes) +sc_result sc_stream_read_data(const sc_stream * stream, sc_char * data, sc_uint32 data_len, sc_uint32 * read_bytes) { g_assert(stream != 0); @@ -36,7 +35,7 @@ sc_result sc_stream_read_data(const sc_stream *stream, sc_char *data, sc_uint32 return stream->read_func(stream, data, data_len, read_bytes); } -sc_result sc_stream_write_data(const sc_stream *stream, sc_char *data, sc_uint32 data_len, sc_uint32 *written_bytes) +sc_result sc_stream_write_data(const sc_stream * stream, sc_char * data, sc_uint32 data_len, sc_uint32 * written_bytes) { g_assert(stream != 0); @@ -49,22 +48,20 @@ sc_result sc_stream_write_data(const sc_stream *stream, sc_char *data, sc_uint32 return stream->write_func(stream, data, data_len, written_bytes); } -sc_result sc_stream_seek(const sc_stream *stream, sc_stream_seek_origin seek_origin, sc_uint32 offset) +sc_result sc_stream_seek(const sc_stream * stream, sc_stream_seek_origin seek_origin, sc_uint32 offset) { g_assert(stream != 0); if (sc_stream_check_flag(stream, SC_STREAM_FLAG_SEEK) == FALSE) return SC_RESULT_ERROR; - if (stream->seek_func == 0) return SC_RESULT_ERROR; return stream->seek_func(stream, seek_origin, offset); } - -sc_bool sc_stream_eof(const sc_stream *stream) +sc_bool sc_stream_eof(const sc_stream * stream) { g_assert(stream != 0); @@ -74,7 +71,7 @@ sc_bool sc_stream_eof(const sc_stream *stream) return stream->eof_func(stream); } -sc_result sc_stream_get_length(const sc_stream *stream, sc_uint32 *length) +sc_result sc_stream_get_length(const sc_stream * stream, sc_uint32 * length) { sc_uint32 old_pos = 0; sc_result res = SC_RESULT_ERROR; @@ -106,7 +103,7 @@ sc_result sc_stream_get_length(const sc_stream *stream, sc_uint32 *length) return res; } -sc_result sc_stream_get_position(const sc_stream *stream, sc_uint32 *position) +sc_result sc_stream_get_position(const sc_stream * stream, sc_uint32 * position) { g_assert(stream != 0); @@ -119,8 +116,7 @@ sc_result sc_stream_get_position(const sc_stream *stream, sc_uint32 *position) return stream->tell_func(stream, position); } - -sc_bool sc_stream_check_flag(const sc_stream *stream, sc_uint8 flag) +sc_bool sc_stream_check_flag(const sc_stream * stream, sc_uint8 flag) { g_assert(stream != 0); return (stream->flags & flag) ? SC_TRUE : SC_FALSE; diff --git a/sc-memory/sc-core/sc-store/sc_stream.h b/sc-memory/sc-core/sc-store/sc_stream.h index 2e02d55e97..cc6e98c2f2 100644 --- a/sc-memory/sc-core/sc-store/sc_stream.h +++ b/sc-memory/sc-core/sc-store/sc_stream.h @@ -48,7 +48,7 @@ typedef enum _sc_stream_seek_origin sc_stream_seek_origin; * @return If stream has been freed without any errors, then return SC_OK; otherwise return SC_ERROR * @remarks After calling this function \p stream pointer woldn't be a valid. */ -_SC_EXTERN sc_result sc_stream_free(sc_stream *stream); +_SC_EXTERN sc_result sc_stream_free(sc_stream * stream); /*! Read data from stream. * @param stream Stream pointer to read data @@ -57,7 +57,8 @@ _SC_EXTERN sc_result sc_stream_free(sc_stream *stream); * @param read_bytes Result: number of bytes, that has been read from stream into buffer. * @return If data has been read without any errors, then return SC_OK; otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_stream_read_data(const sc_stream *stream, sc_char *data, sc_uint32 data_len, sc_uint32 *read_bytes); +_SC_EXTERN sc_result +sc_stream_read_data(const sc_stream * stream, sc_char * data, sc_uint32 data_len, sc_uint32 * read_bytes); /*! Write data into stream * @param stream Stream pointer to write data @@ -66,7 +67,8 @@ _SC_EXTERN sc_result sc_stream_read_data(const sc_stream *stream, sc_char *data, * @param written_bytes Result: Number of bytes that has been written into stream * @return If data has been written without any errors, then return SC_OK; otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_stream_write_data(const sc_stream *stream, sc_char *data, sc_uint32 data_len, sc_uint32 *written_bytes); +_SC_EXTERN sc_result +sc_stream_write_data(const sc_stream * stream, sc_char * data, sc_uint32 data_len, sc_uint32 * written_bytes); /*! Sets the position indicator associated with the stream to a new position * @param stream Stream pointer to change position @@ -74,35 +76,33 @@ _SC_EXTERN sc_result sc_stream_write_data(const sc_stream *stream, sc_char *data * @param offset Offset in bytes * @return If position changed without any errors, then return SC_OK; otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_stream_seek(const sc_stream *stream, sc_stream_seek_origin seek_origin, sc_uint32 offset); +_SC_EXTERN sc_result sc_stream_seek(const sc_stream * stream, sc_stream_seek_origin seek_origin, sc_uint32 offset); /*! Check if stream points into the end position * @param stream Stream pointer to check * @return If stream points into the end position, then return SC_TRUE; otherwise return SC_FALSE */ -_SC_EXTERN sc_bool sc_stream_eof(const sc_stream *stream); - +_SC_EXTERN sc_bool sc_stream_eof(const sc_stream * stream); /*! Returns length of stream in bytes. * @param stream Stream pointer to get size * @param length Pointer to result container * @return If correct length returned, then return SC_OK; otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_stream_get_length(const sc_stream *stream, sc_uint32 *length); +_SC_EXTERN sc_result sc_stream_get_length(const sc_stream * stream, sc_uint32 * length); /*! Returns current position in stream * @param stream Stream pointer to get position * @param position Pointer to result container * @return If correct position returned, thern return SC_OK; otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_stream_get_position(const sc_stream *stream, sc_uint32 *position); +_SC_EXTERN sc_result sc_stream_get_position(const sc_stream * stream, sc_uint32 * position); /*! Check if specified data stream supports specified \p flag * @param stream Pointer to data stream for checking * @param flag Data stream flag to check * @return If specified \p flag is supported by \p stream, then return SC_TRUE; otherwise return SC_FALSE */ -_SC_EXTERN sc_bool sc_stream_check_flag(const sc_stream *stream, sc_uint8 flag); - +_SC_EXTERN sc_bool sc_stream_check_flag(const sc_stream * stream, sc_uint8 flag); #endif diff --git a/sc-memory/sc-core/sc-store/sc_stream_file.c b/sc-memory/sc-core/sc-store/sc_stream_file.c index a7687f1de5..e04dfcf231 100644 --- a/sc-memory/sc-core/sc-store/sc_stream_file.c +++ b/sc-memory/sc-core/sc-store/sc_stream_file.c @@ -11,15 +11,15 @@ #include #define SC_STREAM_FILE_FD_CHECK \ - FILE *fd = (FILE*)stream->handler; \ + FILE * fd = (FILE *)stream->handler; \ g_assert(stream != 0); \ if (fd == 0) \ -{ \ - g_message("File handler is null"); \ - return SC_RESULT_ERROR; \ + { \ + g_message("File handler is null"); \ + return SC_RESULT_ERROR; \ } -sc_result sc_stream_file_read(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_read) +sc_result sc_stream_file_read(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_read) { SC_STREAM_FILE_FD_CHECK; @@ -27,7 +27,7 @@ sc_result sc_stream_file_read(const sc_stream *stream, sc_char *data, sc_uint32 return SC_RESULT_OK; } -sc_result sc_stream_file_write(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_written) +sc_result sc_stream_file_write(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_written) { SC_STREAM_FILE_FD_CHECK; @@ -39,7 +39,7 @@ sc_result sc_stream_file_write(const sc_stream *stream, sc_char *data, sc_uint32 return SC_RESULT_OK; } -sc_result sc_stream_file_seek(const sc_stream *stream, sc_stream_seek_origin origin, sc_uint32 offset) +sc_result sc_stream_file_seek(const sc_stream * stream, sc_stream_seek_origin origin, sc_uint32 offset) { int whence = 0; SC_STREAM_FILE_FD_CHECK; @@ -65,14 +65,14 @@ sc_result sc_stream_file_seek(const sc_stream *stream, sc_stream_seek_origin ori return SC_RESULT_ERROR; } -sc_result sc_stream_file_tell(const sc_stream *stream, sc_uint32 *position) +sc_result sc_stream_file_tell(const sc_stream * stream, sc_uint32 * position) { SC_STREAM_FILE_FD_CHECK; *position = ftell(fd); return SC_RESULT_OK; } -sc_result sc_stream_file_free_handler(const sc_stream *stream) +sc_result sc_stream_file_free_handler(const sc_stream * stream) { SC_STREAM_FILE_FD_CHECK; if (fclose(fd) == 0) @@ -81,7 +81,7 @@ sc_result sc_stream_file_free_handler(const sc_stream *stream) return SC_RESULT_ERROR; } -sc_bool sc_stream_file_eof(const sc_stream *stream) +sc_bool sc_stream_file_eof(const sc_stream * stream) { SC_STREAM_FILE_FD_CHECK; @@ -91,15 +91,14 @@ sc_bool sc_stream_file_eof(const sc_stream *stream) return SC_TRUE; } - -sc_stream* sc_stream_file_new(const sc_char *file_name, sc_uint8 flags) +sc_stream * sc_stream_file_new(const sc_char * file_name, sc_uint8 flags) { - sc_stream *stream = 0; - FILE *fd = 0; + sc_stream * stream = 0; + FILE * fd = 0; if (flags & SC_STREAM_FLAG_READ) { - g_assert(!(flags & SC_STREAM_FLAG_APPEND)); // couldn't support append in read mode + g_assert(!(flags & SC_STREAM_FLAG_APPEND)); // couldn't support append in read mode fd = fopen(file_name, "rb"); } else @@ -120,7 +119,7 @@ sc_stream* sc_stream_file_new(const sc_char *file_name, sc_uint8 flags) stream = g_new0(sc_stream, 1); stream->flags = flags | SC_STREAM_FLAG_TELL | SC_STREAM_FLAG_SEEK; - stream->handler = (void*)fd; + stream->handler = (void *)fd; stream->read_func = &sc_stream_file_read; stream->write_func = &sc_stream_file_write; diff --git a/sc-memory/sc-core/sc-store/sc_stream_file.h b/sc-memory/sc-core/sc-store/sc_stream_file.h index 7ce8e3da8e..745a09146d 100644 --- a/sc-memory/sc-core/sc-store/sc_stream_file.h +++ b/sc-memory/sc-core/sc-store/sc_stream_file.h @@ -16,7 +16,6 @@ * with sc_stream_free function, when done using it. * @return Returns stream pointer if the stream was successfully created, or NULL if an error occurred */ -_SC_EXTERN sc_stream* sc_stream_file_new(const sc_char *file_name, sc_uint8 flags); - +_SC_EXTERN sc_stream * sc_stream_file_new(const sc_char * file_name, sc_uint8 flags); #endif diff --git a/sc-memory/sc-core/sc-store/sc_stream_memory.c b/sc-memory/sc-core/sc-store/sc_stream_memory.c index 445658b562..fa9e5eacbf 100644 --- a/sc-memory/sc-core/sc-store/sc_stream_memory.c +++ b/sc-memory/sc-core/sc-store/sc_stream_memory.c @@ -12,17 +12,17 @@ struct _sc_memory_buffer { - char *data; // pointer to data - sc_uint32 size; // size of data - sc_uint32 pos; // current position - sc_bool data_owner; // ownership on data buffer + char * data; // pointer to data + sc_uint32 size; // size of data + sc_uint32 pos; // current position + sc_bool data_owner; // ownership on data buffer }; typedef struct _sc_memory_buffer sc_memory_buffer; -sc_result sc_stream_memory_read(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_read) +sc_result sc_stream_memory_read(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_read) { - sc_memory_buffer *buffer = (sc_memory_buffer*)stream->handler; + sc_memory_buffer * buffer = (sc_memory_buffer *)stream->handler; g_assert(buffer != 0); if (buffer->size == 0) @@ -36,18 +36,17 @@ sc_result sc_stream_memory_read(const sc_stream *stream, sc_char *data, sc_uint3 memcpy(data, &(buffer->data[buffer->pos]), *bytes_read); buffer->pos += *bytes_read; - return SC_RESULT_OK; } -sc_result sc_stream_memory_write(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_written) +sc_result sc_stream_memory_write(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_written) { return SC_RESULT_ERROR; } -sc_result sc_stream_memory_seek(const sc_stream *stream, sc_stream_seek_origin origin, sc_uint32 offset) +sc_result sc_stream_memory_seek(const sc_stream * stream, sc_stream_seek_origin origin, sc_uint32 offset) { - sc_memory_buffer *buffer = (sc_memory_buffer*)stream->handler; + sc_memory_buffer * buffer = (sc_memory_buffer *)stream->handler; g_assert(buffer != 0); switch (origin) @@ -74,9 +73,9 @@ sc_result sc_stream_memory_seek(const sc_stream *stream, sc_stream_seek_origin o return SC_RESULT_OK; } -sc_result sc_stream_memory_tell(const sc_stream *stream, sc_uint32 *position) +sc_result sc_stream_memory_tell(const sc_stream * stream, sc_uint32 * position) { - sc_memory_buffer *buffer = (sc_memory_buffer*)stream->handler; + sc_memory_buffer * buffer = (sc_memory_buffer *)stream->handler; g_assert(buffer != 0); *position = buffer->pos; @@ -84,9 +83,9 @@ sc_result sc_stream_memory_tell(const sc_stream *stream, sc_uint32 *position) return SC_RESULT_OK; } -sc_result sc_stream_memory_free_handler(const sc_stream *stream) +sc_result sc_stream_memory_free_handler(const sc_stream * stream) { - sc_memory_buffer *buffer = (sc_memory_buffer*)stream->handler; + sc_memory_buffer * buffer = (sc_memory_buffer *)stream->handler; g_assert(buffer != 0); if (buffer->data_owner == SC_TRUE) @@ -100,9 +99,9 @@ sc_result sc_stream_memory_free_handler(const sc_stream *stream) return SC_RESULT_OK; } -sc_bool sc_stream_memory_eof(const sc_stream *stream) +sc_bool sc_stream_memory_eof(const sc_stream * stream) { - sc_memory_buffer *buffer = (sc_memory_buffer*)stream->handler; + sc_memory_buffer * buffer = (sc_memory_buffer *)stream->handler; g_assert(buffer != 0); if (buffer->pos == buffer->size) @@ -111,8 +110,7 @@ sc_bool sc_stream_memory_eof(const sc_stream *stream) return SC_FALSE; } - -sc_stream* sc_stream_memory_new(const sc_char *buffer, sc_uint buffer_size, sc_uint8 flags, sc_bool data_owner) +sc_stream * sc_stream_memory_new(const sc_char * buffer, sc_uint buffer_size, sc_uint8 flags, sc_bool data_owner) { if (flags & SC_STREAM_FLAG_WRITE || flags & SC_STREAM_FLAG_APPEND) { @@ -123,14 +121,14 @@ sc_stream* sc_stream_memory_new(const sc_char *buffer, sc_uint buffer_size, sc_u g_assert(flags & SC_STREAM_FLAG_READ); g_assert(buffer != null_ptr); - sc_memory_buffer *data_buffer = g_new0(sc_memory_buffer, 1); + sc_memory_buffer * data_buffer = g_new0(sc_memory_buffer, 1); - data_buffer->data = (char*)buffer; + data_buffer->data = (char *)buffer; data_buffer->size = buffer_size; data_buffer->pos = 0; data_buffer->data_owner = data_owner; - sc_stream *stream = g_new0(sc_stream, 1); + sc_stream * stream = g_new0(sc_stream, 1); // tell and seek supported anyway stream->flags = flags | SC_STREAM_FLAG_SEEK | SC_STREAM_FLAG_TELL; @@ -141,7 +139,7 @@ sc_stream* sc_stream_memory_new(const sc_char *buffer, sc_uint buffer_size, sc_u stream->read_func = &sc_stream_memory_read; stream->seek_func = &sc_stream_memory_seek; stream->tell_func = &sc_stream_memory_tell; - stream->write_func = 0; // doesn't support writing + stream->write_func = 0; // doesn't support writing return stream; } diff --git a/sc-memory/sc-core/sc-store/sc_stream_memory.h b/sc-memory/sc-core/sc-store/sc_stream_memory.h index 7f8ff43688..64ced3e13d 100644 --- a/sc-memory/sc-core/sc-store/sc_stream_memory.h +++ b/sc-memory/sc-core/sc-store/sc_stream_memory.h @@ -18,6 +18,10 @@ * @remarks The returned stream pointer should be freed with sc_stream_free function, when done using it. * @return Returns stream pointer if the stream was successfully created, or NULL if an error occurred */ -_SC_EXTERN sc_stream* sc_stream_memory_new(const sc_char *buffer, sc_uint buffer_size, sc_uint8 flags, sc_bool data_owner); +_SC_EXTERN sc_stream * sc_stream_memory_new( + const sc_char * buffer, + sc_uint buffer_size, + sc_uint8 flags, + sc_bool data_owner); -#endif // SC_STREAM_MEMORY_H +#endif // SC_STREAM_MEMORY_H diff --git a/sc-memory/sc-core/sc-store/sc_stream_private.h b/sc-memory/sc-core/sc-store/sc_stream_private.h index edde7271a4..d306c5dc2f 100644 --- a/sc-memory/sc-core/sc-store/sc_stream_private.h +++ b/sc-memory/sc-core/sc-store/sc_stream_private.h @@ -12,35 +12,36 @@ /*! Pointer to stream read function. This function read data into specified \i buffer with * fixed \i length and return number of bytes, that has been read. */ -typedef sc_result (*fStreamRead)(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_read); +typedef sc_result (*fStreamRead)(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_read); /*! Pointer to stream write function. This function write data into pointer from specifed \i buffer * with fixed \i length and return number of bytes, that has been written */ -typedef sc_result (*fStreamWrite)(const sc_stream *stream, sc_char *data, sc_uint32 length, sc_uint32 *bytes_written); +typedef sc_result ( + *fStreamWrite)(const sc_stream * stream, sc_char * data, sc_uint32 length, sc_uint32 * bytes_written); /*! Pointer to stream seek function. This function to seek data in stream from \i origin with \i offset. */ -typedef sc_result (*fStreamSeek)(const sc_stream *stream, sc_stream_seek_origin origin, sc_uint32 offset); +typedef sc_result (*fStreamSeek)(const sc_stream * stream, sc_stream_seek_origin origin, sc_uint32 offset); /*! Pointer to stream tell function. This function return \i position in file */ -typedef sc_result (*fStreamTell)(const sc_stream *stream, sc_uint32 *position); +typedef sc_result (*fStreamTell)(const sc_stream * stream, sc_uint32 * position); /*! Pointer to stream eof function. This function return SC_TRUE, if current position in stream is at the end */ -typedef sc_bool (*fStreamEof)(const sc_stream *stream); +typedef sc_bool (*fStreamEof)(const sc_stream * stream); /*! Pointer to stream handler free function. This function destroys stream handler. */ -typedef sc_result (*fStreamFreeHandler)(const sc_stream *stream); +typedef sc_result (*fStreamFreeHandler)(const sc_stream * stream); /*! Structure to store stream information */ struct _sc_stream { //! Pointer to resource handle (file handle, network handle, ...) - void *handler; + void * handler; //! Access flags (read, write, append, ...) sc_uint8 flags; //! Pointer to a function that reads data from stream @@ -57,5 +58,4 @@ struct _sc_stream fStreamEof eof_func; }; - #endif diff --git a/sc-memory/sc-core/sc-store/sc_types.h b/sc-memory/sc-core/sc-store/sc_types.h index 8a5dd748c5..d08f86f761 100644 --- a/sc-memory/sc-core/sc-store/sc_types.h +++ b/sc-memory/sc-core/sc-store/sc_types.h @@ -13,7 +13,7 @@ #include #ifndef null_ptr -#define null_ptr ((void*)0) +# define null_ptr ((void *)0) #endif // base types @@ -34,7 +34,7 @@ typedef sc_uint32 sc_uint; typedef char sc_char; typedef unsigned char sc_uchar; -typedef void* sc_pointer; +typedef void * sc_pointer; #define sc_min(a, b) ((a) < (b) ? (a) : (b)) #define sc_max(a, b) ((a) > (b) ? (a) : (b)) @@ -46,23 +46,23 @@ typedef void* sc_pointer; typedef sc_int sc_bool; // types limits -#define SC_MININT8 ((sc_int8) 0x80) -#define SC_MAXINT8 ((sc_int8) 0x7f) -#define SC_MAXUINT8 ((sc_uint8) 0xff) +#define SC_MININT8 ((sc_int8)0x80) +#define SC_MAXINT8 ((sc_int8)0x7f) +#define SC_MAXUINT8 ((sc_uint8)0xff) -#define SC_MININT16 ((sc_int16) 0x8000) -#define SC_MAXINT16 ((sc_int16) 0x7fff) -#define SC_MAXUINT16 ((sc_uint16) 0xffff) +#define SC_MININT16 ((sc_int16)0x8000) +#define SC_MAXINT16 ((sc_int16)0x7fff) +#define SC_MAXUINT16 ((sc_uint16)0xffff) -#define SC_MININT32 ((sc_int32) 0x80000000) -#define SC_MAXINT32 ((sc_int32) 0x7fffffff) -#define SC_MAXUINT32 ((sc_uint32) 0xffffffff) +#define SC_MININT32 ((sc_int32)0x80000000) +#define SC_MAXINT32 ((sc_int32)0x7fffffff) +#define SC_MAXUINT32 ((sc_uint32)0xffffffff) -#define SC_ADDR_SEG_MAX SC_MAXUINT16 -#define SC_ADDR_OFFSET_MAX SC_MAXUINT16 +#define SC_ADDR_SEG_MAX SC_MAXUINT16 +#define SC_ADDR_OFFSET_MAX SC_MAXUINT16 -#define SC_SEGMENT_ELEMENTS_COUNT SC_MAXUINT16 // number of elements in segment -#define SC_SEGMENT_MAX SC_MAXUINT16 // max number of segments +#define SC_SEGMENT_ELEMENTS_COUNT SC_MAXUINT16 // number of elements in segment +#define SC_SEGMENT_MAX SC_MAXUINT16 // max number of segments // Types for segment and offset typedef sc_uint16 sc_addr_seg; @@ -76,7 +76,11 @@ struct _sc_addr }; //! Make sc-addr empty -#define SC_ADDR_MAKE_EMPTY(addr) { (addr).seg = 0; (addr).offset = 0; } +#define SC_ADDR_MAKE_EMPTY(addr) \ + { \ + (addr).seg = 0; \ + (addr).offset = 0; \ + } //! Check if specified sc-addr is empty #define SC_ADDR_IS_EMPTY(addr) (((addr).seg == 0) && ((addr).offset == 0)) #define SC_ADDR_IS_NOT_EMPTY(addr) (!SC_ADDR_IS_EMPTY(addr)) @@ -88,68 +92,72 @@ struct _sc_addr * and get them back from int */ #define SC_ADDR_LOCAL_TO_INT(addr) (sc_uint32)(((addr).seg << 16) | ((addr).offset & 0xffff)) -#define SC_ADDR_LOCAL_OFFSET_FROM_INT(v) (sc_uint16)((v) & 0x0000ffff) +#define SC_ADDR_LOCAL_OFFSET_FROM_INT(v) (sc_uint16)((v)&0x0000ffff) #define SC_ADDR_LOCAL_SEG_FROM_INT(v) SC_ADDR_LOCAL_OFFSET_FROM_INT(v >> 16) typedef sc_uint16 sc_type; // sc-element types -#define sc_type_node (sc_type)0x1 -#define sc_type_link (sc_type)0x2 +#define sc_type_node (sc_type)0x1 +#define sc_type_link (sc_type)0x2 #define sc_type_edge_common (sc_type)0x4 -#define sc_type_arc_common (sc_type)0x8 -#define sc_type_arc_access (sc_type)0x10 +#define sc_type_arc_common (sc_type)0x8 +#define sc_type_arc_access (sc_type)0x10 // sc-element constant -#define sc_type_const (sc_type)0x20 -#define sc_type_var (sc_type)0x40 +#define sc_type_const (sc_type)0x20 +#define sc_type_var (sc_type)0x40 // sc-element positivity -#define sc_type_arc_pos (sc_type)0x80 -#define sc_type_arc_neg (sc_type)0x100 -#define sc_type_arc_fuz (sc_type)0x200 +#define sc_type_arc_pos (sc_type)0x80 +#define sc_type_arc_neg (sc_type)0x100 +#define sc_type_arc_fuz (sc_type)0x200 // sc-element premanently -#define sc_type_arc_temp (sc_type)0x400 -#define sc_type_arc_perm (sc_type)0x800 +#define sc_type_arc_temp (sc_type)0x400 +#define sc_type_arc_perm (sc_type)0x800 // struct node types -#define sc_type_node_tuple (sc_type)(0x80) -#define sc_type_node_struct (sc_type)(0x100) -#define sc_type_node_role (sc_type)(0x200) -#define sc_type_node_norole (sc_type)(0x400) -#define sc_type_node_class (sc_type)(0x800) -#define sc_type_node_abstract (sc_type)(0x1000) -#define sc_type_node_material (sc_type)(0x2000) +#define sc_type_node_tuple (sc_type)(0x80) +#define sc_type_node_struct (sc_type)(0x100) +#define sc_type_node_role (sc_type)(0x200) +#define sc_type_node_norole (sc_type)(0x400) +#define sc_type_node_class (sc_type)(0x800) +#define sc_type_node_abstract (sc_type)(0x1000) +#define sc_type_node_material (sc_type)(0x2000) #define sc_type_arc_pos_const_perm (sc_type)(sc_type_arc_access | sc_type_const | sc_type_arc_pos | sc_type_arc_perm) #define sc_type_arc_pos_var_perm (sc_type)(sc_type_arc_access | sc_type_var | sc_type_arc_pos | sc_type_arc_perm) // type mask -#define sc_type_element_mask (sc_type)(sc_type_node | sc_type_link | sc_type_edge_common | sc_type_arc_common | sc_type_arc_access) -#define sc_type_constancy_mask (sc_type)(sc_type_const | sc_type_var) -#define sc_type_positivity_mask (sc_type)(sc_type_arc_pos | sc_type_arc_neg | sc_type_arc_fuz) -#define sc_type_permanency_mask (sc_type)(sc_type_arc_perm | sc_type_arc_temp) -#define sc_type_node_mask (sc_type)(sc_type_node_tuple | sc_type_node_struct | sc_type_node_role | sc_type_node_norole | sc_type_node_class | sc_type_node_abstract | sc_type_node_material) -#define sc_type_arc_mask (sc_type)(sc_type_arc_access | sc_type_arc_common | sc_type_edge_common) +#define sc_type_element_mask \ + (sc_type)(sc_type_node | sc_type_link | sc_type_edge_common | sc_type_arc_common | sc_type_arc_access) +#define sc_type_constancy_mask (sc_type)(sc_type_const | sc_type_var) +#define sc_type_positivity_mask (sc_type)(sc_type_arc_pos | sc_type_arc_neg | sc_type_arc_fuz) +#define sc_type_permanency_mask (sc_type)(sc_type_arc_perm | sc_type_arc_temp) +#define sc_type_node_mask \ + (sc_type)( \ + sc_type_node_tuple | sc_type_node_struct | sc_type_node_role | sc_type_node_norole | sc_type_node_class | \ + sc_type_node_abstract | sc_type_node_material) +#define sc_type_arc_mask (sc_type)(sc_type_arc_access | sc_type_arc_common | sc_type_edge_common) // just for internal usage -#define sc_flag_request_deletion (0x4000) +#define sc_flag_request_deletion (0x4000) #define sc_flag_link_self_container (0x8000) -#define sc_flags_remove(x) ((x) & ~(sc_flag_request_deletion | sc_flag_link_self_container)) +#define sc_flags_remove(x) ((x) & ~(sc_flag_request_deletion | sc_flag_link_self_container)) // locks -#define sc_lock_out_in 0x1 -#define sc_lock_del 0x2 -#define sc_lock_change 0x4 -#define sc_lock_read 0x8 +#define sc_lock_out_in 0x1 +#define sc_lock_del 0x2 +#define sc_lock_change 0x4 +#define sc_lock_read 0x8 // access levels -#define SC_ACCESS_LVL_MAX_VALUE 15 -#define SC_ACCESS_LVL_MIN_VALUE 0 +#define SC_ACCESS_LVL_MAX_VALUE 15 +#define SC_ACCESS_LVL_MIN_VALUE 0 -#define SC_ACCESS_LVL_RMASK 0xf0 -#define SC_ACCESS_LVL_WMASK 0x0f +#define SC_ACCESS_LVL_RMASK 0xf0 +#define SC_ACCESS_LVL_WMASK 0x0f #define sc_access_lvl_get_read(levels) ((levels & SC_ACCESS_LVL_RMASK) >> 4) #define sc_access_lvl_get_write(levels) (levels & SC_ACCESS_LVL_WMASK) @@ -159,8 +167,12 @@ typedef sc_uint16 sc_type; #define sc_access_lvl_make_max sc_access_lvl_make(SC_ACCESS_LVL_MAX_VALUE, SC_ACCESS_LVL_MAX_VALUE) #define sc_access_lvl_make_min sc_access_lvl_make(SC_ACCESS_LVL_MIN_VALUE, SC_ACCESS_LVL_MIN_VALUE) -#define sc_access_lvl_min(a, b) (sc_min(((a) & SC_ACCESS_LVL_RMASK), ((b) & SC_ACCESS_LVL_RMASK)) | sc_min(((a) & SC_ACCESS_LVL_WMASK), ((b) & SC_ACCESS_LVL_WMASK))) -#define sc_access_lvl_max(a, b) (sc_max(((a) & SC_ACCESS_LVL_RMASK), ((b) & SC_ACCESS_LVL_RMASK)) | sc_max(((a) & SC_ACCESS_LVL_WMASK), ((b) & SC_ACCESS_LVL_WMASK))) +#define sc_access_lvl_min(a, b) \ + (sc_min(((a)&SC_ACCESS_LVL_RMASK), ((b)&SC_ACCESS_LVL_RMASK)) | \ + sc_min(((a)&SC_ACCESS_LVL_WMASK), ((b)&SC_ACCESS_LVL_WMASK))) +#define sc_access_lvl_max(a, b) \ + (sc_max(((a)&SC_ACCESS_LVL_RMASK), ((b)&SC_ACCESS_LVL_RMASK)) | \ + sc_max(((a)&SC_ACCESS_LVL_WMASK), ((b)&SC_ACCESS_LVL_WMASK))) #define sc_access_lvl_check_read(c, e) (sc_access_lvl_get_read(c) >= sc_access_lvl_get_read(e)) #define sc_access_lvl_check_write(c, e) (sc_access_lvl_get_write(c) >= sc_access_lvl_get_write(e)) @@ -168,31 +180,31 @@ typedef sc_uint16 sc_type; enum _sc_result { // SC_RESULT_ERROR should be 0 anytime - SC_RESULT_ERROR = 0, // unknown error - // SC_RESULT_OK should be 1 anytime - SC_RESULT_OK = 1, // no any error - SC_RESULT_ERROR_INVALID_PARAMS, // invalid function parameters error - SC_RESULT_ERROR_INVALID_TYPE, // invalied type error - SC_RESULT_ERROR_IO, // input/output error - SC_RESULT_ERROR_INVALID_STATE, // invalid state of processed object - SC_RESULT_ERROR_NOT_FOUND, // item not found - SC_RESULT_ERROR_NO_WRITE_RIGHTS, // no ritghs to change or delete object - SC_RESULT_ERROR_NO_READ_RIGHTS, // no ritghs to read object - SC_RESULT_NO, // no any result - SC_RESULT_UNKNOWN, // result unknown + SC_RESULT_ERROR = 0, // unknown error + // SC_RESULT_OK should be 1 anytime + SC_RESULT_OK = 1, // no any error + SC_RESULT_ERROR_INVALID_PARAMS, // invalid function parameters error + SC_RESULT_ERROR_INVALID_TYPE, // invalied type error + SC_RESULT_ERROR_IO, // input/output error + SC_RESULT_ERROR_INVALID_STATE, // invalid state of processed object + SC_RESULT_ERROR_NOT_FOUND, // item not found + SC_RESULT_ERROR_NO_WRITE_RIGHTS, // no ritghs to change or delete object + SC_RESULT_ERROR_NO_READ_RIGHTS, // no ritghs to read object + SC_RESULT_NO, // no any result + SC_RESULT_UNKNOWN, // result unknown // add atomic types before - SC_RESULT_COUNT, // number of result types + SC_RESULT_COUNT, // number of result types SC_RESULT_ERROR_NO_RIGHTS = SC_RESULT_ERROR_NO_WRITE_RIGHTS | SC_RESULT_ERROR_NO_READ_RIGHTS }; // contents -#define SC_MAX_CHECKSUM_LEN 32 +#define SC_MAX_CHECKSUM_LEN 32 //! Structure to store checksum informaiton struct _sc_check_sum { char data[SC_MAX_CHECKSUM_LEN]; // maximum checksum length - sc_uint8 len; // checksum length + sc_uint8 len; // checksum length }; // events @@ -210,17 +222,16 @@ enum _sc_event_type // structure to store statistics info struct _sc_stat { - sc_uint32 node_count; // amount of all sc-nodes stored in memory - sc_uint32 arc_count; // amount of all sc-arcs stored in memory - sc_uint32 link_count; // amount of all sc-links stored in memory + sc_uint32 node_count; // amount of all sc-nodes stored in memory + sc_uint32 arc_count; // amount of all sc-arcs stored in memory + sc_uint32 link_count; // amount of all sc-links stored in memory - sc_uint32 empty_count; // amount of empty sc-element cells + sc_uint32 empty_count; // amount of empty sc-element cells sc_uint32 segments_count; }; - typedef struct _sc_check_sum sc_check_sum; -typedef struct _sc_arc sc_arc; +typedef struct _sc_arc sc_arc; typedef struct _sc_content sc_content; typedef struct _sc_arc_info sc_arc_info; typedef sc_uint8 sc_access_levels; @@ -241,7 +252,6 @@ typedef enum _sc_result sc_result; typedef enum _sc_event_type sc_event_type; typedef struct _sc_stat sc_stat; - _SC_EXTERN sc_pointer sc_thread(); #endif diff --git a/sc-memory/sc-core/sc_helper.c b/sc-memory/sc-core/sc_helper.c index fe5b0cb355..1e236ff205 100644 --- a/sc-memory/sc-core/sc_helper.c +++ b/sc-memory/sc-core/sc_helper.c @@ -13,18 +13,20 @@ // sc-helper initialization flag sc_bool sc_helper_is_initialized = SC_FALSE; -sc_char **keynodes_str = 0; -sc_addr *sc_keynodes = 0; +sc_char ** keynodes_str = 0; +sc_addr * sc_keynodes = 0; sc_result resolve_nrel_system_identifier(sc_memory_context const * ctx) { - sc_addr *results = 0; + sc_addr * results = 0; sc_uint32 results_count = 0; - sc_stream *stream = sc_stream_memory_new(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], - (sc_uint)(sizeof(sc_uchar) * strlen(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER])), - SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * stream = sc_stream_memory_new( + keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], + (sc_uint)(sizeof(sc_uchar) * strlen(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER])), + SC_STREAM_FLAG_READ, + SC_FALSE); sc_uint32 i = 0; - sc_iterator5 *it = 0; + sc_iterator5 * it = 0; sc_bool found = SC_FALSE; sc_addr addr1, addr2; @@ -33,16 +35,16 @@ sc_result resolve_nrel_system_identifier(sc_memory_context const * ctx) { for (i = 0; i < results_count; i++) { - it = sc_iterator5_a_a_f_a_a_new(ctx, - sc_type_node | sc_type_const | sc_type_node_norole, - sc_type_arc_common | sc_type_const, - results[i], - sc_type_arc_pos_const_perm, - sc_type_const | sc_type_node | sc_type_node_norole); + it = sc_iterator5_a_a_f_a_a_new( + ctx, + sc_type_node | sc_type_const | sc_type_node_norole, + sc_type_arc_common | sc_type_const, + results[i], + sc_type_arc_pos_const_perm, + sc_type_const | sc_type_node | sc_type_node_norole); while (sc_iterator5_next(it)) { - addr1 = sc_iterator5_value(it, 0); addr2 = sc_iterator5_value(it, 4); // comare begin sc-element and attribute, they must be equivalent @@ -80,9 +82,9 @@ void _init_keynodes_str() gsize bytes_read = 0, bytes_written = 0; sc_uint32 i = 0; - keynodes_str = g_new0(gchar*, SC_KEYNODE_COUNT); - keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER] = g_locale_to_utf8("nrel_system_identifier", -1, &bytes_read, &bytes_written, 0); - + keynodes_str = g_new0(gchar *, SC_KEYNODE_COUNT); + keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER] = + g_locale_to_utf8("nrel_system_identifier", -1, &bytes_read, &bytes_written, 0); // check for errors for (i = 0; i < (sc_uint32)SC_KEYNODE_COUNT; ++i) @@ -90,7 +92,6 @@ void _init_keynodes_str() if (keynodes_str[(sc_keynode)i] == null_ptr) g_error("Error to create string representation of keynode: %d", i); } - } void _destroy_keynodes_str() @@ -116,9 +117,11 @@ sc_result sc_helper_init(sc_memory_context * ctx) g_message("Can't resovle nrel_system_identifier node. Create the last one"); sc_addr addr = sc_memory_node_new(ctx, sc_type_const | sc_type_node_norole); sc_addr link = sc_memory_link_new(ctx); - sc_stream *stream = sc_stream_memory_new(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], - (sc_uint)(sizeof(sc_uchar) * strlen(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER])), - SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * stream = sc_stream_memory_new( + keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], + (sc_uint)(sizeof(sc_uchar) * strlen(keynodes_str[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER])), + SC_STREAM_FLAG_READ, + SC_FALSE); sc_memory_set_link_content(ctx, link, stream); sc_stream_free(stream); @@ -140,13 +143,17 @@ void sc_helper_shutdown() _destroy_keynodes_str(); } -sc_result sc_helper_find_element_by_system_identifier(sc_memory_context const * ctx, const sc_char* data, sc_uint32 len, sc_addr *result_addr) +sc_result sc_helper_find_element_by_system_identifier( + sc_memory_context const * ctx, + const sc_char * data, + sc_uint32 len, + sc_addr * result_addr) { - sc_addr *results = 0; + sc_addr * results = 0; sc_uint32 results_count = 0; - sc_stream *stream = 0; + sc_stream * stream = 0; sc_uint32 i = 0; - sc_iterator5 *it = 0; + sc_iterator5 * it = 0; sc_bool found = SC_FALSE; g_assert(sc_helper_is_initialized == SC_TRUE); @@ -158,12 +165,13 @@ sc_result sc_helper_find_element_by_system_identifier(sc_memory_context const * { for (i = 0; i < results_count; i++) { - it = sc_iterator5_a_a_f_a_f_new(ctx, - 0, - sc_type_arc_common | sc_type_const, - results[i], - sc_type_arc_pos_const_perm, - sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); + it = sc_iterator5_a_a_f_a_f_new( + ctx, + 0, + sc_type_arc_common | sc_type_const, + results[i], + sc_type_arc_pos_const_perm, + sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); if (sc_iterator5_next(it)) { if (found == SC_FALSE) @@ -192,17 +200,17 @@ sc_result sc_helper_find_element_by_system_identifier(sc_memory_context const * return found == SC_TRUE ? SC_RESULT_OK : SC_RESULT_ERROR; } -sc_result sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, const sc_char* data, sc_uint32 len) +sc_result sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, const sc_char * data, sc_uint32 len) { - sc_iterator5 *it5 = 0; - sc_addr *results = 0; + sc_iterator5 * it5 = 0; + sc_addr * results = 0; sc_uint32 results_count = 0; - sc_stream *stream = 0; + sc_stream * stream = 0; sc_uint32 i = 0; sc_addr idtf_addr, arc_addr; SC_ADDR_MAKE_EMPTY(idtf_addr) - g_assert(sc_keynodes != 0); + g_assert(sc_keynodes != 0); // check if specified system identifier already used stream = sc_stream_memory_new(data, sizeof(sc_char) * len, SC_STREAM_FLAG_READ, SC_FALSE); @@ -210,12 +218,13 @@ sc_result sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, { for (i = 0; i < results_count; i++) { - it5 = sc_iterator5_a_a_f_a_f_new(ctx, - 0, - sc_type_arc_common | sc_type_const, - results[i], - sc_type_arc_pos_const_perm, - sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); + it5 = sc_iterator5_a_a_f_a_f_new( + ctx, + 0, + sc_type_arc_common | sc_type_const, + results[i], + sc_type_arc_pos_const_perm, + sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); if (sc_iterator5_next(it5)) { // don't foget to free allocated memory before return error @@ -247,24 +256,26 @@ sc_result sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, if (SC_ADDR_IS_EMPTY(arc_addr)) return SC_RESULT_ERROR; - arc_addr = sc_memory_arc_new(ctx, sc_type_arc_pos_const_perm, sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], arc_addr); + arc_addr = + sc_memory_arc_new(ctx, sc_type_arc_pos_const_perm, sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER], arc_addr); if (SC_ADDR_IS_EMPTY(arc_addr)) return SC_RESULT_ERROR; return SC_RESULT_OK; } -sc_result sc_helper_get_system_identifier_link(sc_memory_context const * ctx, sc_addr el, sc_addr *sys_idtf_addr) +sc_result sc_helper_get_system_identifier_link(sc_memory_context const * ctx, sc_addr el, sc_addr * sys_idtf_addr) { - sc_iterator5 *it = 0; + sc_iterator5 * it = 0; sc_result res = SC_RESULT_ERROR; - it = sc_iterator5_f_a_a_a_f_new(ctx, - el, - sc_type_arc_common | sc_type_const, - sc_type_link, - sc_type_arc_pos_const_perm, - sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); + it = sc_iterator5_f_a_a_a_f_new( + ctx, + el, + sc_type_arc_common | sc_type_const, + sc_type_link, + sc_type_arc_pos_const_perm, + sc_keynodes[SC_KEYNODE_NREL_SYSTEM_IDENTIFIER]); g_assert(it != null_ptr); while (sc_iterator5_next(it) == SC_TRUE) @@ -278,7 +289,7 @@ sc_result sc_helper_get_system_identifier_link(sc_memory_context const * ctx, sc return res; } -sc_result sc_helper_get_keynode(sc_memory_context const * ctx, sc_keynode keynode, sc_addr *keynode_addr) +sc_result sc_helper_get_keynode(sc_memory_context const * ctx, sc_keynode keynode, sc_addr * keynode_addr) { if ((sc_helper_is_initialized == SC_FALSE) || (sc_keynodes == null_ptr)) return SC_RESULT_ERROR; @@ -288,9 +299,9 @@ sc_result sc_helper_get_keynode(sc_memory_context const * ctx, sc_keynode keynod return SC_RESULT_OK; } -sc_bool sc_helper_resolve_system_identifier(sc_memory_context const * ctx, const char *system_idtf, sc_addr *result) +sc_bool sc_helper_resolve_system_identifier(sc_memory_context const * ctx, const char * system_idtf, sc_addr * result) { - gchar *keynode_idtf = 0; + gchar * keynode_idtf = 0; gsize bytes_written = 0; keynode_idtf = g_locale_to_utf8(system_idtf, -1, 0, &bytes_written, 0); @@ -310,7 +321,7 @@ sc_bool sc_helper_resolve_system_identifier(sc_memory_context const * ctx, const sc_bool sc_helper_check_arc(sc_memory_context const * ctx, sc_addr beg_el, sc_addr end_el, sc_type arc_type) { - sc_iterator3 *it = 0; + sc_iterator3 * it = 0; sc_bool res = SC_FALSE; it = sc_iterator3_f_a_f_new(ctx, beg_el, arc_type, end_el); @@ -324,8 +335,6 @@ sc_bool sc_helper_check_arc(sc_memory_context const * ctx, sc_addr beg_el, sc_ad return res; } - - sc_bool sc_helper_check_version_equal(sc_uint8 major, sc_uint8 minor, sc_uint8 patch) { sc_version v = {major, minor, patch, 0}; diff --git a/sc-memory/sc-core/sc_helper.h b/sc-memory/sc-core/sc_helper.h index ca8691dce6..43b5606494 100644 --- a/sc-memory/sc-core/sc_helper.h +++ b/sc-memory/sc-core/sc_helper.h @@ -12,13 +12,12 @@ //! Enumeration of sc-keynodes enum _sc_keynode { - SC_KEYNODE_NREL_SYSTEM_IDENTIFIER = 0, // nrel_system_identifier + SC_KEYNODE_NREL_SYSTEM_IDENTIFIER = 0, // nrel_system_identifier SC_KEYNODE_COUNT }; typedef enum _sc_keynode sc_keynode; - /*! Finds sc-addr of element with specified system identifier * @param data Buffer that contains system identifier for sc-element (must be an UTF-8 encoded) * @param len Length of data buffer @@ -28,7 +27,11 @@ typedef enum _sc_keynode sc_keynode; * specified system identifier, then return SC_RESULT_ERROR_INVALID_STATE, but result_addr will contains sc-addr * of firstly found sc-element. */ -_SC_EXTERN sc_result sc_helper_find_element_by_system_identifier(sc_memory_context const * ctx, const sc_char* data, sc_uint32 len, sc_addr *result_addr); +_SC_EXTERN sc_result sc_helper_find_element_by_system_identifier( + sc_memory_context const * ctx, + const sc_char * data, + sc_uint32 len, + sc_addr * result_addr); /*! Setup new system identifier for specified sc-element * @param addr sc-addr of sc-element to setup new system identifier @@ -37,14 +40,16 @@ _SC_EXTERN sc_result sc_helper_find_element_by_system_identifier(sc_memory_conte * @remarks If sc-element already has system identifier, then it would be replaced. If system identifier * already used for another sc-element, then function returns SC_ERROR_INVALID_PARAMS */ -_SC_EXTERN sc_result sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, const sc_char* data, sc_uint32 len); +_SC_EXTERN sc_result +sc_helper_set_system_identifier(sc_memory_context * ctx, sc_addr addr, const sc_char * data, sc_uint32 len); /*! Return sc-addr of system identifier for specified sc-element * @param el sc-addr of element to get it system identifier * @param sys_idtf_addr Pointer to found sc-addr of system identifier * @return If system identifier found, then return SC_RESULT_OK; otherwise return SC_RESULT_ERROR */ -_SC_EXTERN sc_result sc_helper_get_system_identifier_link(sc_memory_context const * ctx, sc_addr el, sc_addr *sys_idtf_addr); +_SC_EXTERN sc_result +sc_helper_get_system_identifier_link(sc_memory_context const * ctx, sc_addr el, sc_addr * sys_idtf_addr); /*! Returns sc-addr of specified sc-keynode * @param keynode Code of specified sc-keynode @@ -52,14 +57,15 @@ _SC_EXTERN sc_result sc_helper_get_system_identifier_link(sc_memory_context cons * @return If specified keynode exist, then return SC_OK and keynode_addr contains sc-addr of this one; * otherwise return SC_ERROR */ -_SC_EXTERN sc_result sc_helper_get_keynode(sc_memory_context const * ctx, sc_keynode keynode, sc_addr *keynode_addr); +_SC_EXTERN sc_result sc_helper_get_keynode(sc_memory_context const * ctx, sc_keynode keynode, sc_addr * keynode_addr); /*! Resolve sc-elemen by specified string system identifier * @param system_idtf String that represents system identifier (it will be converted into utf-8) * @param result Pointer to result sc-addr container * @return If sc-element was founded, then return SC_TRUE; otherwise return SC_FALSE. */ -_SC_EXTERN sc_bool sc_helper_resolve_system_identifier(sc_memory_context const * ctx, const char *system_idtf, sc_addr *result); +_SC_EXTERN sc_bool +sc_helper_resolve_system_identifier(sc_memory_context const * ctx, const char * system_idtf, sc_addr * result); /*! Check if specified arc type exist between two objects * @param beg_el sc-addr of begin element @@ -70,13 +76,10 @@ _SC_EXTERN sc_bool sc_helper_resolve_system_identifier(sc_memory_context const * */ _SC_EXTERN sc_bool sc_helper_check_arc(sc_memory_context const * ctx, sc_addr beg_el, sc_addr end_el, sc_type arc_type); - /*! Check if current version equal to specified * @return If version equal to current memory version, then function returns SC_TRUE; * otherwise it returns SC_FALSE */ _SC_EXTERN sc_bool sc_helper_check_version_equal(sc_uint8 major, sc_uint8 minor, sc_uint8 patch); - - -#endif // IDENTIFICATION_H +#endif // IDENTIFICATION_H diff --git a/sc-memory/sc-core/sc_helper_private.h b/sc-memory/sc-core/sc_helper_private.h index 713c8cc18e..d7344f840d 100644 --- a/sc-memory/sc-core/sc_helper_private.h +++ b/sc-memory/sc-core/sc_helper_private.h @@ -21,5 +21,4 @@ sc_result sc_helper_init(sc_memory_context const * ctx); */ void sc_helper_shutdown(); - #endif diff --git a/sc-memory/sc-core/sc_memory.c b/sc-memory/sc-core/sc_memory.c index dda4560a8d..a8870dc1f6 100644 --- a/sc-memory/sc-core/sc_memory.c +++ b/sc-memory/sc-core/sc_memory.c @@ -26,10 +26,10 @@ sc_pointer sc_thread() sc_memory_context * s_memory_default_ctx = 0; sc_uint16 s_context_id_last = 1; sc_uint32 s_context_id_count = 0; -GHashTable *s_context_hash_table = 0; +GHashTable * s_context_hash_table = 0; GMutex s_concurrency_mutex; -void sc_memory_params_clear(sc_memory_params *params) +void sc_memory_params_clear(sc_memory_params * params) { params->clear = SC_FALSE; params->config_file = 0; @@ -38,7 +38,7 @@ void sc_memory_params_clear(sc_memory_params *params) params->enabled_exts = 0; } -sc_memory_context* sc_memory_initialize(const sc_memory_params *params) +sc_memory_context * sc_memory_initialize(const sc_memory_params * params) { g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); @@ -46,7 +46,7 @@ sc_memory_context* sc_memory_initialize(const sc_memory_params *params) s_context_hash_table = g_hash_table_new(g_direct_hash, g_direct_equal); - char *v_str = sc_version_string_new(&SC_VERSION); + char * v_str = sc_version_string_new(&SC_VERSION); g_message("Version: %s", v_str); sc_version_string_free(v_str); @@ -58,7 +58,8 @@ sc_memory_context* sc_memory_initialize(const sc_memory_params *params) return 0; s_memory_default_ctx = sc_memory_context_new(sc_access_lvl_make(SC_ACCESS_LVL_MAX_VALUE, SC_ACCESS_LVL_MAX_VALUE)); - sc_memory_context *helper_ctx = sc_memory_context_new(sc_access_lvl_make(SC_ACCESS_LVL_MIN_VALUE, SC_ACCESS_LVL_MAX_VALUE)); + sc_memory_context * helper_ctx = + sc_memory_context_new(sc_access_lvl_make(SC_ACCESS_LVL_MIN_VALUE, SC_ACCESS_LVL_MAX_VALUE)); if (sc_helper_init(helper_ctx) != SC_RESULT_OK) goto error; sc_memory_context_free(helper_ctx); @@ -76,13 +77,13 @@ sc_memory_context* sc_memory_initialize(const sc_memory_params *params) } return s_memory_default_ctx; - + error: - { - if (helper_ctx) - sc_memory_context_free(helper_ctx); - sc_memory_context_free(s_memory_default_ctx); - } +{ + if (helper_ctx) + sc_memory_context_free(helper_ctx); + sc_memory_context_free(s_memory_default_ctx); +} return (s_memory_default_ctx = null_ptr); } @@ -109,7 +110,6 @@ sc_result sc_memory_init_ext(sc_char const * ext_path, const sc_char ** enabled_ return ext_res; } - void sc_memory_shutdown(sc_bool save_state) { sc_events_stop_processing(); @@ -138,14 +138,14 @@ void sc_memory_shutdown_ext() sc_ext_shutdown(); } -sc_memory_context* sc_memory_context_new(sc_uint8 levels) +sc_memory_context * sc_memory_context_new(sc_uint8 levels) { return sc_memory_context_new_impl(levels); } -sc_memory_context* sc_memory_context_new_impl(sc_uint8 levels) +sc_memory_context * sc_memory_context_new_impl(sc_uint8 levels) { - sc_memory_context *ctx = g_new0(sc_memory_context, 1); + sc_memory_context * ctx = g_new0(sc_memory_context, 1); sc_uint32 index = 0; ctx->access_levels = levels; @@ -156,7 +156,8 @@ sc_memory_context* sc_memory_context_new_impl(sc_uint8 levels) goto error; index = (s_context_id_last + 1) % G_MAXUINT32; - while (index == 0 || (index != s_context_id_last && g_hash_table_lookup(s_context_hash_table, GINT_TO_POINTER(index)))) + while (index == 0 || + (index != s_context_id_last && g_hash_table_lookup(s_context_hash_table, GINT_TO_POINTER(index)))) index = (index + 1) % G_MAXUINT32; if (index != s_context_id_last) @@ -164,17 +165,18 @@ sc_memory_context* sc_memory_context_new_impl(sc_uint8 levels) ctx->id = index; s_context_id_last = index; g_hash_table_insert(s_context_hash_table, GINT_TO_POINTER(ctx->id), (gpointer)ctx); - } else + } + else goto error; s_context_id_count++; goto result; error: - { - g_free(ctx); - ctx = 0; - } +{ + g_free(ctx); + ctx = 0; +} result: g_mutex_unlock(&s_concurrency_mutex); @@ -182,18 +184,18 @@ sc_memory_context* sc_memory_context_new_impl(sc_uint8 levels) return ctx; } -void sc_memory_context_free(sc_memory_context *ctx) +void sc_memory_context_free(sc_memory_context * ctx) { sc_memory_context_free_impl(ctx); } -void sc_memory_context_free_impl(sc_memory_context *ctx) +void sc_memory_context_free_impl(sc_memory_context * ctx) { g_assert(ctx != 0); g_mutex_lock(&s_concurrency_mutex); - sc_memory_context *c = g_hash_table_lookup(s_context_hash_table, GINT_TO_POINTER(ctx->id)); + sc_memory_context * c = g_hash_table_lookup(s_context_hash_table, GINT_TO_POINTER(ctx->id)); g_assert(c == ctx); g_hash_table_remove(s_context_hash_table, GINT_TO_POINTER(ctx->id)); s_context_id_count--; @@ -231,10 +233,11 @@ void sc_memory_context_emit_events(sc_memory_context * ctx) while (ctx->pend_events) { item = ctx->pend_events; - evt_params = (sc_event_emit_params*)item->data; + evt_params = (sc_event_emit_params *)item->data; + + sc_event_emit_impl( + ctx, evt_params->el, evt_params->el_access, evt_params->type, evt_params->edge, evt_params->other_el); - sc_event_emit_impl(ctx, evt_params->el, evt_params->el_access, evt_params->type, evt_params->edge, evt_params->other_el); - g_free(evt_params); ctx->pend_events = g_slist_delete_link(ctx->pend_events, ctx->pend_events); @@ -276,7 +279,7 @@ sc_addr sc_memory_arc_new(sc_memory_context * ctx, sc_type type, sc_addr beg, sc return sc_storage_arc_new(ctx, type, beg, end); } -sc_result sc_memory_get_element_type(sc_memory_context const * ctx, sc_addr addr, sc_type *result) +sc_result sc_memory_get_element_type(sc_memory_context const * ctx, sc_addr addr, sc_type * result) { return sc_storage_get_element_type(ctx, addr, result); } @@ -286,33 +289,40 @@ sc_result sc_memory_change_element_subtype(sc_memory_context const * ctx, sc_add return sc_storage_change_element_subtype(ctx, addr, type); } -sc_result sc_memory_get_arc_begin(sc_memory_context const * ctx, sc_addr addr, sc_addr *result) +sc_result sc_memory_get_arc_begin(sc_memory_context const * ctx, sc_addr addr, sc_addr * result) { return sc_storage_get_arc_begin(ctx, addr, result); } -sc_result sc_memory_get_arc_end(sc_memory_context const * ctx, sc_addr addr, sc_addr *result) +sc_result sc_memory_get_arc_end(sc_memory_context const * ctx, sc_addr addr, sc_addr * result) { return sc_storage_get_arc_end(ctx, addr, result); } -sc_result sc_memory_get_arc_info(sc_memory_context const * ctx, sc_addr addr, - sc_addr * result_start_addr, sc_addr * result_end_addr) +sc_result sc_memory_get_arc_info( + sc_memory_context const * ctx, + sc_addr addr, + sc_addr * result_start_addr, + sc_addr * result_end_addr) { return sc_storage_get_arc_info(ctx, addr, result_start_addr, result_end_addr); } -sc_result sc_memory_set_link_content(sc_memory_context * ctx, sc_addr addr, const sc_stream *stream) +sc_result sc_memory_set_link_content(sc_memory_context * ctx, sc_addr addr, const sc_stream * stream) { return sc_storage_set_link_content(ctx, addr, stream); } -sc_result sc_memory_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream **stream) +sc_result sc_memory_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream ** stream) { return sc_storage_get_link_content(ctx, addr, stream); } -sc_result sc_memory_find_links_with_content(sc_memory_context const * ctx, sc_stream const * stream, sc_addr **result, sc_uint32 *result_count) +sc_result sc_memory_find_links_with_content( + sc_memory_context const * ctx, + sc_stream const * stream, + sc_addr ** result, + sc_uint32 * result_count) { return sc_storage_find_links_with_content(ctx, stream, result, result_count); } @@ -322,7 +332,11 @@ void sc_memory_free_buff(sc_pointer buff) g_free(buff); } -sc_result sc_memory_set_element_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels access_levels, sc_access_levels * new_value) +sc_result sc_memory_set_element_access_levels( + sc_memory_context const * ctx, + sc_addr addr, + sc_access_levels access_levels, + sc_access_levels * new_value) { return sc_storage_set_access_levels(ctx, addr, access_levels, new_value); } @@ -332,7 +346,7 @@ sc_result sc_memory_get_element_access_levels(sc_memory_context const * ctx, sc_ return sc_storage_get_access_levels(ctx, addr, result); } -sc_result sc_memory_stat(sc_memory_context const * ctx, sc_stat *stat) +sc_result sc_memory_stat(sc_memory_context const * ctx, sc_stat * stat) { return sc_storage_get_elements_stat(stat); } diff --git a/sc-memory/sc-core/sc_memory.h b/sc-memory/sc-core/sc_memory.h index e4dab08c33..6b175f5566 100644 --- a/sc-memory/sc-core/sc_memory.h +++ b/sc-memory/sc-core/sc_memory.h @@ -14,23 +14,23 @@ struct _sc_memory_params { - const sc_char *repo_path; - const sc_char *config_file; - const sc_char *ext_path; - const sc_char **enabled_exts; // null-terminated list of extension names that should be loaded + const sc_char * repo_path; + const sc_char * config_file; + const sc_char * ext_path; + const sc_char ** enabled_exts; // null-terminated list of extension names that should be loaded sc_bool clear; }; typedef struct _sc_memory_params sc_memory_params; //! Function to clear memory parameters -_SC_EXTERN void sc_memory_params_clear(sc_memory_params *params); +_SC_EXTERN void sc_memory_params_clear(sc_memory_params * params); /*! Initialize sc-memory with specified path to repository * @param params Pointer to initialization parameters * @returns Returns pointer to created sc-memory context */ -_SC_EXTERN sc_memory_context* sc_memory_initialize(const sc_memory_params *params); +_SC_EXTERN sc_memory_context * sc_memory_initialize(const sc_memory_params * params); /*! Initialize sc-memory extensions in specified directory * @param enabled_list Null terminated list of extensions names, that should be loaded. If it's a null value, then all @@ -51,12 +51,12 @@ _SC_EXTERN void sc_memory_shutdown_ext(); * context creation, then function returns 0 * @note Do not use one context in different threads. */ -_SC_EXTERN sc_memory_context* sc_memory_context_new(sc_uint8 levels); +_SC_EXTERN sc_memory_context * sc_memory_context_new(sc_uint8 levels); /*! Function that destroys created memory context. You can use that function * just for contexts, that were created with @see sc_memory_context_new */ -_SC_EXTERN void sc_memory_context_free(sc_memory_context *ctx); +_SC_EXTERN void sc_memory_context_free(sc_memory_context * ctx); /*! Start events pending mode for a context. * In that mode all events emit will be pending until @@ -69,7 +69,6 @@ _SC_EXTERN void sc_memory_context_pending_begin(sc_memory_context * ctx); */ _SC_EXTERN void sc_memory_context_pending_end(sc_memory_context * ctx); - //! Check if sc-memory is initialized _SC_EXTERN sc_bool sc_memory_is_initialized(); @@ -144,8 +143,11 @@ _SC_EXTERN sc_result sc_memory_get_arc_end(sc_memory_context const * ctx, sc_add * Call logic equal to calls sc_memory_get_arc_begin and sc_memory_get_arc_end, * but this one do this work faster. */ -_SC_EXTERN sc_result sc_memory_get_arc_info(sc_memory_context const * ctx, sc_addr addr, - sc_addr * result_start_addr, sc_addr * result_end_addr); +_SC_EXTERN sc_result sc_memory_get_arc_info( + sc_memory_context const * ctx, + sc_addr addr, + sc_addr * result_start_addr, + sc_addr * result_end_addr); /*! Setup content data for specified sc-link * @param addr sc-addr of sc-link to setup content @@ -158,7 +160,7 @@ _SC_EXTERN sc_result sc_memory_get_arc_info(sc_memory_context const * ctx, sc_ad * */ -_SC_EXTERN sc_result sc_memory_set_link_content(sc_memory_context * ctx, sc_addr addr, sc_stream const *stream); +_SC_EXTERN sc_result sc_memory_set_link_content(sc_memory_context * ctx, sc_addr addr, sc_stream const * stream); /*! Returns content of specified sc-link * @param addr sc-addr of sc-link to return content data @@ -172,7 +174,7 @@ _SC_EXTERN sc_result sc_memory_set_link_content(sc_memory_context * ctx, sc_addr * */ -_SC_EXTERN sc_result sc_memory_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream **stream); +_SC_EXTERN sc_result sc_memory_get_link_content(sc_memory_context const * ctx, sc_addr addr, sc_stream ** stream); /*! Search sc-link addrs by specified checksum * @param stream Pointert to stream that contains data for search @@ -184,18 +186,27 @@ _SC_EXTERN sc_result sc_memory_get_link_content(sc_memory_context const * ctx, s * sc-addrs * @attention \p result array need to be free after usage */ -_SC_EXTERN sc_result sc_memory_find_links_with_content(sc_memory_context const * ctx, sc_stream const * stream, sc_addr **result, sc_uint32 *result_count); +_SC_EXTERN sc_result sc_memory_find_links_with_content( + sc_memory_context const * ctx, + sc_stream const * stream, + sc_addr ** result, + sc_uint32 * result_count); /*! Free buffer allocated for links content find result */ _SC_EXTERN void sc_memory_free_buff(sc_pointer buff); -/*! Setup new access levele for sc-element. New access levels will be a minimum from context access levels and parameter \b access_levels +/*! Setup new access levele for sc-element. New access levels will be a minimum from context access levels and parameter + * \b access_levels * @param addr sc-add of sc-element to change access levels * @param access_levels New access levels * @param new_value Pointer to structure that contains new value of access levels. This pointer can be a NULL. */ -_SC_EXTERN sc_result sc_memory_set_element_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels access_levels, sc_access_levels * new_value); +_SC_EXTERN sc_result sc_memory_set_element_access_levels( + sc_memory_context const * ctx, + sc_addr addr, + sc_access_levels access_levels, + sc_access_levels * new_value); /*! Get access levels of sc-element * @param addr sc-addr of sc-element to get access levels @@ -203,19 +214,18 @@ _SC_EXTERN sc_result sc_memory_set_element_access_levels(sc_memory_context const * * @return If access levele returned in \b result, then return SC_RESULT_OK; otherwise returns error code */ -_SC_EXTERN sc_result sc_memory_get_element_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels * result); +_SC_EXTERN sc_result +sc_memory_get_element_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels * result); /*! Collect statistic information about current state of sc-memory * @param stat Pointer to structure, that will contains statistics info * @return If info collected without errors, then return SC_RESULT_OK; otherwise return SC_RESULT_ERROR */ -_SC_EXTERN sc_result sc_memory_stat(sc_memory_context const * ctx, sc_stat *stat); +_SC_EXTERN sc_result sc_memory_stat(sc_memory_context const * ctx, sc_stat * stat); /*! Save sc-memory state. * Calls from application, when request to save memory state */ _SC_EXTERN sc_result sc_memory_save(sc_memory_context const * ctx); - - #endif diff --git a/sc-memory/sc-core/sc_memory_ext.c b/sc-memory/sc-core/sc_memory_ext.c index 16de5422b2..652e96296e 100644 --- a/sc-memory/sc-core/sc_memory_ext.c +++ b/sc-memory/sc-core/sc_memory_ext.c @@ -9,7 +9,7 @@ #include #include -GList *modules_priority_list = 0; +GList * modules_priority_list = 0; //! Type of module function typedef sc_result (*fModuleFunc)(); @@ -17,8 +17,8 @@ typedef sc_uint32 (*fModulePriorityFunc)(); typedef struct _sc_module_info { - GModule *ptr; - gchar *path; + GModule * ptr; + gchar * path; sc_uint32 priority; fModuleFunc init_func; fModuleFunc shut_func; @@ -26,7 +26,7 @@ typedef struct _sc_module_info void sc_module_info_free(gpointer mi) { - sc_module_info *info = (sc_module_info*)mi; + sc_module_info * info = (sc_module_info *)mi; if (info->path) g_free(info->path); @@ -37,8 +37,8 @@ void sc_module_info_free(gpointer mi) gint sc_priority_less(gconstpointer a, gconstpointer b) { - sc_module_info *ma = (sc_module_info*)a; - sc_module_info *mb = (sc_module_info*)b; + sc_module_info * ma = (sc_module_info *)a; + sc_module_info * mb = (sc_module_info *)b; if (ma->priority < mb->priority) return -1; @@ -53,10 +53,10 @@ gint sc_priority_great(gconstpointer a, gconstpointer b) return sc_priority_less(b, a); } -sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enabled_list) +sc_result sc_ext_initialize(const sc_char * ext_dir_path, const sc_char ** enabled_list) { - GDir *ext_dir = null_ptr; - const gchar *file_name = 0; + GDir * ext_dir = null_ptr; + const gchar * file_name = 0; fModuleFunc func = 0; #if SC_IS_PLATFORM_MAC @@ -111,7 +111,7 @@ sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enable goto next; } - sc_module_info *mi = g_new0(sc_module_info, 1); + sc_module_info * mi = g_new0(sc_module_info, 1); mi->path = g_module_build_path(ext_dir_path, file_name); // open module @@ -125,14 +125,14 @@ sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enable // skip non module files if (g_str_has_suffix(file_name, moduleSuffix) == TRUE) { - if (g_module_symbol(mi->ptr, "sc_module_initialize", (gpointer*) &func) == FALSE) + if (g_module_symbol(mi->ptr, "sc_module_initialize", (gpointer *)&func) == FALSE) { g_warning("Can't find 'sc_module_initialize' symbol in module: %s", mi->path); goto clean; } mi->init_func = func; - if (g_module_symbol(mi->ptr, "sc_module_shutdown", (gpointer*) &func) == FALSE) + if (g_module_symbol(mi->ptr, "sc_module_shutdown", (gpointer *)&func) == FALSE) { g_warning("Can't find 'sc_module_shutdown' symbol in module: %s", mi->path); goto clean; @@ -140,7 +140,7 @@ sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enable mi->shut_func = func; fModulePriorityFunc pfunc; - if (g_module_symbol(mi->ptr, "sc_module_load_priority", (gpointer*)&pfunc) == FALSE) + if (g_module_symbol(mi->ptr, "sc_module_load_priority", (gpointer *)&pfunc) == FALSE) mi->priority = G_MAXUINT32; else mi->priority = pfunc(); @@ -149,25 +149,24 @@ sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enable modules_priority_list = g_list_insert_sorted(modules_priority_list, (gpointer)mi, sc_priority_less); goto next; -clean: - { - sc_module_info_free(mi); - } + clean: + { + sc_module_info_free(mi); + } -next: - { - file_name = g_dir_read_name(ext_dir); - } + next: + { + file_name = g_dir_read_name(ext_dir); + } } g_dir_close(ext_dir); - // initialize modules - GList *item = modules_priority_list; + GList * item = modules_priority_list; while (item != null_ptr) { - sc_module_info *module = (sc_module_info*)item->data; + sc_module_info * module = (sc_module_info *)item->data; g_message("Initialize module: %s", module->path); if (module->init_func() != SC_RESULT_OK) { @@ -186,10 +185,10 @@ sc_result sc_ext_initialize(const sc_char *ext_dir_path, const sc_char ** enable void sc_ext_shutdown() { modules_priority_list = g_list_sort(modules_priority_list, sc_priority_great); - GList *item = modules_priority_list; + GList * item = modules_priority_list; while (item != null_ptr) { - sc_module_info *module = (sc_module_info*)item->data; + sc_module_info * module = (sc_module_info *)item->data; g_message("Shutdown module: %s", module->path); if (module->ptr != null_ptr) { diff --git a/sc-memory/sc-core/sc_memory_ext.h b/sc-memory/sc-core/sc_memory_ext.h index 1cff0a57b0..85cfb3b0c8 100644 --- a/sc-memory/sc-core/sc_memory_ext.h +++ b/sc-memory/sc-core/sc_memory_ext.h @@ -14,9 +14,9 @@ * This function find all available extensions in specified directory and try to load them. * @param ext_dir_path Path to directory, that contains extensions. This function doens't take * ownership on this parameter, so you need to free it after end using the last one. - * @param enabled_list Null terminated list of enabled extension names. If it null, then all extensions in a deirectory will be loaded. - * Ohterwise just extensions in a list will be loaded. - * @return If specified directory doesn't exist, then return SC_ERROR_INVALID_PARAMS. If + * @param enabled_list Null terminated list of enabled extension names. If it null, then all extensions in a deirectory + * will be loaded. Ohterwise just extensions in a list will be loaded. + * @return If specified directory doesn't exist, then return SC_ERROR_INVALID_PARAMS. If * there are any other errors to load extensions, then return SC_ERROR */ sc_result sc_ext_initialize(const sc_char * ext_dir_path, const sc_char ** enabled_list); @@ -25,4 +25,4 @@ sc_result sc_ext_initialize(const sc_char * ext_dir_path, const sc_char ** enabl */ void sc_ext_shutdown(); -#endif // _sc_memory_h_ +#endif // _sc_memory_h_ diff --git a/sc-memory/sc-core/sc_memory_headers.h b/sc-memory/sc-core/sc_memory_headers.h index 99a0196ff5..ebd311f615 100644 --- a/sc-memory/sc-core/sc_memory_headers.h +++ b/sc-memory/sc-core/sc_memory_headers.h @@ -16,5 +16,4 @@ #include "sc-store/sc_stream_memory.h" #include "sc-store/sc_config.h" - #endif diff --git a/sc-memory/sc-core/sc_memory_private.h b/sc-memory/sc-core/sc_memory_private.h index 3eb092854b..68b426c376 100644 --- a/sc-memory/sc-core/sc_memory_private.h +++ b/sc-memory/sc-core/sc_memory_private.h @@ -23,7 +23,7 @@ struct _sc_event_emit_params typedef struct _sc_event_emit_params sc_event_emit_params; -#define SC_CONTEXT_FLAG_PENDING_EVENTS 0x1 +#define SC_CONTEXT_FLAG_PENDING_EVENTS 0x1 struct _sc_memory_context { @@ -41,7 +41,7 @@ extern sc_memory_context * s_memory_default_ctx; * context creation, then function returns 0 * @note Do not use one context in different threads. */ -sc_memory_context* sc_memory_context_new_impl(sc_uint8 levels); +sc_memory_context * sc_memory_context_new_impl(sc_uint8 levels); /*! Function that destroys created memory context. You can use that function * just for contexts, that were created with @see sc_memory_context_new diff --git a/sc-memory/sc-core/sc_memory_version.c b/sc-memory/sc-core/sc_memory_version.c index 551d3e1ab2..a01f9e1f50 100644 --- a/sc-memory/sc-core/sc_memory_version.c +++ b/sc-memory/sc-core/sc_memory_version.c @@ -8,26 +8,31 @@ #include -const sc_version SC_VERSION = { 0, 6, 0, "" }; +const sc_version SC_VERSION = {0, 6, 0, ""}; - -sc_int32 sc_version_compare(const sc_version *a, const sc_version *b) +sc_int32 sc_version_compare(const sc_version * a, const sc_version * b) { g_assert(a && b); - if (a->major < b->major) return -1; - if (a->major > b->major) return 1; + if (a->major < b->major) + return -1; + if (a->major > b->major) + return 1; - if (a->minor < b->minor) return -1; - if (a->minor > b->minor) return 1; + if (a->minor < b->minor) + return -1; + if (a->minor > b->minor) + return 1; - if (a->patch < b->patch) return -1; - if (a->patch > b->patch) return 1; + if (a->patch < b->patch) + return -1; + if (a->patch > b->patch) + return 1; return 0; } -char* sc_version_string_new(const sc_version *v) +char * sc_version_string_new(const sc_version * v) { if (v->suffix) return g_strdup_printf("%u.%u.%u %s", v->major, v->minor, v->patch, v->suffix); @@ -35,7 +40,7 @@ char* sc_version_string_new(const sc_version *v) return g_strdup_printf("%u.%u.%u", v->major, v->minor, v->patch); } -void sc_version_string_free(char *str) +void sc_version_string_free(char * str) { g_assert(str != 0); g_free(str); diff --git a/sc-memory/sc-core/sc_memory_version.h b/sc-memory/sc-core/sc_memory_version.h index 7137418216..c67f220d98 100644 --- a/sc-memory/sc-core/sc_memory_version.h +++ b/sc-memory/sc-core/sc_memory_version.h @@ -14,12 +14,11 @@ struct _sc_version sc_uint8 major; sc_uint8 minor; sc_uint8 patch; - const char *suffix; + const char * suffix; }; typedef struct _sc_version sc_version; - extern const sc_version SC_VERSION; /*! Function compares to versions @p a and @p b. @@ -28,16 +27,16 @@ extern const sc_version SC_VERSION; * If version @p a and @p b equal, then returns 0. * @note This function ignores suffixes */ -_SC_EXTERN sc_int32 sc_version_compare(const sc_version *a, const sc_version *b); +_SC_EXTERN sc_int32 sc_version_compare(const sc_version * a, const sc_version * b); /*! Returns newvly-alocated string that represents version. * The returned string should be freed with sc_version_string_free when no longer needed. */ -_SC_EXTERN char* sc_version_string_new(const sc_version *v); +_SC_EXTERN char * sc_version_string_new(const sc_version * v); /*! Frees string that represents sc-version */ -_SC_EXTERN void sc_version_string_free(char *str); +_SC_EXTERN void sc_version_string_free(char * str); _SC_EXTERN sc_uint32 sc_version_to_int(sc_version const * version); _SC_EXTERN void sc_version_from_int(sc_uint32 value, sc_version * version); diff --git a/sc-memory/sc-memory/CMakeLists.txt b/sc-memory/sc-memory/CMakeLists.txt index 3394be40eb..df57bfd36e 100644 --- a/sc-memory/sc-memory/CMakeLists.txt +++ b/sc-memory/sc-memory/CMakeLists.txt @@ -54,3 +54,7 @@ add_dependencies(sc-memory SCsParser) target_compile_definitions(sc-memory PRIVATE "-DSC_MEMORY_SELF_BUILD") + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-memory) +endif () diff --git a/sc-memory/sc-memory/http/sc_http_request.cpp b/sc-memory/sc-memory/http/sc_http_request.cpp index 7651763992..4468eb960b 100644 --- a/sc-memory/sc-memory/http/sc_http_request.cpp +++ b/sc-memory/sc-memory/http/sc_http_request.cpp @@ -6,8 +6,7 @@ namespace { - -size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmemb, std::string * s) +size_t CurlWrite_CallbackFunc_StdString(void * contents, size_t size, size_t nmemb, std::string * s) { size_t newLength = size * nmemb; size_t oldLength = s->size(); @@ -17,35 +16,34 @@ size_t CurlWrite_CallbackFunc_StdString(void *contents, size_t size, size_t nmem } catch (std::bad_alloc &) { - //handle memory problem + // handle memory problem return 0; } - std::copy((char*)contents, (char*)contents + newLength, s->begin() + oldLength); + std::copy((char *)contents, (char *)contents + newLength, s->begin() + oldLength); return size * nmemb; } -} // namespace - +} // namespace ScHttpRequest::ScHttpRequest(std::string const & url) : m_handle(nullptr) , m_type(Type::GET) { - m_handle = (void*)curl_easy_init(); + m_handle = (void *)curl_easy_init(); if (!url.empty()) SetURL(url); } ScHttpRequest::~ScHttpRequest() { - curl_easy_cleanup((CURL*)m_handle); + curl_easy_cleanup((CURL *)m_handle); } void ScHttpRequest::Perform() { - CURL * curl = (CURL*)m_handle; - + CURL * curl = (CURL *)m_handle; + if (m_type == Type::POST) { curl_easy_setopt(curl, CURLOPT_POST, 1L); @@ -78,7 +76,7 @@ void ScHttpRequest::Perform() void ScHttpRequest::SetURL(std::string const & url) { - CURLcode const r = curl_easy_setopt((CURL*)m_handle, CURLOPT_URL, url.c_str()); + CURLcode const r = curl_easy_setopt((CURL *)m_handle, CURLOPT_URL, url.c_str()); SC_ASSERT(r == CURLE_OK, ()); } diff --git a/sc-memory/sc-memory/http/sc_http_request.hpp b/sc-memory/sc-memory/http/sc_http_request.hpp index bd21a95d69..2919299d27 100644 --- a/sc-memory/sc-memory/http/sc_http_request.hpp +++ b/sc-memory/sc-memory/http/sc_http_request.hpp @@ -6,10 +6,9 @@ #include #include -class ScHttpRequest +class ScHttpRequest { public: - enum class Type : uint8_t { GET, diff --git a/sc-memory/sc-memory/http/sc_http_response.hpp b/sc-memory/sc-memory/http/sc_http_response.hpp index 93b3475240..fcac24ece3 100644 --- a/sc-memory/sc-memory/http/sc_http_response.hpp +++ b/sc-memory/sc-memory/http/sc_http_response.hpp @@ -16,7 +16,7 @@ class ScHttpResponse public: _SC_EXTERN std::string const & GetData() const; _SC_EXTERN std::string GetResultCodeString() const; - + _SC_EXTERN bool IsSuccess() const; private: diff --git a/sc-memory/sc-memory/json/json.hpp b/sc-memory/sc-memory/json/json.hpp index 85d559d7a3..02606186ff 100644 --- a/sc-memory/sc-memory/json/json.hpp +++ b/sc-memory/sc-memory/json/json.hpp @@ -29,83 +29,83 @@ SOFTWARE. #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP -#include // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform -#include // array -#include // assert -#include // and, not, or -#include // lconv, localeconv -#include // isfinite, labs, ldexp, signbit -#include // nullptr_t, ptrdiff_t, size_t -#include // int64_t, uint64_t -#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull -#include // memcpy, strlen -#include // forward_list -#include // function, hash, less -#include // initializer_list -#include // hex -#include // istream, ostream -#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator -#include // numeric_limits -#include // locale -#include // map -#include // addressof, allocator, allocator_traits, unique_ptr -#include // accumulate -#include // stringstream -#include // getline, stoi, string, to_string -#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type -#include // declval, forward, make_pair, move, pair, swap -#include // vector +#include // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform +#include // array +#include // assert +#include // and, not, or +#include // lconv, localeconv +#include // isfinite, labs, ldexp, signbit +#include // nullptr_t, ptrdiff_t, size_t +#include // int64_t, uint64_t +#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull +#include // memcpy, strlen +#include // forward_list +#include // function, hash, less +#include // initializer_list +#include // hex +#include // istream, ostream +#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator +#include // numeric_limits +#include // locale +#include // map +#include // addressof, allocator, allocator_traits, unique_ptr +#include // accumulate +#include // stringstream +#include // getline, stoi, string, to_string +#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type +#include // declval, forward, make_pair, move, pair, swap +#include // vector // exclude unsupported compilers #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif +# if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 +# error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" +# endif #elif defined(__GNUC__) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif +# if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 +# error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +# endif #endif // disable float-equal warnings on GCC/clang #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wfloat-equal" #endif // disable documentation warnings on clang #if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdocumentation" #endif // allow for portable deprecation warnings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) +# define JSON_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) +# define JSON_DEPRECATED __declspec(deprecated) #else - #define JSON_DEPRECATED +# define JSON_DEPRECATED #endif // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) +# define JSON_THROW(exception) throw exception +# define JSON_TRY try +# define JSON_CATCH(exception) catch (exception) #else - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) +# define JSON_THROW(exception) std::abort() +# define JSON_TRY if (true) +# define JSON_CATCH(exception) if (false) #endif // manual branch prediction #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +# define JSON_LIKELY(x) __builtin_expect(!!(x), 1) +# define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x +# define JSON_LIKELY(x) x +# define JSON_UNLIKELY(x) x #endif /*! @@ -115,7 +115,6 @@ SOFTWARE. */ namespace nlohmann { - /*! @brief unnamed namespace with internal helper functions @@ -144,29 +143,31 @@ Extension of std::exception objects with a member @a id for exception ids. */ class exception : public std::exception { - public: - /// returns the explanatory string - virtual const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) - : id(id_), m(what_arg) - {} - - static std::string name(const std::string& ename, int id) - { - return "[json.exception." + ename + "." + std::to_string(id) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; +public: + /// returns the explanatory string + virtual const char * what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; + +protected: + exception(int id_, const char * what_arg) + : id(id_) + , m(what_arg) + { + } + + static std::string name(const std::string & ename, int id) + { + return "[json.exception." + ename + "." + std::to_string(id) + "] "; + } + +private: + /// an exception object as storage for error messages + std::runtime_error m; }; /*! @@ -188,57 +189,70 @@ Exceptions have ids 1xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error +indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token +(character) was encountered, and the member @a byte indicates the error position. json.exception.parse_error.102 | parse +error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points +above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair +is incomplete or contains an invalid code point. json.exception.parse_error.103 | parse error: code points above +0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC +6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array +of objects. json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a +JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must +be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. json.exception.parse_error.106 +| parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC +6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number wihtout a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer +must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, +only `~0` and `~1` are valid escape sequences. json.exception.parse_error.109 | parse error: array index 'one' is not a +number | A JSON Pointer array index must be a number. json.exception.parse_error.110 | parse error at 1: cannot read 2 +bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.111 | parse error: bad input stream | Parsing CBOR or MessagePack from an input stream where +the [`badbit` or `failbit`](http://en.cppreference.com/w/cpp/io/ios_base/iostate) is set. json.exception.parse_error.112 +| parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This +exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR +string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. @since version 3.0.0 */ class parse_error : public exception { - public: - /*! - @brief create a parse error exception - @param[in] id the id of the exception - @param[in] byte_ the byte index where the error occured (or 0 if - the position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id, size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character - and n+1 is the index of the terminating null byte or the end of - file. This also holds true when reading a byte vector (CBOR or - MessagePack). - */ - const size_t byte; - - private: - parse_error(int id_, size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) - {} +public: + /*! + @brief create a parse error exception + @param[in] id the id of the exception + @param[in] byte_ the byte index where the error occured (or 0 if + the position cannot be determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + static parse_error create(int id, size_t byte_, const std::string & what_arg) + { + std::string w = exception::name("parse_error", id) + "parse error" + + (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + ": " + what_arg; + return parse_error(id, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character + and n+1 is the index of the terminating null byte or the end of + file. This also holds true when reading a byte vector (CBOR or + MessagePack). + */ + const size_t byte; + +private: + parse_error(int id_, size_t byte_, const char * what_arg) + : exception(id_, what_arg) + , byte(byte_) + { + } }; /*! @@ -248,36 +262,52 @@ Exceptions have ids 2xx. name / id | example massage | description ----------------------------------- | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compated, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref +basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, +the range (@a first, @a last) is invalid. json.exception.invalid_iterator.202 | iterator does not fit current value | In +an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was +called. It hence does not define a valid position for the deletion/insertion. json.exception.invalid_iterator.203 | +iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType +last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to +delete values from. json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a +primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be +exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges +are invalid. json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type +(number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because +it is the only way to address the stored value. All other iterators are invalid. json.exception.invalid_iterator.206 | +cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT +last) belong to a JSON null value and hence to not define a valid range. json.exception.invalid_iterator.207 | cannot +use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, +because other types do not have a concept of a key. json.exception.invalid_iterator.208 | cannot use operator[] for +object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, +because JSON objects are unordered. json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The +offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are +unordered. json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function +are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is +invalid. json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed +to the insert function must not be a subrange of the container to insert to. json.exception.invalid_iterator.212 | +cannot compare iterators of different containers | When two iterators are compared, they must belong to the same +container. json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object +iterators cannot be compated, because JSON objects are unordered. json.exception.invalid_iterator.214 | cannot get value +| Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type +(number, boolean, or string), but the iterator is different to @ref begin(). @since version 3.0.0 */ class invalid_iterator : public exception { - public: - static invalid_iterator create(int id, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id) + what_arg; - return invalid_iterator(id, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) - {} +public: + static invalid_iterator create(int id, const std::string & what_arg) + { + std::string w = exception::name("invalid_iterator", id) + what_arg; + return invalid_iterator(id, w.c_str()); + } + +private: + invalid_iterator(int id_, const char * what_arg) + : exception(id_, what_arg) + { + } }; /*! @@ -287,36 +317,46 @@ Exceptions have ids 3xx. name / id | example massage | description ----------------------------- | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer +list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is +violated, an array is created instead. json.exception.type_error.302 | type must be object, but is array | During +implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string +can only be converted into string types, but not into numbers or boolean types. json.exception.type_error.303 | +incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref +basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON +array, the @a ReferenceType must be @ref array_t&. json.exception.type_error.304 | cannot use at() with string | The +@ref at() member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use +operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed +for certain JSON types. json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member +functions can only be executed for certain JSON types. json.exception.type_error.308 | cannot use push_back() with +string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for +certain JSON types. json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can +only be executed for certain JSON types. json.exception.type_error.311 | cannot use emplace_back() with string | The +@ref emplace_back() member function can only be executed for certain JSON types. json.exception.type_error.313 | invalid +value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary +nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object +whose keys are JSON Pointers. json.exception.type_error.315 | values in object must be primitive | The @ref unflatten +function only works for an object whose keys are JSON Pointers and whose values are primitive. @since version 3.0.0 */ class type_error : public exception { - public: - static type_error create(int id, const std::string& what_arg) - { - std::string w = exception::name("type_error", id) + what_arg; - return type_error(id, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) - : exception(id_, what_arg) - {} +public: + static type_error create(int id, const std::string & what_arg) + { + std::string w = exception::name("type_error", id) + what_arg; + return type_error(id, w.c_str()); + } + +private: + type_error(int id_, const char * what_arg) + : exception(id_, what_arg) + { + } }; /*! @@ -326,28 +366,31 @@ Exceptions have ids 4xx. name / id | example massage | description ------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a +size-1. json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON +Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add +elements at this position, but not to read it. json.exception.out_of_range.403 | key 'foo' not found | The provided key +was not found in the JSON object. json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token +in a JSON Pointer could not be resolved. json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch +operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 +| number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. @since version 3.0.0 */ class out_of_range : public exception { - public: - static out_of_range create(int id, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id) + what_arg; - return out_of_range(id, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) - : exception(id_, what_arg) - {} +public: + static out_of_range create(int id, const std::string & what_arg) + { + std::string w = exception::name("out_of_range", id) + what_arg; + return out_of_range(id, w.c_str()); + } + +private: + out_of_range(int id_, const char * what_arg) + : exception(id_, what_arg) + { + } }; /*! @@ -357,27 +400,27 @@ Exceptions have ids 5xx. name / id | example massage | description ------------------------------ | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation +'test' failed. The unsuccessful operation is also printed. @since version 3.0.0 */ class other_error : public exception { - public: - static other_error create(int id, const std::string& what_arg) - { - std::string w = exception::name("other_error", id) + what_arg; - return other_error(id, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) - : exception(id_, what_arg) - {} +public: + static other_error create(int id, const std::string & what_arg) + { + std::string w = exception::name("other_error", id) + what_arg; + return other_error(id, w.c_str()); + } + +private: + other_error(int id_, const char * what_arg) + : exception(id_, what_arg) + { + } }; - - /////////////////////////// // JSON type enumeration // /////////////////////////// @@ -408,15 +451,15 @@ value with the default value for a given type */ enum class value_t : uint8_t { - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + discarded ///< discarded by the the parser callback function }; /*! @@ -430,38 +473,35 @@ Returns an ordering that is similar to Python: */ inline bool operator<(const value_t lhs, const value_t rhs) noexcept { - static constexpr std::array order = {{ - 0, // null - 3, // object - 4, // array - 5, // string - 1, // boolean - 2, // integer - 2, // unsigned - 2, // float - } - }; - - // discarded values are not comparable - if (lhs == value_t::discarded or rhs == value_t::discarded) - { - return false; - } - - return order[static_cast(lhs)] < - order[static_cast(rhs)]; + static constexpr std::array order = {{ + 0, // null + 3, // object + 4, // array + 5, // string + 1, // boolean + 2, // integer + 2, // unsigned + 2, // float + }}; + + // discarded values are not comparable + if (lhs == value_t::discarded or rhs == value_t::discarded) + { + return false; + } + + return order[static_cast(lhs)] < order[static_cast(rhs)]; } - ///////////// // helpers // ///////////// // alias templates to reduce boilerplate -template +template using enable_if_t = typename std::enable_if::type; -template +template using uncvref_t = typename std::remove_cv::type>::type; /* @@ -477,149 +517,165 @@ Please note that those constructs must be used with caution, since symbols can become very long quickly (which can slow down compilation and cause MSVC internal compiler errors). Only use it when you have to (see example ahead). */ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; +template +struct conjunction : std::true_type +{ +}; +template +struct conjunction : B1 +{ +}; +template +struct conjunction : std::conditional, B1>::type +{ +}; -template struct negation : std::integral_constant < bool, !B::value > {}; +template +struct negation : std::integral_constant +{ +}; // dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - +template +struct priority_tag : priority_tag +{ +}; +template <> +struct priority_tag<0> +{ +}; ////////////////// // constructors // ////////////////// -template struct external_constructor; +template +struct external_constructor; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, const typename BasicJsonType::string_t & s) + { + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (bool x : arr) - { - j.m_value.array->push_back(x); - } - j.assert_invariant(); - } + template + static void construct(BasicJsonType & j, const typename BasicJsonType::array_t & arr) + { + j.m_type = value_t::array; + j.m_value = arr; + j.assert_invariant(); + } + + template < + typename BasicJsonType, + typename CompatibleArrayType, + enable_if_t::value, int> = 0> + static void construct(BasicJsonType & j, const CompatibleArrayType & arr) + { + using std::begin; + using std::end; + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType & j, const std::vector & arr) + { + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (bool x : arr) + { + j.m_value.array->push_back(x); + } + j.assert_invariant(); + } }; -template<> +template <> struct external_constructor { - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; + template + static void construct(BasicJsonType & j, const typename BasicJsonType::object_t & obj) + { + j.m_type = value_t::object; + j.m_value = obj; + j.assert_invariant(); + } + + template < + typename BasicJsonType, + typename CompatibleObjectType, + enable_if_t::value, int> = 0> + static void construct(BasicJsonType & j, const CompatibleObjectType & obj) + { + using std::begin; + using std::end; - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.assert_invariant(); - } + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.assert_invariant(); + } }; - //////////////////////// // has_/is_ functions // //////////////////////// @@ -634,16 +690,18 @@ contains a `mapped_type`, whereas `std::vector` fails the test. @sa http://stackoverflow.com/a/7728728/266378 @since version 1.0.0, overworked in version 2.0.6 */ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } +#define NLOHMANN_JSON_HAS_HELPER(type) \ + template \ + struct has_##type \ + { \ + private: \ + template \ + static int detect(U &&); \ + static void detect(...); \ +\ + public: \ + static constexpr bool value = std::is_integral()))>::value; \ + } NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(key_type); @@ -652,217 +710,222 @@ NLOHMANN_JSON_HAS_HELPER(iterator); #undef NLOHMANN_JSON_HAS_HELPER +template +struct is_compatible_object_type_impl : std::false_type +{ +}; -template -struct is_compatible_object_type_impl : std::false_type {}; - -template +template struct is_compatible_object_type_impl { - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; + static constexpr auto value = + std::is_constructible::value and + std::is_constructible::value; }; -template +template struct is_compatible_object_type { - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; + static auto constexpr value = is_compatible_object_type_impl< + conjunction< + negation>, + has_mapped_type, + has_key_type>::value, + typename BasicJsonType::object_t, + CompatibleObjectType>::value; }; -template +template struct is_basic_json_nested_type { - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; + static auto constexpr value = std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value or + std::is_same::value; }; -template +template struct is_compatible_array_type { - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; + static auto constexpr value = conjunction< + negation>, + negation>, + negation>, + negation>, + has_value_type, + has_iterator>::value; }; -template -struct is_compatible_integer_type_impl : std::false_type {}; +template +struct is_compatible_integer_type_impl : std::false_type +{ +}; -template +template struct is_compatible_integer_type_impl { - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = std::is_constructible::value and + CompatibleLimits::is_integer and RealLimits::is_signed == CompatibleLimits::is_signed; }; -template +template struct is_compatible_integer_type { - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; + static constexpr auto value = + is_compatible_integer_type_impl < std::is_integral::value and + not std::is_same::value, + RealIntegerType, CompatibleNumberIntegerType > ::value; }; - // trait checking if JSONSerializer::from_json(json const&, udt&) exists -template +template struct has_from_json { - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; +private: + // also check the return type of from_json + template < + typename U, + typename = enable_if_t::from_json(std::declval(), std::declval()))>::value>> + static int detect(U &&); + static void detect(...); + +public: + static constexpr bool value = std::is_integral>()))>::value; }; // This trait checks if JSONSerializer::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types -template +template struct has_non_default_from_json { - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; +private: + template < + typename U, + typename = enable_if_t::from_json(std::declval()))>::value>> + static int detect(U &&); + static void detect(...); + +public: + static constexpr bool value = std::is_integral>()))>::value; }; // This trait checks if BasicJsonType::json_serializer::to_json exists -template +template struct has_to_json { - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; +private: + template ::to_json(std::declval(), std::declval()))> + static int detect(U &&); + static void detect(...); + +public: + static constexpr bool value = std::is_integral>()))>::value; }; - ///////////// // to_json // ///////////// -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept +template < + typename BasicJsonType, + typename T, + enable_if_t::value, int> = 0> +void to_json(BasicJsonType & j, T b) noexcept { - external_constructor::construct(j, b); + external_constructor::construct(j, b); } -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) +template < + typename BasicJsonType, + typename CompatibleString, + enable_if_t::value, int> = 0> +void to_json(BasicJsonType & j, const CompatibleString & s) { - external_constructor::construct(j, s); + external_constructor::construct(j, s); } -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept +template ::value, int> = 0> +void to_json(BasicJsonType & j, FloatType val) noexcept { - external_constructor::construct(j, static_cast(val)); + external_constructor::construct(j, static_cast(val)); } template < - typename BasicJsonType, typename CompatibleNumberUnsignedType, - enable_if_t::value, int> = 0 > -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept + typename BasicJsonType, + typename CompatibleNumberUnsignedType, + enable_if_t< + is_compatible_integer_type::value, + int> = 0> +void to_json(BasicJsonType & j, CompatibleNumberUnsignedType val) noexcept { - external_constructor::construct(j, static_cast(val)); + external_constructor::construct( + j, static_cast(val)); } template < - typename BasicJsonType, typename CompatibleNumberIntegerType, - enable_if_t::value, int> = 0 > -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept + typename BasicJsonType, + typename CompatibleNumberIntegerType, + enable_if_t< + is_compatible_integer_type::value, + int> = 0> +void to_json(BasicJsonType & j, CompatibleNumberIntegerType val) noexcept { - external_constructor::construct(j, static_cast(val)); + external_constructor::construct( + j, static_cast(val)); } -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept +template ::value, int> = 0> +void to_json(BasicJsonType & j, EnumType e) noexcept { - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); } -template -void to_json(BasicJsonType& j, const std::vector& e) +template +void to_json(BasicJsonType & j, const std::vector & e) { - external_constructor::construct(j, e); + external_constructor::construct(j, e); } template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < + typename BasicJsonType, + typename CompatibleArrayType, + enable_if_t< is_compatible_array_type::value or - std::is_same::value, - int > = 0 > -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) + std::is_same::value, + int> = 0> +void to_json(BasicJsonType & j, const CompatibleArrayType & arr) { - external_constructor::construct(j, arr); + external_constructor::construct(j, arr); } template < - typename BasicJsonType, typename CompatibleObjectType, - enable_if_t::value, - int> = 0 > -void to_json(BasicJsonType& j, const CompatibleObjectType& arr) + typename BasicJsonType, + typename CompatibleObjectType, + enable_if_t::value, int> = 0> +void to_json(BasicJsonType & j, const CompatibleObjectType & arr) { - external_constructor::construct(j, arr); + external_constructor::construct(j, arr); } -template ::value, - int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) +template < + typename BasicJsonType, + typename T, + std::size_t N, + enable_if_t::value, int> = 0> +void to_json(BasicJsonType & j, T (&arr)[N]) { - external_constructor::construct(j, arr); + external_constructor::construct(j, arr); } /////////////// @@ -870,294 +933,292 @@ void to_json(BasicJsonType& j, T (&arr)[N]) /////////////// // overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +template < + typename BasicJsonType, + typename ArithmeticType, + enable_if_t< + std::is_arithmetic::value and + not std::is_same::value, + int> = 0> +void get_arithmetic_value(const BasicJsonType & j, ArithmeticType & val) { - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast( - *j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast( - *j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast( - *j.template get_ptr()); - break; - } - default: - { - JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name())); - } - } + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + default: + { + JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name())); + } + } } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::boolean_t & b) { - if (not j.is_boolean()) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + j.type_name())); - } - b = *j.template get_ptr(); + if (not j.is_boolean()) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + j.type_name())); + } + b = *j.template get_ptr(); } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::string_t & s) { - if (not j.is_string()) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + j.type_name())); - } - s = *j.template get_ptr(); + if (not j.is_string()) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + j.type_name())); + } + s = *j.template get_ptr(); } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::number_float_t & val) { - get_arithmetic_value(j, val); + get_arithmetic_value(j, val); } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::number_unsigned_t & val) { - get_arithmetic_value(j, val); + get_arithmetic_value(j, val); } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::number_integer_t & val) { - get_arithmetic_value(j, val); + get_arithmetic_value(j, val); } -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) +template ::value, int> = 0> +void from_json(const BasicJsonType & j, EnumType & e) { - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); } -template -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +template +void from_json(const BasicJsonType & j, typename BasicJsonType::array_t & arr) { - if (not j.is_array()) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); - } - arr = *j.template get_ptr(); + if (not j.is_array()) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); + } + arr = *j.template get_ptr(); } // forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) +template < + typename BasicJsonType, + typename T, + typename Allocator, + enable_if_t::value, int> = 0> +void from_json(const BasicJsonType & j, std::forward_list & l) { - if (not j.is_array()) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); - } - - for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) - { - l.push_front(it->template get()); - } + if (not j.is_array()) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); + } + + for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) + { + l.push_front(it->template get()); + } } -template -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0>) +template +void from_json_array_impl(const BasicJsonType & j, CompatibleArrayType & arr, priority_tag<0>) { - using std::begin; - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); + using std::begin; + using std::end; + + std::transform(j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); } -template -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1>) --> decltype( - arr.reserve(std::declval()), - void()) +template +auto from_json_array_impl(const BasicJsonType & j, CompatibleArrayType & arr, priority_tag<1>) + -> decltype(arr.reserve(std::declval()), void()) { - using std::begin; - using std::end; - - arr.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); + using std::begin; + using std::end; + + arr.reserve(j.size()); + std::transform(j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType & i) { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); } -template::value and - std::is_convertible::value and - not std::is_same::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +template < + typename BasicJsonType, + typename CompatibleArrayType, + enable_if_t< + is_compatible_array_type::value and + std::is_convertible::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType & j, CompatibleArrayType & arr) { - if (not j.is_array()) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); - } + if (not j.is_array()) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); + } - from_json_array_impl(j, arr, priority_tag<1> {}); + from_json_array_impl(j, arr, priority_tag<1>{}); } -template::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +template < + typename BasicJsonType, + typename CompatibleObjectType, + enable_if_t::value, int> = 0> +void from_json(const BasicJsonType & j, CompatibleObjectType & obj) { - if (not j.is_object()) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + j.type_name())); - } - - auto inner_object = j.template get_ptr(); - using std::begin; - using std::end; - // we could avoid the assignment, but this might require a for loop, which - // might be less efficient than the container constructor for some - // containers (would it?) - obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); + if (not j.is_object()) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + j.type_name())); + } + + auto inner_object = j.template get_ptr(); + using std::begin; + using std::end; + // we could avoid the assignment, but this might require a for loop, which + // might be less efficient than the container constructor for some + // containers (would it?) + obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); } // overload for arithmetic types, not chosen for basic_json template arguments // (BooleanType, etc..); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) +template < + typename BasicJsonType, + typename ArithmeticType, + enable_if_t< + std::is_arithmetic::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value and + not std::is_same::value, + int> = 0> +void from_json(const BasicJsonType & j, ArithmeticType & val) { - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - default: - { - JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name())); - } - } + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + default: + { + JSON_THROW(type_error::create(302, "type must be number, but is " + j.type_name())); + } + } } struct to_json_fn { - private: - template - auto call(BasicJsonType& j, T&& val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } - - template - void call(BasicJsonType&, T&&, priority_tag<0>) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - } - - public: - template - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) - { - return call(j, std::forward(val), priority_tag<1> {}); - } +private: + template + auto call(BasicJsonType & j, T && val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } + + template + void call(BasicJsonType &, T &&, priority_tag<0>) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, "could not find to_json() method in T's namespace"); + } + +public: + template + void operator()(BasicJsonType & j, T && val) const + noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1>{}))) + { + return call(j, std::forward(val), priority_tag<1>{}); + } }; struct from_json_fn { - private: - template - auto call(const BasicJsonType& j, T& val, priority_tag<1>) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template - void call(const BasicJsonType&, T&, priority_tag<0>) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); - } - - public: - template - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } +private: + template + auto call(const BasicJsonType & j, T & val, priority_tag<1>) const noexcept(noexcept(from_json(j, val))) + -> decltype(from_json(j, val), void()) + { + return from_json(j, val); + } + + template + void call(const BasicJsonType &, T &, priority_tag<0>) const noexcept + { + static_assert(sizeof(BasicJsonType) == 0, "could not find from_json() method in T's namespace"); + } + +public: + template + void operator()(const BasicJsonType & j, T & val) const + noexcept(noexcept(std::declval().call(j, val, priority_tag<1>{}))) + { + return call(j, val, priority_tag<1>{}); + } }; // taken from ranges-v3 -template +template struct static_const { - static constexpr T value{}; + static constexpr T value{}; }; -template +template constexpr T static_const::value; -} // namespace detail - +} // namespace detail /// namespace to hold default `to_json` / `from_json` functions namespace { -constexpr const auto& to_json = detail::static_const::value; -constexpr const auto& from_json = detail::static_const::value; -} - +constexpr const auto & to_json = detail::static_const::value; +constexpr const auto & from_json = detail::static_const::value; +} // namespace /*! @brief default JSONSerializer template argument @@ -1166,43 +1227,42 @@ This serializer ignores the template arguments and uses ADL ([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) for serialization. */ -template +template struct adl_serializer { - /*! - @brief convert a JSON value to any value type - - This function is usually called by the `get()` function of the - @ref basic_json class (either explicit or via conversion operators). - - @param[in] j JSON value to read from - @param[in,out] val value to write to - */ - template - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward(j), val))) - { - ::nlohmann::from_json(std::forward(j), val); - } - - /*! - @brief convert any value type to a JSON value - - This function is usually called by the constructors of the @ref basic_json - class. - - @param[in,out] j JSON value to write to - @param[in] val value to read from - */ - template - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( - noexcept(::nlohmann::to_json(j, std::forward(val)))) - { - ::nlohmann::to_json(j, std::forward(val)); - } + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static void from_json(BasicJsonType && j, ValueType & val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static void to_json(BasicJsonType & j, ValueType && val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + { + ::nlohmann::to_json(j, std::forward(val)); + } }; - /*! @brief a class to store JSON values @@ -1285,13064 +1345,13026 @@ Format](http://rfc7159.net/rfc7159) @nosubgrouping */ template < - template class ObjectType = std::map, - template class ArrayType = std::vector, + template class ObjectType = std::map, + template class ArrayType = std::vector, class StringType = std::string, class BooleanType = bool, class NumberIntegerType = std::int64_t, class NumberUnsignedType = std::uint64_t, class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = adl_serializer - > + template class AllocatorType = std::allocator, + template class JSONSerializer = adl_serializer> class basic_json { - private: - template friend struct detail::external_constructor; - /// workaround type for MSVC - using basic_json_t = basic_json; +private: + template + friend struct detail::external_constructor; + /// workaround type for MSVC + using basic_json_t = basic_json< + ObjectType, + ArrayType, + StringType, + BooleanType, + NumberIntegerType, + NumberUnsignedType, + NumberFloatType, + AllocatorType, + JSONSerializer>; + +public: + using value_t = detail::value_t; + // forward declarations + template + class iter_impl; + template + class json_reverse_iterator; + class json_pointer; + template + using json_serializer = JSONSerializer; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type &; + /// the type of an element const reference + using const_reference = const value_type &; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ + standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, + `sunpro`, and `unknown`), and `version` (the compiler version). `copyright` | The copyright line for the library as + string. `name` | The name of the library as string. `platform` | The used platform as string. Possible values + are `win32`, `linux`, `apple`, `unix`, and `unknown`. `url` | The URL of the project as string. `version` | + The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by + [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @complexity Constant. + + @since 2.1.0 + */ + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2017 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"] = {{"string", "2.1.1"}, {"major", 2}, {"minor", 1}, {"patch", 1}}; - public: - using value_t = detail::value_t; - // forward declarations - template class iter_impl; - template class json_reverse_iterator; - class json_pointer; - template - using json_serializer = JSONSerializer; - - - //////////////// - // exceptions // - //////////////// - - /// @name exceptions - /// Classes to implement user-defined exceptions. - /// @{ - - /// @copydoc detail::exception - using exception = detail::exception; - /// @copydoc detail::parse_error - using parse_error = detail::parse_error; - /// @copydoc detail::invalid_iterator - using invalid_iterator = detail::invalid_iterator; - /// @copydoc detail::type_error - using type_error = detail::type_error; - /// @copydoc detail::out_of_range - using out_of_range = detail::out_of_range; - /// @copydoc detail::other_error - using other_error = detail::other_error; - - /// @} +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif +#if defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = { + {"family", "gcc"}, + {"version", + std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif - ///////////////////// - // container types // - ///////////////////// +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + + /*! + @brief a type for an object + + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, later stored name/value + pairs overwrite previously stored name/value pairs, leaving the used + names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will + be treated as equal and both stored as `{"key": 1}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. - /// the type of elements in a basic_json container - using value_type = basic_json; + #### Limits - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; + In this class, the object's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. - /// the allocator type - using allocator_type = AllocatorType; + #### Storage - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. - /// an iterator for a basic_json container - using iterator = iter_impl; - /// a const iterator for a basic_json container - using const_iterator = iter_impl; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; + @sa @ref array_t -- type for an array value - /// @} + @since version 1.0.0 + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 7159](http://rfc7159.net/rfc7159), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = + ObjectType, AllocatorType>>; - /*! - @brief returns the allocator associated with the container - */ - static allocator_type get_allocator() - { - return allocator_type(); - } + /*! + @brief a type for an array - /*! - @brief returns version information on the library + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. - This function returns a JSON object with information about the library, - including the version number and information on the platform and compiler. + To store objects in C++, a type is defined by the template parameters + explained below. - @return JSON object holding version information - key | description - ----------- | --------------- - `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). - `copyright` | The copyright line for the library as string. - `name` | The name of the library as string. - `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. - `url` | The URL of the project as string. - `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) - @liveexample{The following code shows an example output of the `meta()` - function.,meta} + #### Default type - @complexity Constant. + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: - @since 2.1.0 - */ - static basic_json meta() - { - basic_json result; - - result["copyright"] = "(C) 2013-2017 Niels Lohmann"; - result["name"] = "JSON for Modern C++"; - result["url"] = "https://github.com/nlohmann/json"; - result["version"] = - { - {"string", "2.1.1"}, {"major", 2}, {"minor", 1}, {"patch", 1} - }; - -#ifdef _WIN32 - result["platform"] = "win32"; -#elif defined __linux__ - result["platform"] = "linux"; -#elif defined __APPLE__ - result["platform"] = "apple"; -#elif defined __unix__ - result["platform"] = "unix"; -#else - result["platform"] = "unknown"; -#endif + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode -#if defined(__clang__) - result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; -#elif defined(__ICC) || defined(__INTEL_COMPILER) - result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; -#elif defined(__GNUC__) || defined(__GNUG__) - result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; -#elif defined(__HP_cc) || defined(__HP_aCC) - result["compiler"] = "hp" -#elif defined(__IBMCPP__) - result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; -#elif defined(_MSC_VER) - result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; -#elif defined(__PGI) - result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; -#elif defined(__SUNPRO_CC) - result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; -#else - result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; -#endif + #### Limits -#ifdef __cplusplus - result["compiler"]["c++"] = std::to_string(__cplusplus); -#else - result["compiler"]["c++"] = "unknown"; -#endif - return result; - } + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the maximum depth of nesting. + In this class, the array's limit of nesting is not constraint explicitly. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. - /////////////////////////// - // JSON value data types // - /////////////////////////// + #### Storage - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. - /*! - @brief a type for an object + @sa @ref object_t -- type for an object value - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: - > An object is an unordered collection of zero or more name/value pairs, - > where a name is a string and a value is a string, number, boolean, null, - > object, or array. + @since version 1.0.0 + */ + using array_t = ArrayType>; - To store objects in C++, a type is defined by the template parameters - described below. + /*! + @brief a type for a string - @tparam ObjectType the container to store objects (e.g., `std::map` or - `std::unordered_map`) - @tparam StringType the type of the keys or names (e.g., `std::string`). - The comparison function `std::less` is used to order elements - inside the container. - @tparam AllocatorType the allocator to use for objects (e.g., - `std::allocator`) + [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. - #### Default type + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. - With the default values for @a ObjectType (`std::map`), @a StringType - (`std::string`), and @a AllocatorType (`std::allocator`), the default - value for @a object_t is: + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. - @code {.cpp} - std::map< - std::string, // key_type - basic_json, // value_type - std::less, // key_compare - std::allocator> // allocator_type - > - @endcode + #### Default type - #### Behavior - - The choice of @a object_t influences the behavior of the JSON class. With - the default type, objects have the following behavior: - - - When all names are unique, objects will be interoperable in the sense - that all software implementations receiving that object will agree on - the name-value mappings. - - When the names within an object are not unique, later stored name/value - pairs overwrite previously stored name/value pairs, leaving the used - names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will - be treated as equal and both stored as `{"key": 1}`. - - Internally, name/value pairs are stored in lexicographical order of the - names. Objects will also be serialized (see @ref dump) in this order. - For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored - and serialized as `{"a": 2, "b": 1}`. - - When comparing objects, the order of the name/value pairs is irrelevant. - This makes objects interoperable in the sense that they will not be - affected by these differences. For instance, `{"b": 1, "a": 2}` and - `{"a": 2, "b": 1}` will be treated as equal. - - #### Limits - - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. - - In this class, the object's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON object. - - #### Storage - - Objects are stored as pointers in a @ref basic_json type. That is, for any - access to object values, a pointer of type `object_t*` must be - dereferenced. - - @sa @ref array_t -- type for an array value - - @since version 1.0.0 - - @note The order name/value pairs are added to the object is *not* - preserved by the library. Therefore, iterating an object may return - name/value pairs in a different order than they were originally stored. In - fact, keys will be traversed in alphabetical order as `std::map` with - `std::less` is used by default. Please note this behavior conforms to [RFC - 7159](http://rfc7159.net/rfc7159), because any order implements the - specified "unordered" nature of JSON objects. - */ - using object_t = ObjectType, - AllocatorType>>; + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: - /*! - @brief a type for an array + @code {.cpp} + std::string + @endcode - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: - > An array is an ordered sequence of zero or more values. + #### Encoding - To store objects in C++, a type is defined by the template parameters - explained below. + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. - @tparam ArrayType container type to store arrays (e.g., `std::vector` or - `std::list`) - @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + #### String comparison - #### Default type + [RFC 7159](http://rfc7159.net/rfc7159) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. - With the default values for @a ArrayType (`std::vector`) and @a - AllocatorType (`std::allocator`), the default value for @a array_t is: + This implementation is interoperable as it does compare strings code unit + by code unit. - @code {.cpp} - std::vector< - basic_json, // value_type - std::allocator // allocator_type - > - @endcode + #### Storage - #### Limits + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the maximum depth of nesting. + @since version 1.0.0 + */ + using string_t = StringType; - In this class, the array's limit of nesting is not constraint explicitly. - However, a maximum depth of nesting may be introduced by the compiler or - runtime environment. A theoretical limit can be queried by calling the - @ref max_size function of a JSON array. + /*! + @brief a type for a boolean - #### Storage + [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. - Arrays are stored as pointers in a @ref basic_json type. That is, for any - access to array values, a pointer of type `array_t*` must be dereferenced. + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. - @sa @ref object_t -- type for an object value + #### Default type - @since version 1.0.0 - */ - using array_t = ArrayType>; + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: - /*! - @brief a type for a string + @code {.cpp} + bool + @endcode - [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: - > A string is a sequence of zero or more Unicode characters. + #### Storage - To store objects in C++, a type is defined by the template parameter - described below. Unicode values are split by the JSON class into - byte-sized characters during deserialization. + Boolean values are stored directly inside a @ref basic_json type. - @tparam StringType the container to store strings (e.g., `std::string`). - Note this container is used for keys/names in objects, see @ref object_t. + @since version 1.0.0 + */ + using boolean_t = BooleanType; - #### Default type + /*! + @brief a type for a number (integer) - With the default values for @a StringType (`std::string`), the default - value for @a string_t is: + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. - @code {.cpp} - std::string - @endcode + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. - #### Encoding + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. - Strings are stored in UTF-8 encoding. Therefore, functions like - `std::string::size()` or `std::string::length()` return the number of - bytes in the string rather than the number of characters or glyphs. + #### Default type - #### String comparison + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: - [RFC 7159](http://rfc7159.net/rfc7159) states: - > Software implementations are typically required to test names of object - > members for equality. Implementations that transform the textual - > representation into sequences of Unicode code units and then perform the - > comparison numerically, code unit by code unit, are interoperable in the - > sense that implementations will agree in all cases on equality or - > inequality of two strings. For example, implementations that compare - > strings with escaped characters unconverted may incorrectly find that - > `"a\\b"` and `"a\u005Cb"` are not equal. + @code {.cpp} + int64_t + @endcode - This implementation is interoperable as it does compare strings code unit - by code unit. + #### Default behavior - #### Storage + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. - String values are stored as pointers in a @ref basic_json type. That is, - for any access to string values, a pointer of type `string_t*` must be - dereferenced. + #### Limits - @since version 1.0.0 - */ - using string_t = StringType; + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. - /*! - @brief a type for a boolean + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. - [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a - type which differentiates the two literals `true` and `false`. + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. - To store objects in C++, a type is defined by the template parameter @a - BooleanType which chooses the type to use. + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. - #### Default type + #### Storage - With the default values for @a BooleanType (`bool`), the default value for - @a boolean_t is: + Integer number values are stored directly inside a @ref basic_json type. - @code {.cpp} - bool - @endcode + @sa @ref number_float_t -- type for number values (floating-point) - #### Storage + @sa @ref number_unsigned_t -- type for number values (unsigned integer) - Boolean values are stored directly inside a @ref basic_json type. + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; - @since version 1.0.0 - */ - using boolean_t = BooleanType; + /*! + @brief a type for a number (unsigned) - /*! - @brief a type for a number (integer) + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. - To store integer numbers in C++, a type is defined by the template - parameter @a NumberIntegerType which chooses the type to use. + #### Default type - #### Default type + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: - With the default values for @a NumberIntegerType (`int64_t`), the default - value for @a number_integer_t is: + @code {.cpp} + uint64_t + @endcode - @code {.cpp} - int64_t - @endcode + #### Default behavior - #### Default behavior + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. + #### Limits - #### Limits + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. - When the default type is used, the maximal integer number that can be - stored is `9223372036854775807` (INT64_MAX) and the minimal integer number - that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers - that are out of range will yield over/underflow when used in a - constructor. During deserialization, too large or small integer numbers - will be automatically be stored as @ref number_unsigned_t or @ref - number_float_t. + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. - As this range is a subrange of the exactly supported range [INT64_MIN, - INT64_MAX], this class's integer type is interoperable. + #### Storage - #### Storage + Integer number values are stored directly inside a @ref basic_json type. - Integer number values are stored directly inside a @ref basic_json type. + @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_integer_t -- type for number values (integer) - @sa @ref number_float_t -- type for number values (floating-point) + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; - @sa @ref number_unsigned_t -- type for number values (unsigned integer) + /*! + @brief a type for a number (floating-point) - @since version 1.0.0 - */ - using number_integer_t = NumberIntegerType; + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. - /*! - @brief a type for a number (unsigned) + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. + #### Default type - To store unsigned integer numbers in C++, a type is defined by the - template parameter @a NumberUnsignedType which chooses the type to use. + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior - #### Default type + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. - With the default values for @a NumberUnsignedType (`uint64_t`), the - default value for @a number_unsigned_t is: + #### Limits - @code {.cpp} - uint64_t - @endcode + [RFC 7159](http://rfc7159.net/rfc7159) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. - #### Default behavior + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in integer literals lead to an interpretation as octal - number. Internally, the value will be stored as decimal number. For - instance, the C++ integer literal `010` will be serialized to `8`. - During deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. + #### Storage - #### Limits + Floating-point number values are stored directly inside a @ref basic_json + type. - [RFC 7159](http://rfc7159.net/rfc7159) specifies: - > An implementation may set limits on the range and precision of numbers. + @sa @ref number_integer_t -- type for number values (integer) + + @sa @ref number_unsigned_t -- type for number values (unsigned integer) - When the default type is used, the maximal integer number that can be - stored is `18446744073709551615` (UINT64_MAX) and the minimal integer - number that can be stored is `0`. Integer numbers that are out of range - will yield over/underflow when used in a constructor. During - deserialization, too large or small integer numbers will be automatically - be stored as @ref number_integer_t or @ref number_float_t. + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; - [RFC 7159](http://rfc7159.net/rfc7159) further states: - > Note that when such software is used, numbers that are integers and are - > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense - > that implementations will agree exactly on their numeric values. + /// @} - As this range is a subrange (when considered in conjunction with the - number_integer_t type) of the exactly supported range [0, UINT64_MAX], - this class's integer type is interoperable. +private: + /// helper for exception-safe object creation + template + static T * create(Args &&... args) + { + AllocatorType alloc; + auto deleter = [&](T * object) { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + assert(object != nullptr); + return object.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t * object; + /// array (stored with pointer to save storage) + array_t * array; + /// string (stored with pointer to save storage) + string_t * string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept + : boolean(v) + { + } + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept + : number_integer(v) + { + } + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept + : number_unsigned(v) + { + } + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept + : number_float(v) + { + } + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + break; + } + + default: + { + if (JSON_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t & value) + { + string = create(value); + } + + /// constructor for objects + json_value(const object_t & value) + { + object = create(value); + } + + /// constructor for arrays + json_value(const array_t & value) + { + array = create(value); + } + }; + + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + */ + void assert_invariant() const + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } + +public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief JSON callback events + + This enumeration lists the parser events that can trigger calling a + callback function of type @ref parser_callback_t during parsing. + + @image html callback_events.png "Example when certain parse events are triggered" + + @since version 1.0.0 + */ + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse(std::istream&, const + parser_callback_t) or @ref parse(const CharT, const parser_callback_t), + it is called on certain events (passed as @ref parse_event_t via parameter + @a event) with a set recursion depth @a depth and context JSON value + @a parsed. The return value of the callback function is a boolean + indicating whether the element that emitted the callback shall be kept or + not. - #### Storage + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the + JSON object | a JSON value with type discarded parse_event_t::key | the parser read a key of a value in an object | + depth of the currently parsed JSON object | a JSON string containing the key parse_event_t::object_end | the parser + read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON + array | a JSON value with type discarded parse_event_t::array_end | the parser read `]` and finished processing a JSON + array | depth of the parent of the JSON array | the parsed JSON array parse_event_t::value | the parser finished + reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa @ref parse(std::istream&, parser_callback_t) or + @ref parse(const CharT, const parser_callback_t) for examples + + @since version 1.0.0 + */ + using parser_callback_t = std::function; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + + @param[in] value_type the type of the value to create + + @complexity Constant. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @since version 1.0.0 + */ + basic_json(const value_t value_type) + : m_type(value_type) + , m_value(value_type) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exsits. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and + `unordered_multiset` with a `value_type` from which a @ref basic_json + value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - @ref @ref json_serializer has a + `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @throw what `json_serializer::to_json()` throws + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template < + typename CompatibleType, + typename U = detail::uncvref_t, + detail::enable_if_t< + not std::is_base_of::value and not std::is_same::value and + not detail::is_basic_json_nested_type::value and + detail::has_to_json::value, + int> = 0> + basic_json(CompatibleType && val) noexcept( + noexcept(JSONSerializer::to_json(std::declval(), std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has now way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(std::initializer_list) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(std::initializer_list) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(std::initializer_list) and + @ref object(std::initializer_list). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(std::initializer_list) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(std::initializer_list init, bool type_deduction = true, value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), [](const basic_json & element) { + return element.is_array() and element.size() == 2 and element[0].is_string(); + }); - Integer number values are stored directly inside a @ref basic_json type. + // adjust type if type deduction is not wanted + if (not type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } - @sa @ref number_float_t -- type for number values (floating-point) - @sa @ref number_integer_t -- type for number values (integer) + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list")); + } + } - @since version 2.0.0 - */ - using number_unsigned_t = NumberUnsignedType; + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; - /*! - @brief a type for a number (floating-point) + std::for_each(init.begin(), init.end(), [this](const basic_json & element) { + m_value.object->emplace(*(element[0].m_value.string), element[1]); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init); + } - [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: - > The representation of numbers is similar to that used in most - > programming languages. A number is represented in base 10 using decimal - > digits. It contains an integer component that may be prefixed with an - > optional minus sign, which may be followed by a fraction part and/or an - > exponent part. Leading zeros are not allowed. (...) Numeric values that - > cannot be represented in the grammar below (such as Infinity and NaN) - > are not permitted. + assert_invariant(); + } - This description includes both integer and floating-point numbers. - However, C++ allows more precise storage if it is known whether the number - is a signed integer, an unsigned integer or a floating-point number. - Therefore, three different types, @ref number_integer_t, @ref - number_unsigned_t and @ref number_float_t are used. + /*! + @brief explicitly create an array from an initializer list - To store floating-point numbers in C++, a type is defined by the template - parameter @a NumberFloatType which chooses the type to use. + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. - #### Default type + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(std::initializer_list, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object - With the default values for @a NumberFloatType (`double`), the default - value for @a number_float_t is: + @param[in] init initializer list with JSON values to create an array from + (optional) - @code {.cpp} - double - @endcode + @return JSON array value - #### Default behavior + @complexity Linear in the size of @a init. - - The restrictions about leading zeros is not enforced in C++. Instead, - leading zeros in floating-point literals will be ignored. Internally, - the value will be stored as decimal number. For instance, the C++ - floating-point literal `01.2` will be serialized to `1.2`. During - deserialization, leading zeros yield an error. - - Not-a-number (NaN) values will be serialized to `null`. + @liveexample{The following code shows an example for the `array` + function.,array} - #### Limits + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref object(std::initializer_list) -- create a JSON object + value from an initializer list - [RFC 7159](http://rfc7159.net/rfc7159) states: - > This specification allows implementations to set limits on the range and - > precision of numbers accepted. Since software that implements IEEE - > 754-2008 binary64 (double precision) numbers is generally available and - > widely used, good interoperability can be achieved by implementations - > that expect no more precision or range than these provide, in the sense - > that implementations will approximate JSON numbers within the expected - > precision. + @since version 1.0.0 + */ + static basic_json array(std::initializer_list init = std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } - This implementation does exactly follow this approach, as it uses double - precision floating-point numbers. Note values smaller than - `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` - will be stored as NaN internally and be serialized to `null`. + /*! + @brief explicitly create an object from an initializer list - #### Storage + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. - Floating-point number values are stored directly inside a @ref basic_json - type. + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(std::initializer_list), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(std::initializer_list, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(std::initializer_list, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. - @sa @ref number_integer_t -- type for number values (integer) + @complexity Linear in the size of @a init. - @sa @ref number_unsigned_t -- type for number values (unsigned integer) + @liveexample{The following code shows an example for the `object` + function.,object} - @since version 1.0.0 - */ - using number_float_t = NumberFloatType; + @sa @ref basic_json(std::initializer_list, bool, value_t) -- + create a JSON value from an initializer list + @sa @ref array(std::initializer_list) -- create a JSON array + value from an initializer list - /// @} + @since version 1.0.0 + */ + static basic_json object(std::initializer_list init = std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } - private: + /*! + @brief construct an array with count copies of given value - /// helper for exception-safe object creation - template - static T* create(Args&& ... args) - { - AllocatorType alloc; - auto deleter = [&](T * object) - { - alloc.deallocate(object, 1); - }; - std::unique_ptr object(alloc.allocate(1), deleter); - alloc.construct(object.get(), std::forward(args)...); - assert(object != nullptr); - return object.release(); - } + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. As postcondition, + `std::distance(begin(),end()) == cnt` holds. - //////////////////////// - // JSON value storage // - //////////////////////// + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy - /*! - @brief a JSON value - - The actual storage for a JSON value of the @ref basic_json class. This - union combines the different storage types for the JSON value types - defined in @ref value_t. - - JSON type | value_t type | used type - --------- | --------------- | ------------------------ - object | object | pointer to @ref object_t - array | array | pointer to @ref array_t - string | string | pointer to @ref string_t - boolean | boolean | @ref boolean_t - number | number_integer | @ref number_integer_t - number | number_unsigned | @ref number_unsigned_t - number | number_float | @ref number_float_t - null | null | *no value is stored* - - @note Variable-length types (objects, arrays, and strings) are stored as - pointers. The size of the union should not exceed 64 bits if the default - value types are used. - - @since version 1.0.0 - */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: - { - object = create(); - break; - } + @complexity Linear in @a cnt. - case value_t::array: - { - array = create(); - break; - } + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} - case value_t::string: - { - string = create(""); - break; - } + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json & val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } + /*! + @brief construct a JSON container given an iterator range - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of primitive types (number, boolean, or string), @a first must + be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector`. + - In case of a null type, invalid_iterator.206 is thrown. - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) - case value_t::null: - { - break; - } + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion.** - default: - { - if (JSON_UNLIKELY(t == value_t::null)) - { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 2.1.1")); // LCOV_EXCL_LINE - } - break; - } - } - } + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. - /// constructor for strings - json_value(const string_t& value) - { - string = create(value); - } + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. - /// constructor for objects - json_value(const object_t& value) - { - object = create(value); - } + @complexity Linear in distance between @a first and @a last. - /// constructor for arrays - json_value(const array_t& value) - { - array = create(value); - } - }; + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} - /*! - @brief checks the class invariants + @since version 1.0.0 + */ + template < + class InputIT, + typename std::enable_if< + std::is_same::value or + std::is_same::value, + int>::type = 0> + basic_json(InputIT first, InputIT last) + { + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); - This function asserts the class invariants. It needs to be called at the - end of every constructor to make sure that created objects respect the - invariant. Furthermore, it has to be called each time the type of a JSON - value is changed, because the invariant expresses a relationship between - @a m_type and @a m_value. - */ - void assert_invariant() const + // make sure iterator fits the current value + if (first.m_object != last.m_object) { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); } - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// - - /*! - @brief JSON callback events - - This enumeration lists the parser events that can trigger calling a - callback function of type @ref parser_callback_t during parsing. - - @image html callback_events.png "Example when certain parse events are triggered" + // copy type from first iterator + m_type = first.m_object->m_type; - @since version 1.0.0 - */ - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; - - /*! - @brief per-element parser callback type - - With a parser callback function, the result of parsing a JSON text can be - influenced. When passed to @ref parse(std::istream&, const - parser_callback_t) or @ref parse(const CharT, const parser_callback_t), - it is called on certain events (passed as @ref parse_event_t via parameter - @a event) with a set recursion depth @a depth and context JSON value - @a parsed. The return value of the callback function is a boolean - indicating whether the element that emitted the callback shall be kept or - not. - - We distinguish six scenarios (determined by the event type) in which the - callback function can be called. The following table describes the values - of the parameters @a depth, @a event, and @a parsed. - - parameter @a event | description | parameter @a depth | parameter @a parsed - ------------------ | ----------- | ------------------ | ------------------- - parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded - parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key - parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object - parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded - parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array - parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + break; + } - @image html callback_events.png "Example when certain parse events are triggered" + default: + { + break; + } + } - Discarding a value (i.e., returning `false`) has different effects - depending on the context in which function was called: + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } - - Discarded values in structured types are skipped. That is, the parser - will behave as if the discarded value was never read. - - In case a value outside a structured type is skipped, it is replaced - with `null`. This case happens if the top-level element is skipped. + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } - @param[in] depth the depth of the recursion during parsing + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } - @param[in] event an event of type parse_event_t indicating the context in - the callback function has been called + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } - @param[in,out] parsed the current intermediate parse result; note that - writing to this value has no effect for parse_event_t::key events + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } - @return Whether the JSON value which called the function during parsing - should be kept (`true`) or not (`false`). In the latter case, it is either - skipped completely or replaced by an empty discarded object. + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } - @sa @ref parse(std::istream&, parser_callback_t) or - @ref parse(const CharT, const parser_callback_t) for examples + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } - @since version 1.0.0 - */ - using parser_callback_t = std::function; + default: + { + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + first.m_object->type_name())); + } + } + assert_invariant(); + } - ////////////////// - // constructors // - ////////////////// + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ + /*! + @brief copy constructor - /*! - @brief create an empty value with a given type + Creates a copy of a given JSON value. - Create an empty JSON value with a given type. The value will be default - initialized with an empty value which depends on the type: + @param[in] other the JSON value to copy - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` + @complexity Linear in the size of @a other. - @param[in] value_type the type of the value to create + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. - @complexity Constant. + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} - @liveexample{The following code shows the constructor for different @ref - value_t values,basic_json__value_t} + @since version 1.0.0 + */ + basic_json(const basic_json & other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); - @since version 1.0.0 - */ - basic_json(const value_t value_type) - : m_type(value_type), m_value(value_type) + switch (m_type) { - assert_invariant(); + case value_t::object: + { + m_value = *other.m_value.object; + break; } - /*! - @brief create a null object - - Create a `null` JSON value. It either takes a null pointer as parameter - (explicitly creating `null`) or no parameter (implicitly creating `null`). - The passed null pointer itself is not read -- it is only used to choose - the right constructor. + case value_t::array: + { + m_value = *other.m_value.array; + break; + } - @complexity Constant. + case value_t::string: + { + m_value = *other.m_value.string; + break; + } - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } - @liveexample{The following code shows the constructor with and without a - null pointer parameter.,basic_json__nullptr_t} + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } - @since version 1.0.0 - */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) + case value_t::number_unsigned: { - assert_invariant(); + m_value = other.m_value.number_unsigned; + break; } - /*! - @brief create a JSON value - - This is a "catch all" constructor for all compatible JSON types; that is, - types for which a `to_json()` method exsits. The constructor forwards the - parameter @a val to that method (to `json_serializer::to_json` method - with `U = uncvref_t`, to be exact). - - Template type @a CompatibleType includes, but is not limited to, the - following types: - - **arrays**: @ref array_t and all kinds of compatible containers such as - `std::vector`, `std::deque`, `std::list`, `std::forward_list`, - `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and - `unordered_multiset` with a `value_type` from which a @ref basic_json - value can be constructed. - - **objects**: @ref object_t and all kinds of compatible associative - containers such as `std::map`, `std::unordered_map`, `std::multimap`, - and `std::unordered_multimap` with a `key_type` compatible to - @ref string_t and a `value_type` from which a @ref basic_json value can - be constructed. - - **strings**: @ref string_t, string literals, and all compatible string - containers can be used. - - **numbers**: @ref number_integer_t, @ref number_unsigned_t, - @ref number_float_t, and all convertible number types such as `int`, - `size_t`, `int64_t`, `float` or `double` can be used. - - **boolean**: @ref boolean_t / `bool` can be used. - - See the examples below. - - @tparam CompatibleType a type such that: - - @a CompatibleType is not derived from `std::istream`, - - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move - constructors), - - @a CompatibleType is not a @ref basic_json nested type (e.g., - @ref json_pointer, @ref iterator, etc ...) - - @ref @ref json_serializer has a - `to_json(basic_json_t&, CompatibleType&&)` method - - @tparam U = `uncvref_t` - - @param[in] val the value to be forwarded - - @complexity Usually linear in the size of the passed @a val, also - depending on the implementation of the called `to_json()` - method. - - @throw what `json_serializer::to_json()` throws - - @liveexample{The following code shows the constructor with several - compatible types.,basic_json__CompatibleType} - - @since version 2.1.0 - */ - template, - detail::enable_if_t::value and - not std::is_same::value and - not detail::is_basic_json_nested_type< - basic_json_t, U>::value and - detail::has_to_json::value, - int> = 0> - basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer::to_json( - std::declval(), std::forward(val)))) + case value_t::number_float: { - JSONSerializer::to_json(*this, std::forward(val)); - assert_invariant(); + m_value = other.m_value.number_float; + break; } - /*! - @brief create a container (array or object) from an initializer list - - Creates a JSON value of type array or object from the passed initializer - list @a init. In case @a type_deduction is `true` (default), the type of - the JSON value to be created is deducted from the initializer list @a init - according to the following rules: - - 1. If the list is empty, an empty JSON object value `{}` is created. - 2. If the list consists of pairs whose first element is a string, a JSON - object value is created where the first elements of the pairs are - treated as keys and the second elements are as values. - 3. In all other cases, an array is created. - - The rules aim to create the best fit between a C++ initializer list and - JSON values. The rationale is as follows: - - 1. The empty initializer list is written as `{}` which is exactly an empty - JSON object. - 2. C++ has now way of describing mapped types other than to list a list of - pairs. As JSON requires that keys must be of type string, rule 2 is the - weakest constraint one can pose on initializer lists to interpret them - as an object. - 3. In all other cases, the initializer list could not be interpreted as - JSON object type, so interpreting it as JSON array type is safe. - - With the rules described above, the following JSON values cannot be - expressed by an initializer list: - - - the empty array (`[]`): use @ref array(std::initializer_list) - with an empty initializer list in this case - - arrays whose elements satisfy rule 2: use @ref - array(std::initializer_list) with the same initializer list - in this case - - @note When used without parentheses around an empty initializer list, @ref - basic_json() is called instead of this function, yielding the JSON null - value. - - @param[in] init initializer list with JSON values - - @param[in] type_deduction internal parameter; when set to `true`, the type - of the JSON value is deducted from the initializer list @a init; when set - to `false`, the type provided via @a manual_type is forced. This mode is - used by the functions @ref array(std::initializer_list) and - @ref object(std::initializer_list). - - @param[in] manual_type internal parameter; when @a type_deduction is set - to `false`, the created JSON value will use the provided type (only @ref - value_t::array and @ref value_t::object are valid); when @a type_deduction - is set to `true`, this parameter has no effect - - @throw type_error.301 if @a type_deduction is `false`, @a manual_type is - `value_t::object`, but @a init contains an element which is not a pair - whose first element is a string. In this case, the constructor could not - create an object. If @a type_deduction would have be `true`, an array - would have been created. See @ref object(std::initializer_list) - for an example. - - @complexity Linear in the size of the initializer list @a init. - - @liveexample{The example below shows how JSON values are created from - initializer lists.,basic_json__list_init_t} - - @sa @ref array(std::initializer_list) -- create a JSON array - value from an initializer list - @sa @ref object(std::initializer_list) -- create a JSON object - value from an initializer list - - @since version 1.0.0 - */ - basic_json(std::initializer_list init, - bool type_deduction = true, - value_t manual_type = value_t::array) + default: { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const basic_json & element) - { - return element.is_array() and element.size() == 2 and element[0].is_string(); - }); + break; + } + } - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) - { - is_an_object = false; - } + assert_invariant(); + } - // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_an_object) - { - JSON_THROW(type_error::create(301, "cannot create object from initializer list")); - } - } + /*! + @brief move constructor - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. - std::for_each(init.begin(), init.end(), [this](const basic_json & element) - { - m_value.object->emplace(*(element[0].m_value.string), element[1]); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init); - } + @param[in,out] other value to move to this object - assert_invariant(); - } + @post @a other is a JSON null value - /*! - @brief explicitly create an array from an initializer list + @complexity Constant. - Creates a JSON array value from a given initializer list. That is, given a - list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the - initializer list is empty, the empty array `[]` is created. + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} - @note This function is only needed to express two edge cases that cannot - be realized with the initializer list constructor (@ref - basic_json(std::initializer_list, bool, value_t)). These cases - are: - 1. creating an array whose elements are all pairs whose first element is a - string -- in this case, the initializer list constructor would create an - object, taking the first elements as keys - 2. creating an empty array -- passing the empty initializer list to the - initializer list constructor yields an empty object + @since version 1.0.0 + */ + basic_json(basic_json && other) noexcept + : m_type(std::move(other.m_type)) + , m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); - @param[in] init initializer list with JSON values to create an array from - (optional) + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; - @return JSON array value + assert_invariant(); + } - @complexity Linear in the size of @a init. + /*! + @brief copy assignment - @liveexample{The following code shows an example for the `array` - function.,array} + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the swap() member function. - @sa @ref basic_json(std::initializer_list, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref object(std::initializer_list) -- create a JSON object - value from an initializer list + @param[in] other value to copy from - @since version 1.0.0 - */ - static basic_json array(std::initializer_list init = - std::initializer_list()) - { - return basic_json(init, false, value_t::array); - } + @complexity Linear. - /*! - @brief explicitly create an object from an initializer list + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. - Creates a JSON object value from a given initializer list. The initializer - lists elements must be pairs, and their first elements must be strings. If - the initializer list is empty, the empty object `{}` is created. + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} - @note This function is only added for symmetry reasons. In contrast to the - related function @ref array(std::initializer_list), there are - no cases which can only be expressed by this function. That is, any - initializer list @a init can also be passed to the initializer list - constructor @ref basic_json(std::initializer_list, bool, value_t). + @since version 1.0.0 + */ + reference & operator=(basic_json other) noexcept( + std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value) + { + // check that passed value is valid + other.assert_invariant(); - @param[in] init initializer list to create an object from (optional) + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); - @return JSON object value + assert_invariant(); + return *this; + } - @throw type_error.301 if @a init is not a list of pairs whose first - elements are strings. In this case, no object can be created. When such a - value is passed to @ref basic_json(std::initializer_list, bool, value_t), - an array would have been created from the passed initializer list @a init. - See example below. + /*! + @brief destructor - @complexity Linear in the size of @a init. + Destroys the JSON value and frees all allocated memory. - @liveexample{The following code shows an example for the `object` - function.,object} + @complexity Linear. - @sa @ref basic_json(std::initializer_list, bool, value_t) -- - create a JSON value from an initializer list - @sa @ref array(std::initializer_list) -- create a JSON array - value from an initializer list + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. - @since version 1.0.0 - */ - static basic_json object(std::initializer_list init = - std::initializer_list()) + @since version 1.0.0 + */ + ~basic_json() + { + assert_invariant(); + + switch (m_type) + { + case value_t::object: { - return basic_json(init, false, value_t::object); + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; } - /*! - @brief construct an array with count copies of given value - - Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == cnt` holds. - - @param[in] cnt the number of JSON copies of @a val to create - @param[in] val the JSON value to copy - - @complexity Linear in @a cnt. - - @liveexample{The following code shows examples for the @ref - basic_json(size_type\, const basic_json&) - constructor.,basic_json__size_type_basic_json} - - @since version 1.0.0 - */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) + case value_t::array: { - m_value.array = create(cnt, val); - assert_invariant(); + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; } - /*! - @brief construct a JSON container given an iterator range - - Constructs the JSON value with the contents of the range `[first, last)`. - The semantics depends on the different types a JSON value can have: - - In case of primitive types (number, boolean, or string), @a first must - be `begin()` and @a last must be `end()`. In this case, the value is - copied. Otherwise, invalid_iterator.204 is thrown. - - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector`. - - In case of a null type, invalid_iterator.206 is thrown. - - @tparam InputIT an input iterator type (@ref iterator or @ref - const_iterator) - - @param[in] first begin of the range to copy from (included) - @param[in] last end of the range to copy from (excluded) - - @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion.** - - @pre Range `[first, last)` is valid. Usually, this precondition cannot be - checked efficiently. Only certain edge cases are detected; see the - description of the exceptions below. - - @throw invalid_iterator.201 if iterators @a first and @a last are not - compatible (i.e., do not belong to the same JSON value). In this case, - the range `[first, last)` is undefined. - @throw invalid_iterator.204 if iterators @a first and @a last belong to a - primitive type (number, boolean, or string), but @a first does not point - to the first element any more. In this case, the range `[first, last)` is - undefined. See example code below. - @throw invalid_iterator.206 if iterators @a first and @a last belong to a - null value. In this case, the range `[first, last)` is undefined. - - @complexity Linear in distance between @a first and @a last. - - @liveexample{The example below shows several ways to create JSON values by - specifying a subrange with iterators.,basic_json__InputIt_InputIt} - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type = 0> - basic_json(InputIT first, InputIT last) + case value_t::string: { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } - // make sure iterator fits the current value - if (first.m_object != last.m_object) - { - JSON_THROW(invalid_iterator::create(201, "iterators are not compatible")); - } + default: + { + // all other types need no specific destructor + break; + } + } + } - // copy type from first iterator - m_type = first.m_object->m_type; + /// @} - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } - break; - } +public: + /////////////////////// + // object inspection // + /////////////////////// - default: - { - break; - } - } + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ - switch (m_type) - { - case value_t::number_integer: - { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } + /*! + @brief serialization - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + parameter. - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation of @a indent is + greate than `0`. The default is ` ` (space). - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } + @return string containing the serialization of the JSON value - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } + @complexity Linear. - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } + @liveexample{The following example shows the effect of different @a indent + parameters to the result of the serialization.,dump} - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } + @see https://docs.python.org/2/library/json.html#json.dump - default: - { - JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + - first.m_object->type_name())); - } - } + @since version 1.0.0; indentaction character added in version 3.0.0 + */ + string_t dump(const int indent = -1, const char indent_char = ' ') const + { + string_t result; + serializer s(output_adapter::create(result), indent_char); - assert_invariant(); + if (indent >= 0) + { + s.dump(*this, true, static_cast(indent)); + } + else + { + s.dump(*this, false, 0); } + return result; + } - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// + /*! + @brief return the type of the JSON value (explicit) - /*! - @brief copy constructor + Return the type of the JSON value as a value from the @ref value_t + enumeration. - Creates a copy of a given JSON value. + @return the type of the JSON value - @param[in] other the JSON value to copy + @complexity Constant. - @complexity Linear in the size of @a other. + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - As postcondition, it holds: `other == basic_json(other)`. + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} - @liveexample{The following code shows an example for the copy - constructor.,basic_json__basic_json} + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } - @since version 1.0.0 - */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); + /*! + @brief return whether type is primitive - switch (m_type) - { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } + This function returns true iff the JSON type is primitive (string, number, + boolean, or null). - case value_t::array: - { - m_value = *other.m_value.array; - break; - } + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. - case value_t::string: - { - m_value = *other.m_value.string; - break; - } + @complexity Constant. - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } + @sa @ref is_structured() -- returns whether JSON value is structured + @sa @ref is_null() -- returns whether JSON value is `null` + @sa @ref is_string() -- returns whether JSON value is a string + @sa @ref is_boolean() -- returns whether JSON value is a boolean + @sa @ref is_number() -- returns whether JSON value is a number - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } - default: - { - break; - } - } + /*! + @brief return whether type is structured - assert_invariant(); - } + This function returns true iff the JSON type is structured (array or + object). - /*! - @brief move constructor + @return `true` if type is structured (array or object), `false` otherwise. - Move constructor. Constructs a JSON value with the contents of the given - value @a other using move semantics. It "steals" the resources from @a - other and leaves it as JSON null value. + @complexity Constant. - @param[in,out] other value to move to this object + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @post @a other is a JSON null value + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} - @complexity Constant. + @sa @ref is_primitive() -- returns whether value is primitive + @sa @ref is_array() -- returns whether value is an array + @sa @ref is_object() -- returns whether value is an object - @liveexample{The code below shows the move constructor explicitly called - via std::move.,basic_json__moveconstructor} + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } - @since version 1.0.0 - */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); + /*! + @brief return whether value is null - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; + This function returns true iff the JSON value is null. - assert_invariant(); - } + @return `true` if type is null, `false` otherwise. - /*! - @brief copy assignment + @complexity Constant. - Copy assignment operator. Copies a JSON value via the "copy and swap" - strategy: It is expressed in terms of the copy constructor, destructor, - and the swap() member function. + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @param[in] other value to copy from + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} - @complexity Linear. + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. + /*! + @brief return whether value is a boolean - @liveexample{The code below shows and example for the copy assignment. It - creates a copy of value `a` which is then swapped with `b`. Finally\, the - copy of `a` (which is the null value after the swap) is - destroyed.,basic_json__copyassignment} + This function returns true iff the JSON value is a boolean. - @since version 1.0.0 - */ - reference& operator=(basic_json other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); + @return `true` if type is boolean, `false` otherwise. - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); + @complexity Constant. - assert_invariant(); - return *this; - } + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - /*! - @brief destructor + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} - Destroys the JSON value and frees all allocated memory. + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } - @complexity Linear. + /*! + @brief return whether value is a number - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is linear. - - All stored elements are destroyed and all memory is freed. + This function returns true iff the JSON value is a number. This includes + both integer and floating-point values. - @since version 1.0.0 - */ - ~basic_json() - { - assert_invariant(); + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. - switch (m_type) - { - case value_t::object: - { - AllocatorType alloc; - alloc.destroy(m_value.object); - alloc.deallocate(m_value.object, 1); - break; - } + @complexity Constant. - case value_t::array: - { - AllocatorType alloc; - alloc.destroy(m_value.array); - alloc.deallocate(m_value.array, 1); - break; - } + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - case value_t::string: - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - break; - } + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} - default: - { - // all other types need no specific destructor - break; - } - } - } + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number - /// @} + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } - public: - /////////////////////// - // object inspection // - /////////////////////// + /*! + @brief return whether value is an integer number - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ + This function returns true iff the JSON value is an integer or unsigned + integer number. This excludes floating-point values. - /*! - @brief serialization + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. - Serialization function for JSON values. The function tries to mimic - Python's `json.dumps()` function, and currently supports its @a indent - parameter. + @complexity Constant. - @param[in] indent If indent is nonnegative, then array elements and object - members will be pretty-printed with that indent level. An indent level of - `0` will only insert newlines. `-1` (the default) selects the most compact - representation. - @param[in] indent_char The character to use for indentation of @a indent is - greate than `0`. The default is ` ` (space). + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @return string containing the serialization of the JSON value + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} - @complexity Linear. + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa @ref is_number_float() -- check if value is a floating-point number - @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serialization.,dump} + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } - @see https://docs.python.org/2/library/json.html#json.dump + /*! + @brief return whether value is an unsigned integer number - @since version 1.0.0; indentaction character added in version 3.0.0 - */ - string_t dump(const int indent = -1, const char indent_char = ' ') const - { - string_t result; - serializer s(output_adapter::create(result), indent_char); + This function returns true iff the JSON value is an unsigned integer + number. This excludes floating-point and (signed) integer values. - if (indent >= 0) - { - s.dump(*this, true, static_cast(indent)); - } - else - { - s.dump(*this, false, 0); - } + @return `true` if type is an unsigned integer number, `false` otherwise. - return result; - } + @complexity Constant. - /*! - @brief return the type of the JSON value (explicit) + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - Return the type of the JSON value as a value from the @ref value_t - enumeration. + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} - @return the type of the JSON value + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number - @complexity Constant. + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + /*! + @brief return whether value is a floating-point number - @liveexample{The following code exemplifies `type()` for all JSON - types.,type} + This function returns true iff the JSON value is a floating-point number. + This excludes integer and unsigned integer values. - @since version 1.0.0 - */ - constexpr value_t type() const noexcept - { - return m_type; - } + @return `true` if type is a floating-point number, `false` otherwise. - /*! - @brief return whether type is primitive + @complexity Constant. - This function returns true iff the JSON type is primitive (string, number, - boolean, or null). + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @return `true` if type is primitive (string, number, boolean, or null), - `false` otherwise. + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} - @complexity Constant. + @sa @ref is_number() -- check if value is number + @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer + number - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } - @liveexample{The following code exemplifies `is_primitive()` for all JSON - types.,is_primitive} + /*! + @brief return whether value is an object - @sa @ref is_structured() -- returns whether JSON value is structured - @sa @ref is_null() -- returns whether JSON value is `null` - @sa @ref is_string() -- returns whether JSON value is a string - @sa @ref is_boolean() -- returns whether JSON value is a boolean - @sa @ref is_number() -- returns whether JSON value is a number + This function returns true iff the JSON value is an object. - @since version 1.0.0 - */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } + @return `true` if type is object, `false` otherwise. - /*! - @brief return whether type is structured + @complexity Constant. - This function returns true iff the JSON type is structured (array or - object). + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @return `true` if type is structured (array or object), `false` otherwise. + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} - @complexity Constant. + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + /*! + @brief return whether value is an array - @liveexample{The following code exemplifies `is_structured()` for all JSON - types.,is_structured} + This function returns true iff the JSON value is an array. - @sa @ref is_primitive() -- returns whether value is primitive - @sa @ref is_array() -- returns whether value is an array - @sa @ref is_object() -- returns whether value is an object + @return `true` if type is array, `false` otherwise. - @since version 1.0.0 - */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } + @complexity Constant. - /*! - @brief return whether value is null + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - This function returns true iff the JSON value is null. + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} - @return `true` if type is null, `false` otherwise. + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } - @complexity Constant. + /*! + @brief return whether value is a string - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + This function returns true iff the JSON value is a string. - @liveexample{The following code exemplifies `is_null()` for all JSON - types.,is_null} + @return `true` if type is string, `false` otherwise. - @since version 1.0.0 - */ - constexpr bool is_null() const noexcept - { - return m_type == value_t::null; - } + @complexity Constant. - /*! - @brief return whether value is a boolean + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - This function returns true iff the JSON value is a boolean. + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} - @return `true` if type is boolean, `false` otherwise. + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } - @complexity Constant. + /*! + @brief return whether value is discarded - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + This function returns true iff the JSON value was discarded during parsing + with a callback function (see @ref parser_callback_t). - @liveexample{The following code exemplifies `is_boolean()` for all JSON - types.,is_boolean} + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. - @since version 1.0.0 - */ - constexpr bool is_boolean() const noexcept - { - return m_type == value_t::boolean; - } + @return `true` if type is discarded, `false` otherwise. - /*! - @brief return whether value is a number + @complexity Constant. - This function returns true iff the JSON value is a number. This includes - both integer and floating-point values. + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. - @return `true` if type is number (regardless whether integer, unsigned - integer or floating-type), `false` otherwise. + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} - @complexity Constant. + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + /*! + @brief return the type of the JSON value (implicit) - @liveexample{The following code exemplifies `is_number()` for all JSON - types.,is_number} + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number + @return the type of the JSON value - @since version 1.0.0 - */ - constexpr bool is_number() const noexcept + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + +private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t * /*unused*/) const + { + if (is_boolean()) { - return is_number_integer() or is_number_float(); - } + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + type_name())); + } + + /// get a pointer to the value (object) + object_t * get_impl_ptr(object_t * /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t * get_impl_ptr(const object_t * /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } - /*! - @brief return whether value is an integer number + /// get a pointer to the value (array) + array_t * get_impl_ptr(array_t * /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t * get_impl_ptr(const array_t * /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t * get_impl_ptr(string_t * /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } - This function returns true iff the JSON value is an integer or unsigned - integer number. This excludes floating-point values. + /// get a pointer to the value (string) + constexpr const string_t * get_impl_ptr(const string_t * /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t * get_impl_ptr(boolean_t * /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } - @return `true` if type is an integer or unsigned integer number, `false` - otherwise. + /// get a pointer to the value (boolean) + constexpr const boolean_t * get_impl_ptr(const boolean_t * /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t * get_impl_ptr(number_integer_t * /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t * get_impl_ptr(const number_integer_t * /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t * get_impl_ptr(number_unsigned_t * /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t * get_impl_ptr(const number_unsigned_t * /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t * get_impl_ptr(number_float_t * /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t * get_impl_ptr(const number_float_t * /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType & obj) + { + // helper type + using PointerType = typename std::add_pointer::type; + + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr(); + + if (ptr != nullptr) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name())); + } + +public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template < + typename BasicJsonType, + detail::enable_if_t::type, basic_json_t>::value, int> = 0> + basic_json get() const + { + return *this; + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < + typename ValueTypeCV, + typename ValueType = detail::uncvref_t, + detail::enable_if_t< + not std::is_same::value and detail::has_from_json::value and + not detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept( + noexcept(JSONSerializer::from_json(std::declval(), std::declval()))) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert( + not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + static_assert( + std::is_default_constructible::value, "types must be DefaultConstructible when used with get()"); - @complexity Constant. + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) + and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < + typename ValueTypeCV, + typename ValueType = detail::uncvref_t, + detail::enable_if_t< + not std::is_same::value and + detail::has_non_default_from_json::value, + int> = 0> + ValueType get() const noexcept(noexcept(JSONSerializer::from_json(std::declval()))) + { + static_assert( + not std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return JSONSerializer::from_json(*this); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template ::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template ::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template ::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const< + typename std::remove_pointer::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value or std::is_same::value or + std::is_same::value or std::is_same::value or + std::is_same::value or std::is_same::value or + std::is_same::value, + "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template < + typename PointerType, + typename std::enable_if< + std::is_pointer::value and std::is_const::type>::value, + int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const< + typename std::remove_pointer::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value or std::is_same::value or + std::is_same::value or std::is_same::value or + std::is_same::value or std::is_same::value or + std::is_same::value, + "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template ::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template < + typename ReferenceType, + typename std::enable_if< + std::is_reference::value and + std::is_const::type>::value, + int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < + typename ValueType, + typename std::enable_if< + not std::is_pointer::value and not std::is_same::value +#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 + and not std::is_same>::value +#endif +#if defined(_MSC_VER) && _MSC_VER > 1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1 // fix for issue #464 + and not std::is_same::value +#endif + , + int>::type = 0> + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + /// @} - @liveexample{The following code exemplifies `is_number_integer()` for all - JSON types.,is_number_integer} + //////////////////// + // element access // + //////////////////// - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number - @sa @ref is_number_float() -- check if value is a floating-point number + /// @name element access + /// Access to the JSON value. + /// @{ - @since version 1.0.0 - */ - constexpr bool is_number_integer() const noexcept - { - return m_type == value_t::number_integer or m_type == value_t::number_unsigned; - } + /*! + @brief access specified array element with bounds checking - /*! - @brief return whether value is an unsigned integer number + Returns a reference to the element at specified location @a idx, with + bounds checking. - This function returns true iff the JSON value is an unsigned integer - number. This excludes floating-point and (signed) integer values. + @param[in] idx index of the element to access - @return `true` if type is an unsigned integer number, `false` otherwise. + @return reference to the element at index @a idx - @complexity Constant. + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @liveexample{The following code exemplifies `is_number_unsigned()` for all - JSON types.,is_number_unsigned} + @complexity Constant. - @sa @ref is_number() -- check if value is a number - @sa @ref is_number_integer() -- check if value is an integer or unsigned - integer number - @sa @ref is_number_float() -- check if value is a floating-point number + @since version 1.0.0 - @since version 2.0.0 - */ - constexpr bool is_number_unsigned() const noexcept + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (is_array()) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH(std::out_of_range &) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else { - return m_type == value_t::number_unsigned; + JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); } + } - /*! - @brief return whether value is a floating-point number + /*! + @brief access specified array element with bounds checking - This function returns true iff the JSON value is a floating-point number. - This excludes integer and unsigned integer values. + Returns a const reference to the element at specified location @a idx, + with bounds checking. - @return `true` if type is a floating-point number, `false` otherwise. + @param[in] idx index of the element to access - @complexity Constant. + @return const reference to the element at index @a idx - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. - @liveexample{The following code exemplifies `is_number_float()` for all - JSON types.,is_number_float} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @sa @ref is_number() -- check if value is number - @sa @ref is_number_integer() -- check if value is an integer number - @sa @ref is_number_unsigned() -- check if value is an unsigned integer - number + @complexity Constant. - @since version 1.0.0 - */ - constexpr bool is_number_float() const noexcept + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (is_array()) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH(std::out_of_range &) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } + } + else { - return m_type == value_t::number_float; + JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); } + } - /*! - @brief return whether value is an object + /*! + @brief access specified object element with bounds checking - This function returns true iff the JSON value is an object. + Returns a reference to the element at with specified key @a key, with + bounds checking. - @return `true` if type is object, `false` otherwise. + @param[in] key key of the element to access - @complexity Constant. + @return reference to the element at key @a key - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. - @liveexample{The following code exemplifies `is_object()` for all JSON - types.,is_object} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @since version 1.0.0 - */ - constexpr bool is_object() const noexcept + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type & key) + { + // at only works for objects + if (is_object()) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH(std::out_of_range &) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else { - return m_type == value_t::object; + JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); } + } - /*! - @brief return whether value is an array + /*! + @brief access specified object element with bounds checking - This function returns true iff the JSON value is an array. + Returns a const reference to the element at with specified key @a key, + with bounds checking. - @return `true` if type is array, `false` otherwise. + @param[in] key key of the element to access - @complexity Constant. + @return const reference to the element at key @a key - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. - @liveexample{The following code exemplifies `is_array()` for all JSON - types.,is_array} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @since version 1.0.0 - */ - constexpr bool is_array() const noexcept + @complexity Logarithmic in the size of the container. + + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type & key) const + { + // at only works for objects + if (is_object()) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH(std::out_of_range &) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); + } + } + else { - return m_type == value_t::array; + JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); } + } - /*! - @brief return whether value is a string + /*! + @brief access specified array element - This function returns true iff the JSON value is a string. + Returns a reference to the element at specified location @a idx. - @return `true` if type is string, `false` otherwise. + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. - @complexity Constant. + @param[in] idx index of the element to access - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @return reference to the element at index @a idx - @liveexample{The following code exemplifies `is_string()` for all JSON - types.,is_string} + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. - @since version 1.0.0 - */ - constexpr bool is_string() const noexcept + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) { - return m_type == value_t::string; + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); } - /*! - @brief return whether value is discarded + // operator[] only works for arrays + if (is_array()) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), idx - m_value.array->size() + 1, basic_json()); + } + + return m_value.array->operator[](idx); + } - This function returns true iff the JSON value was discarded during parsing - with a callback function (see @ref parser_callback_t). + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - @note This function will always be `false` for JSON values after parsing. - That is, discarded values can only occur during parsing, but will be - removed when inside a structured value or replaced by null in other cases. + /*! + @brief access specified array element - @return `true` if type is discarded, `false` otherwise. + Returns a const reference to the element at specified location @a idx. - @complexity Constant. + @param[in] idx index of the element to access - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @return const reference to the element at index @a idx - @liveexample{The following code exemplifies `is_discarded()` for all JSON - types.,is_discarded} + @throw type_error.305 if the JSON value is not an array; in that cases, + using the [] operator with an index makes no sense. - @since version 1.0.0 - */ - constexpr bool is_discarded() const noexcept + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (is_array()) { - return m_type == value_t::discarded; + return m_value.array->operator[](idx); } - /*! - @brief return the type of the JSON value (implicit) - - Implicitly return the type of the JSON value as a value from the @ref - value_t enumeration. + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - @return the type of the JSON value + /*! + @brief access specified object element - @complexity Constant. + Returns a reference to the element at with specified key @a key. - @exceptionsafety No-throw guarantee: this member function never throws - exceptions. + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. - @liveexample{The following code exemplifies the @ref value_t operator for - all JSON types.,operator__value_t} + @param[in] key key of the element to access - @since version 1.0.0 - */ - constexpr operator value_t() const noexcept - { - return m_type; - } + @return reference to the element at key @a key - /// @} + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. - private: - ////////////////// - // value access // - ////////////////// + @complexity Logarithmic in the size of the container. - /// get a boolean (explicit) - boolean_t get_impl(boolean_t* /*unused*/) const - { - if (is_boolean()) - { - return m_value.boolean; - } + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} - JSON_THROW(type_error::create(302, "type must be boolean, but is " + type_name())); - } + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t* /*unused*/) noexcept + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type & key) + { + // implicitly convert null value to an empty object + if (is_null()) { - return is_object() ? m_value.object : nullptr; + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); } - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + // operator[] only works for objects + if (is_object()) { - return is_object() ? m_value.object : nullptr; + return m_value.object->operator[](key); } - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t* /*unused*/) noexcept - { - return is_array() ? m_value.array : nullptr; - } + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept - { - return is_array() ? m_value.array : nullptr; - } + /*! + @brief read-only access specified object element - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t* /*unused*/) noexcept - { - return is_string() ? m_value.string : nullptr; - } + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept - { - return is_string() ? m_value.string : nullptr; - } + @warning If the element with key @a key does not exist, the behavior is + undefined. - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } + @param[in] key key of the element to access - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } + @return const reference to the element at key @a key - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } + @complexity Logarithmic in the size of the container. - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type & key) const + { + // const operator[] only works for objects + if (is_object()) { - return is_number_float() ? &m_value.number_float : nullptr; + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; } - /*! - @brief helper function to implement get_ref() + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - This funcion helps to implement get_ref() without code duplication for - const and non-const overloads + /*! + @brief access specified object element - @tparam ThisType will be deduced as `basic_json` or `const basic_json` + Returns a reference to the element at with specified key @a key. - @throw type_error.303 if ReferenceType does not match underlying value - type of the current JSON - */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // helper type - using PointerType = typename std::add_pointer::type; + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr(); + @param[in] key key of the element to access - if (ptr != nullptr) - { - return *ptr; - } + @return reference to the element at key @a key - JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + obj.type_name())); - } + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. - public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ + @complexity Logarithmic in the size of the container. - /*! - @brief get special-case overload + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} - This overloads avoids a lot of template boilerplate, it can be seen as the - identity method + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - @tparam BasicJsonType == @ref basic_json + @since version 1.0.0 + */ + template + reference operator[](T * (&key)[n]) + { + return operator[](static_cast(key)); + } - @return a copy of *this + /*! + @brief read-only access specified object element - @complexity Constant. + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. - @since version 2.1.0 - */ - template < - typename BasicJsonType, - detail::enable_if_t::type, - basic_json_t>::value, - int> = 0 > - basic_json get() const - { - return *this; - } + @warning If the element with key @a key does not exist, the behavior is + undefined. - /*! - @brief get a value (explicit) + @note This function is required for compatibility reasons with Clang. - Explicit type conversion between the JSON value and a compatible value - which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. + @param[in] key key of the element to access - The function is equivalent to executing - @code {.cpp} - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - @endcode + @return const reference to the element at key @a key - This overloads is chosen if: - - @a ValueType is not @ref basic_json, - - @ref json_serializer has a `from_json()` method of the form - `void from_json(const basic_json&, ValueType&)`, and - - @ref json_serializer does not have a `from_json()` method of - the form `ValueType from_json(const basic_json&)` + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type + @complexity Logarithmic in the size of the container. - @return copy of the JSON value, converted to @a ValueType + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} - @throw what @ref json_serializer `from_json()` method throws + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,get__ValueType_const} + @since version 1.0.0 + */ + template + const_reference operator[](T * (&key)[n]) const + { + return operator[](static_cast(key)); + } - @since version 2.1.0 - */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t, - detail::enable_if_t < - not std::is_same::value and - detail::has_from_json::value and - not detail::has_non_default_from_json::value, - int > = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval(), std::declval()))) - { - // we cannot static_assert on ValueTypeCV being non-const, because - // there is support for get(), which is why we - // still need the uncvref - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - static_assert(std::is_default_constructible::value, - "types must be DefaultConstructible when used with get()"); - - ValueType ret; - JSONSerializer::from_json(*this, ret); - return ret; - } + /*! + @brief access specified object element - /*! - @brief get a value (explicit); special case + Returns a reference to the element at with specified key @a key. - Explicit type conversion between the JSON value and a compatible value - which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) - and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). - The value is converted by calling the @ref json_serializer - `from_json()` method. + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. - The function is equivalent to executing - @code {.cpp} - return JSONSerializer::from_json(*this); - @endcode + @param[in] key key of the element to access - This overloads is chosen if: - - @a ValueType is not @ref basic_json and - - @ref json_serializer has a `from_json()` method of the form - `ValueType from_json(const basic_json&)` + @return reference to the element at key @a key - @note If @ref json_serializer has both overloads of - `from_json()`, this one is chosen. + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. - @tparam ValueTypeCV the provided value type - @tparam ValueType the returned value type + @complexity Logarithmic in the size of the container. - @return copy of the JSON value, converted to @a ValueType + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} - @throw what @ref json_serializer `from_json()` method throws + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - @since version 2.1.0 - */ - template < - typename ValueTypeCV, - typename ValueType = detail::uncvref_t, - detail::enable_if_t::value and - detail::has_non_default_from_json::value, int> = 0 > - ValueType get() const noexcept(noexcept( - JSONSerializer::from_json(std::declval()))) + @since version 1.1.0 + */ + template + reference operator[](T * key) + { + // implicitly convert null to object + if (is_null()) { - static_assert(not std::is_reference::value, - "get() cannot be used with reference types, you might want to use get_ref()"); - return JSONSerializer::from_json(*this); + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); } - /*! - @brief get a pointer value (explicit) + // at only works for objects + if (is_object()) + { + return m_value.object->operator[](key); + } - Explicit pointer access to the internally stored JSON value. No copies are - made. + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - @warning The pointer becomes invalid if the underlying JSON object - changes. + /*! + @brief read-only access specified object element - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + @warning If the element with key @a key does not exist, the behavior is + undefined. - @complexity Constant. + @param[in] key key of the element to access - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} + @return const reference to the element at key @a key - @sa @ref get_ptr() for explicit pointer-member access + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } + @throw type_error.305 if the JSON value is not an object; in that cases, + using the [] operator with a key makes no sense. - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } + @complexity Logarithmic in the size of the container. - /*! - @brief get a pointer value (implicit) + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} - Implicit pointer access to the internally stored JSON value. No copies are - made. + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value - @warning Writing data to the pointee of the result yields an undefined - state. + @since version 1.1.0 + */ + template + const_reference operator[](T * key) const + { + // at only works for objects + if (is_object()) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. Enforced by a static - assertion. + JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + } - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + /*! + @brief access specified object element with default value - @complexity Constant. + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get_ptr} + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode - @since version 1.0.0 - */ - template::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. - /*! - @brief get a pointer value (implicit) - @copydoc get_ptr() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. - /*! - @brief get a reference value (implicit) + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found - Implicit reference access to the internally stored JSON value. No copies - are made. + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. - @warning Writing data to the referee of the result yields an undefined - state. + @return copy of the element at key @a key or @a default_value if @a key + is not found - @tparam ReferenceType reference type; must be a reference to @ref array_t, - @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or - @ref number_float_t. Enforced by static assertion. + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. - @return reference to the internally stored JSON value if the requested - reference type @a ReferenceType fits to the JSON value; throws - type_error.303 otherwise + @complexity Logarithmic in the size of the container. - @throw type_error.303 in case passed type @a ReferenceType is incompatible - with the stored JSON value; see example below + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} - @complexity Constant. + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref operator[](const typename object_t::key_type&) for unchecked + access by reference - @liveexample{The example shows several calls to `get_ref()`.,get_ref} + @since version 1.0.0 + */ + template < + class ValueType, + typename std::enable_if::value, int>::type = 0> + ValueType value(const typename object_t::key_type & key, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } - @since version 1.1.0 - */ - template::value, int>::type = 0> - ReferenceType get_ref() + return default_value; + } + else { - // delegate call to get_ref_impl - return get_ref_impl(*this); + JSON_THROW(type_error::create(306, "cannot use value() with " + type_name())); } + } - /*! - @brief get a reference value (implicit) - @copydoc get_ref() - */ - template::value and - std::is_const::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const + */ + string_t value(const typename object_t::key_type & key, const char * default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.306 if the JSON value is not an objec; in that cases, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template < + class ValueType, + typename std::enable_if::value, int>::type = 0> + ValueType value(const json_pointer & ptr, ValueType default_value) const + { + // at only works for objects + if (is_object()) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this); + } + JSON_CATCH(out_of_range &) + { + return default_value; + } } - /*! - @brief get a value (implicit) + JSON_THROW(type_error::create(306, "cannot use value() with " + type_name())); + } - Implicit type conversion between the JSON value and a compatible value. - The call is realized by calling @ref get() const. + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + string_t value(const json_pointer & ptr, const char * default_value) const + { + return value(ptr, string_t(default_value)); + } - @tparam ValueType non-pointer type compatible to the JSON value, for - instance `int` for JSON integer numbers, `bool` for JSON booleans, or - `std::vector` types for JSON arrays. The character type of @ref string_t - as well as an initializer list of this type is excluded to avoid - ambiguities as these types implicitly convert to `std::string`. + /*! + @brief access the first element - @return copy of the JSON value, converted to type @a ValueType + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. - @throw type_error.302 in case passed type @a ValueType is incompatible - to the JSON value type (e.g., the JSON value is of type boolean, but a - string is requested); see example below + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, or boolean values, a + reference to the value is returned. - @complexity Linear in the size of the JSON value. + @complexity Constant. - @liveexample{The example below shows several conversions from JSON values - to other types. There a few things to note: (1) Floating-point numbers can - be converted to integers\, (2) A JSON array can be converted to a standard - `std::vector`\, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`.,operator__ValueType} + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. - @since version 1.0.0 - */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer::value and - not std::is_same::value -#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 - and not std::is_same>::value -#endif -#if defined(_MSC_VER) && _MSC_VER >1900 && defined(_HAS_CXX17) && _HAS_CXX17 == 1 // fix for issue #464 - and not std::is_same::value -#endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } + @throw invalid_iterator.214 when called on `null` value - /// @} + @liveexample{The following code shows an example for `front()`.,front} + @sa @ref back() -- access the last element - //////////////////// - // element access // - //////////////////// + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } - /// @name element access - /// Access to the JSON value. - /// @{ + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } - /*! - @brief access specified array element with bounds checking + /*! + @brief access the last element - Returns a reference to the element at specified location @a idx, with - bounds checking. + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode - @param[in] idx index of the element to access + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, or boolean values, a + reference to the value is returned. - @return reference to the element at index @a idx + @complexity Constant. - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + @throw invalid_iterator.214 when called on a `null` value. See example + below. - @complexity Constant. + @liveexample{The following code shows an example for `back()`.,back} - @since version 1.0.0 + @sa @ref front() -- access the first element - @liveexample{The example below shows how array elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__size_type} - */ - reference at(size_type idx) - { - // at only works for arrays - if (is_array()) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); - } - } + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } - /*! - @brief access specified array element with bounds checking + /*! + @brief remove element given an iterator - Returns a const reference to the element at specified location @a idx, - with bounds checking. + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. - @param[in] idx index of the element to access + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. - @return const reference to the element at index @a idx + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. - @throw type_error.304 if the JSON value is not an array; in this case, - calling `at` with an index makes no sense. See example below. - @throw out_of_range.401 if the index @a idx is out of range of the array; - that is, `idx >= size()`. See example below. + @tparam IteratorType an @ref iterator or @ref const_iterator - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. - @complexity Constant. + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` - @since version 1.0.0 + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings: linear in the length of the string + - other types: constant - @liveexample{The example below shows how array elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__size_type_const} - */ - const_reference at(size_type idx) const + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < + class IteratorType, + typename std::enable_if< + std::is_same::value or + std::is_same::value, + int>::type = 0> + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (this != pos.m_object) { - // at only works for arrays - if (is_array()) - { - JSON_TRY - { - return m_value.array->at(idx); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); - } + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } - /*! - @brief access specified object element with bounds checking + IteratorType result = end(); - Returns a reference to the element at with specified key @a key, with - bounds checking. + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not pos.m_it.primitive_iterator.is_begin()) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range")); + } - @param[in] key key of the element to access + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } - @return reference to the element at key @a key + m_type = value_t::null; + assert_invariant(); + break; + } - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } - @complexity Logarithmic in the size of the container. + default: + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); + } + } - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value + return result; + } - @since version 1.0.0 + /*! + @brief remove elements given an iterator range - @liveexample{The example below shows how object elements can be read and - written using `at()`. It also demonstrates the different exceptions that - can be thrown.,at__object_t_key_type} - */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (is_object()) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); - } - } + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. - /*! - @brief access specified object element with bounds checking + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. - Returns a const reference to the element at with specified key @a key, - with bounds checking. + @tparam IteratorType an @ref iterator or @ref const_iterator - @param[in] key key of the element to access + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. - @return const reference to the element at key @a key + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` - @throw type_error.304 if the JSON value is not an object; in this case, - calling `at` with a key makes no sense. See example below. - @throw out_of_range.403 if the key @a key is is not stored in the object; - that is, `find(key) == end()`. See example below. + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings: linear in the length of the string + - other types: constant - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} - @complexity Logarithmic in the size of the container. + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa @ref erase(const size_type) -- removes the element from an array at + the given index - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference - @sa @ref value() for access by value with a default value + @since version 1.0.0 + */ + template < + class IteratorType, + typename std::enable_if< + std::is_same::value or + std::is_same::value, + int>::type = 0> + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); + } - @since version 1.0.0 + IteratorType result = end(); - @liveexample{The example below shows how object elements can be read using - `at()`. It also demonstrates the different exceptions that can be thrown., - at__object_t_key_type_const} - */ - const_reference at(const typename object_t::key_type& key) const + switch (m_type) { - // at only works for objects - if (is_object()) - { - JSON_TRY - { - return m_value.object->at(key); - } - JSON_CATCH (std::out_of_range&) - { - // create better exception explanation - JSON_THROW(out_of_range::create(403, "key '" + key + "' not found")); - } - } - else - { - JSON_THROW(type_error::create(304, "cannot use at() with " + type_name())); - } + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range")); + } + + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; } - /*! - @brief access specified array element + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } - Returns a reference to the element at specified location @a idx. + default: + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); + } + } - @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), - then the array is silently filled up with `null` values to make `idx` a - valid reference to the last stored element. + return result; + } - @param[in] idx index of the element to access + /*! + @brief remove element from a JSON object given a key - @return reference to the element at index @a idx + Removes elements from a JSON object with the key value @a key. - @throw type_error.305 if the JSON value is not an array or null; in that - cases, using the [] operator with an index makes no sense. + @param[in] key value of the elements to remove - @complexity Constant if @a idx is in the range of the array. Otherwise - linear in `idx - size()`. + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). - @liveexample{The example below shows how array elements can be read and - written using `[]` operator. Note the addition of `null` - values.,operatorarray__size_type} + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. - @since version 1.0.0 - */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` - // operator[] only works for arrays - if (is_array()) - { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) - { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); - } + @complexity `log(size()) + count(key)` - return m_value.array->operator[](idx); - } + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const size_type) -- removes the element from an array at + the given index - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type & key) + { + // this erase only works for objects + if (is_object()) + { + return m_value.object->erase(key); } - /*! - @brief access specified array element + JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); + } - Returns a const reference to the element at specified location @a idx. + /*! + @brief remove element from a JSON array given an index - @param[in] idx index of the element to access + Removes element from a JSON array at the index @a idx. - @return const reference to the element at index @a idx + @param[in] idx index of the element to remove - @throw type_error.305 if the JSON value is not an array; in that cases, - using the [] operator with an index makes no sense. + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` - @complexity Constant. + @complexity Linear in distance between @a idx and the end of the container. - @liveexample{The example below shows how array elements can be read using - the `[]` operator.,operatorarray__size_type_const} + @liveexample{The example shows the effect of `erase()`.,erase__size_type} - @since version 1.0.0 - */ - const_reference operator[](size_type idx) const + @sa @ref erase(IteratorType) -- removes the element at a given position + @sa @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (is_array()) { - // const operator[] only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } + if (idx >= size()) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); + } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + m_value.array->erase(m_value.array->begin() + static_cast(idx)); } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); + } + } - /*! - @brief access specified object element + /// @} - Returns a reference to the element at with specified key @a key. + //////////// + // lookup // + //////////// - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. + /// @name lookup + /// @{ - @param[in] key key of the element to access + /*! + @brief find an element in a JSON object - @return reference to the element at key @a key + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. + @note This method always returns @ref end() when executed on a JSON type + that is not an object. - @complexity Logarithmic in the size of the container. + @param[in] key key value of the element to search for - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + @complexity Logarithmic in the size of the JSON object. - @since version 1.0.0 - */ - reference operator[](const typename object_t::key_type& key) + @liveexample{The example shows how `find()` is used.,find__key_type} + + @since version 1.0.0 + */ + iterator find(typename object_t::key_type key) + { + auto result = end(); + + if (is_object()) { - // implicitly convert null value to an empty object - if (is_null()) - { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } + result.m_it.object_iterator = m_value.object->find(key); + } - // operator[] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(typename object_t::key_type) + */ + const_iterator find(typename object_t::key_type key) const + { + auto result = cend(); - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(key); } - /*! - @brief read-only access specified object element + return result; + } - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. + /*! + @brief returns the number of occurrences of a key in a JSON object - @warning If the element with key @a key does not exist, the behavior is - undefined. + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). - @param[in] key key of the element to access + @note This method always returns `0` when executed on a JSON type that is + not an object. - @return const reference to the element at key @a key + @param[in] key key value of the element to count - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. - @throw type_error.305 if the JSON value is not an object; in that cases, - using the [] operator with a key makes no sense. + @complexity Logarithmic in the size of the JSON object. - @complexity Logarithmic in the size of the container. + @liveexample{The example shows how `count()` is used.,count} - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} + @since version 1.0.0 + */ + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(key) : 0; + } - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + /// @} - @since version 1.0.0 - */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } + /////////////// + // iterators // + /////////////// - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); - } + /// @name iterators + /// @{ - /*! - @brief access specified object element + /*! + @brief returns an iterator to the first element - Returns a reference to the element at with specified key @a key. + Returns an iterator to the first element. - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. + @image html range-begin-end.svg "Illustration from cppreference.com" - @param[in] key key of the element to access + @return iterator to the first element - @return reference to the element at key @a key + @complexity Constant. - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. - @complexity Logarithmic in the size of the container. + @liveexample{The following code shows an example for `begin()`.,begin} - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} + @sa @ref cbegin() -- returns a const iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } - @since version 1.0.0 - */ - template - reference operator[](T * (&key)[n]) - { - return operator[](static_cast(key)); - } + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } - /*! - @brief read-only access specified object element + /*! + @brief returns a const iterator to the first element - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. + Returns a const iterator to the first element. - @warning If the element with key @a key does not exist, the behavior is - undefined. + @image html range-begin-end.svg "Illustration from cppreference.com" - @note This function is required for compatibility reasons with Clang. + @return const iterator to the first element - @param[in] key key of the element to access + @complexity Constant. - @return const reference to the element at key @a key + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. - @throw type_error.305 if the JSON value is not an object; in that cases, - using the [] operator with a key makes no sense. + @liveexample{The following code shows an example for `cbegin()`.,cbegin} - @complexity Logarithmic in the size of the container. + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref end() -- returns an iterator to the end + @sa @ref cend() -- returns a const iterator to the end - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + /*! + @brief returns an iterator to one past the last element - @since version 1.0.0 - */ - template - const_reference operator[](T * (&key)[n]) const - { - return operator[](static_cast(key)); - } + Returns an iterator to one past the last element. - /*! - @brief access specified object element + @image html range-begin-end.svg "Illustration from cppreference.com" - Returns a reference to the element at with specified key @a key. + @return iterator one past the last element - @note If @a key is not found in the object, then it is silently added to - the object and filled with a `null` value to make `key` a valid reference. - In case the value was `null` before, it is converted to an object. + @complexity Constant. - @param[in] key key of the element to access + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. - @return reference to the element at key @a key + @liveexample{The following code shows an example for `end()`.,end} - @throw type_error.305 if the JSON value is not an object or null; in that - cases, using the [] operator with a key makes no sense. + @sa @ref cend() -- returns a const iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning - @complexity Logarithmic in the size of the container. + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } - @liveexample{The example below shows how object elements can be read and - written using the `[]` operator.,operatorarray__key_type} + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + /*! + @brief returns a const iterator to one past the last element - @since version 1.1.0 - */ - template - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } + Returns a const iterator to one past the last element. - // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } + @image html range-begin-end.svg "Illustration from cppreference.com" - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); - } + @return const iterator one past the last element - /*! - @brief read-only access specified object element + @complexity Constant. - Returns a const reference to the element at with specified key @a key. No - bounds checking is performed. + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. - @warning If the element with key @a key does not exist, the behavior is - undefined. + @liveexample{The following code shows an example for `cend()`.,cend} - @param[in] key key of the element to access + @sa @ref end() -- returns an iterator to the end + @sa @ref begin() -- returns an iterator to the beginning + @sa @ref cbegin() -- returns a const iterator to the beginning - @return const reference to the element at key @a key + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } - @pre The element with key @a key must exist. **This precondition is - enforced with an assertion.** + /*! + @brief returns an iterator to the reverse-beginning - @throw type_error.305 if the JSON value is not an object; in that cases, - using the [] operator with a key makes no sense. + Returns an iterator to the reverse-beginning; that is, the last element. - @complexity Logarithmic in the size of the container. + @image html range-rbegin-rend.svg "Illustration from cppreference.com" - @liveexample{The example below shows how object elements can be read using - the `[]` operator.,operatorarray__key_type_const} + @complexity Constant. - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref value() for access by value with a default value + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. - @since version 1.1.0 - */ - template - const_reference operator[](T* key) const - { - // at only works for objects - if (is_object()) - { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } + @liveexample{The following code shows an example for `rbegin()`.,rbegin} - JSON_THROW(type_error::create(305, "cannot use operator[] with " + type_name())); - } + @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end - /*! - @brief access specified object element with default value + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } - The function is basically equivalent to executing - @code {.cpp} - try { - return at(key); - } catch(out_of_range) { - return default_value; - } - @endcode + /*! + @brief returns an iterator to the reverse-end - @note Unlike @ref at(const typename object_t::key_type&), this function - does not throw if the given key @a key was not found. + Returns an iterator to the reverse-end; that is, one before the first + element. - @note Unlike @ref operator[](const typename object_t::key_type& key), this - function does not implicitly add an element to the position defined by @a - key. This function is furthermore also applicable to const objects. + @image html range-rbegin-rend.svg "Illustration from cppreference.com" - @param[in] key key of the element to access - @param[in] default_value the value to return if @a key is not found + @complexity Constant. - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa @ref crend() -- returns a const reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @return copy of the element at key @a key or @a default_value if @a key - is not found + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } - @throw type_error.306 if the JSON value is not an objec; in that cases, - using `value()` with a key makes no sense. + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } - @complexity Logarithmic in the size of the container. + /*! + @brief returns a const reverse iterator to the last element - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value} + Returns a const iterator to the reverse-beginning; that is, the last + element. - @sa @ref at(const typename object_t::key_type&) for access by reference - with range checking - @sa @ref operator[](const typename object_t::key_type&) for unchecked - access by reference + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa @ref rend() -- returns a reverse iterator to the end + @sa @ref rbegin() -- returns a reverse iterator to the beginning + @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @since version 1.0.0 - */ - template::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType default_value) const - { - // at only works for objects - if (is_object()) - { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) - { - return *it; - } + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } - return default_value; - } - else - { - JSON_THROW(type_error::create(306, "cannot use value() with " + type_name())); - } - } +private: + // forward declaration + template + class iteration_proxy; - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const - */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } +public: + /*! + @brief wrapper to access iterator member functions in range-based for - /*! - @brief access specified object element via JSON Pointer with default value + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. - Returns either a copy of an object's element at the specified key @a key - or a given default value if no element with key @a key exists. + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} - The function is basically equivalent to executing - @code {.cpp} - try { - return at(ptr); - } catch(out_of_range) { - return default_value; - } - @endcode + @note The name of this function is not yet final and may change in the + future. + */ + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } - @note Unlike @ref at(const json_pointer&), this function does not throw - if the given key @a key was not found. + /*! + @copydoc iterator_wrapper(reference) + */ + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } - @param[in] ptr a JSON pointer to the element to access - @param[in] default_value the value to return if @a ptr found no value + /// @} - @tparam ValueType type compatible to JSON values, for instance `int` for - JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for - JSON arrays. Note the type of the expected value at @a key and the default - value @a default_value must be compatible. + ////////////// + // capacity // + ////////////// - @return copy of the element at key @a key or @a default_value if @a key - is not found + /// @name capacity + /// @{ - @throw type_error.306 if the JSON value is not an objec; in that cases, - using `value()` with a key makes no sense. + /*! + @brief checks whether the container is empty - @complexity Logarithmic in the size of the container. + Checks if a JSON value has no elements. - @liveexample{The example below shows how object elements can be queried - with a default value.,basic_json__value_ptr} + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` - @sa @ref operator[](const json_pointer&) for unchecked access by reference + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. - @since version 2.0.2 - */ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType default_value) const + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) { - // at only works for objects - if (is_object()) - { - // if pointer resolves a value, return it or use default value - JSON_TRY - { - return ptr.get_checked(this); - } - JSON_CATCH (out_of_range&) - { - return default_value; - } - } + case value_t::null: + { + // null values are empty + return true; + } - JSON_THROW(type_error::create(306, "cannot use value() with " + type_name())); + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); } - /*! - @brief overload for a default value of type const char* - @copydoc basic_json::value(const json_pointer&, ValueType) const - */ - string_t value(const json_pointer& ptr, const char* default_value) const + case value_t::object: { - return value(ptr, string_t(default_value)); + // delegate call to object_t::empty() + return m_value.object->empty(); } - /*! - @brief access the first element + default: + { + // all other types are nonempty + return false; + } + } + } - Returns a reference to the first element in the container. For a JSON - container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + /*! + @brief returns the number of elements - @return In case of a structured type (array or object), a reference to the - first element is returned. In case of number, string, or boolean values, a - reference to the value is returned. + Returns the number of elements in a JSON value. - @complexity Constant. + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + object | result of function object_t::size() + array | result of function array_t::size() - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. - @throw invalid_iterator.214 when called on `null` value + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. - @liveexample{The following code shows an example for `front()`.,front} + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. - @sa @ref back() -- access the last element + @liveexample{The following code calls `size()` on the different value + types.,size} - @since version 1.0.0 - */ - reference front() + @sa @ref empty() -- checks whether the container is empty + @sa @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) { - return *begin(); + case value_t::null: + { + // null values are empty + return 0; } - /*! - @copydoc basic_json::front() - */ - const_reference front() const + case value_t::array: { - return *cbegin(); + // delegate call to array_t::size() + return m_value.array->size(); } - /*! - @brief access the last element + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } - Returns a reference to the last element in the container. For a JSON - container `c`, the expression `c.back()` is equivalent to - @code {.cpp} - auto tmp = c.end(); - --tmp; - return *tmp; - @endcode + default: + { + // all other types have size 1 + return 1; + } + } + } - @return In case of a structured type (array or object), a reference to the - last element is returned. In case of number, string, or boolean values, a - reference to the value is returned. + /*! + @brief returns the maximum possible number of elements - @complexity Constant. + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. - @pre The JSON value must not be `null` (would throw `std::out_of_range`) - or an empty array or object (undefined behavior, **guarded by - assertions**). - @post The JSON value remains unchanged. + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` - @throw invalid_iterator.214 when called on a `null` value. See example - below. + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. - @liveexample{The following code shows an example for `back()`.,back} + @requirement This function helps `basic_json` satisfying the + [Container](http://en.cppreference.com/w/cpp/concept/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. - @sa @ref front() -- access the first element + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} - @since version 1.0.0 - */ - reference back() + @sa @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: { - auto tmp = end(); - --tmp; - return *tmp; + // delegate call to array_t::max_size() + return m_value.array->max_size(); } - /*! - @copydoc basic_json::back() - */ - const_reference back() const + case value_t::object: { - auto tmp = cend(); - --tmp; - return *tmp; + // delegate call to object_t::max_size() + return m_value.object->max_size(); } - /*! - @brief remove element given an iterator - - Removes the element specified by iterator @a pos. The iterator @a pos must - be valid and dereferenceable. Thus the `end()` iterator (which is valid, - but is not dereferenceable) cannot be used as a value for @a pos. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] pos iterator to the element to remove - @return Iterator following the last removed element. If the iterator @a - pos refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.202 if called on an iterator which does not belong - to the current JSON value; example: `"iterator does not fit current - value"` - @throw invalid_iterator.205 if called on a primitive type with invalid - iterator (i.e., any iterator which is not `begin()`); example: `"iterator - out of range"` - - @complexity The complexity depends on the type: - - objects: amortized constant - - arrays: linear in distance between @a pos and the end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType} - - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType pos) + default: { - // make sure iterator fits the current value - if (this != pos.m_object) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } + // all other types have max_size() == size() + return size(); + } + } + } - IteratorType result = end(); + /// @} - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not pos.m_it.primitive_iterator.is_begin()) - { - JSON_THROW(invalid_iterator::create(205, "iterator out of range")); - } + /////////////// + // modifiers // + /////////////// - if (is_string()) - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } + /// @name modifiers + /// @{ - m_type = value_t::null; - assert_invariant(); - break; - } + /*! + @brief clears the contents - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called: - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; - } + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` - default: - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); - } - } + @complexity Linear in the size of the JSON value. - return result; - } + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} - /*! - @brief remove elements given an iterator range - - Removes the element specified by the range `[first; last)`. The iterator - @a first does not need to be dereferenceable if `first == last`: erasing - an empty range is a no-op. - - If called on a primitive type other than `null`, the resulting JSON value - will be `null`. - - @param[in] first iterator to the beginning of the range to remove - @param[in] last iterator past the end of the range to remove - @return Iterator following the last removed element. If the iterator @a - second refers to the last element, the `end()` iterator is returned. - - @tparam IteratorType an @ref iterator or @ref const_iterator - - @post Invalidates iterators and references at or after the point of the - erase, including the `end()` iterator. - - @throw type_error.307 if called on a `null` value; example: `"cannot use - erase() with null"` - @throw invalid_iterator.203 if called on iterators which does not belong - to the current JSON value; example: `"iterators do not fit current value"` - @throw invalid_iterator.204 if called on a primitive type with invalid - iterators (i.e., if `first != begin()` and `last != end()`); example: - `"iterators out of range"` - - @complexity The complexity depends on the type: - - objects: `log(size()) + std::distance(first, last)` - - arrays: linear in the distance between @a first and @a last, plus linear - in the distance between @a last and end of the container - - strings: linear in the length of the string - - other types: constant - - @liveexample{The example shows the result of `erase()` for different JSON - types.,erase__IteratorType_IteratorType} - - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key - @sa @ref erase(const size_type) -- removes the element from an array at - the given index - - @since version 1.0.0 - */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) { - // make sure iterator fits the current value - if (this != first.m_object or this != last.m_object) - { - JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); - } - - IteratorType result = end(); + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: - { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) - { - JSON_THROW(invalid_iterator::create(204, "iterators out of range")); - } + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } - if (is_string()) - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; - } + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } - m_type = value_t::null; - assert_invariant(); - break; - } + case value_t::boolean: + { + m_value.boolean = false; + break; + } - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } + case value_t::string: + { + m_value.string->clear(); + break; + } - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; - } + case value_t::array: + { + m_value.array->clear(); + break; + } - default: - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); - } - } + case value_t::object: + { + m_value.object->clear(); + break; + } - return result; + default: + { + break; + } } + } - /*! - @brief remove element from a JSON object given a key + /*! + @brief add an object to an array - Removes elements from a JSON object with the key value @a key. + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. - @param[in] key value of the elements to remove + @param[in] val the value to add to the JSON array - @return Number of elements removed. If @a ObjectType is the default - `std::map` type, the return value will always be `0` (@a key was not - found) or `1` (@a key was found). + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` - @post References and iterators to the erased elements are invalidated. - Other references and iterators are not affected. + @complexity Amortized constant. - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} - @complexity `log(size()) + count(key)` + @since version 1.0.0 + */ + void push_back(basic_json && val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); + } - @liveexample{The example shows the effect of `erase()`.,erase__key_type} + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const size_type) -- removes the element from an array at - the given index + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } - @since version 1.0.0 - */ - size_type erase(const typename object_t::key_type& key) + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json && val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json & val) + { + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) { - // this erase only works for objects - if (is_object()) - { - return m_value.object->erase(key); - } + JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); + } - JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); } - /*! - @brief remove element from a JSON array given an index + // add element to array + m_value.array->push_back(val); + } - Removes element from a JSON array at the index @a idx. + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json & val) + { + push_back(val); + return *this; + } - @param[in] idx index of the element to remove + /*! + @brief add an object to an object - @throw type_error.307 when called on a type other than JSON object; - example: `"cannot use erase() with null"` - @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 - is out of range"` + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. - @complexity Linear in distance between @a idx and the end of the container. + @param[in] val the value to add to the JSON object - @liveexample{The example shows the effect of `erase()`.,erase__size_type} + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` - @sa @ref erase(IteratorType) -- removes the element at a given position - @sa @ref erase(IteratorType, IteratorType) -- removes the elements in - the given range - @sa @ref erase(const typename object_t::key_type&) -- removes the element - from an object at the given key + @complexity Logarithmic in the size of the container, O(log(`size()`)). - @since version 1.0.0 - */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (is_array()) - { - if (idx >= size()) - { - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - JSON_THROW(type_error::create(307, "cannot use erase() with " + type_name())); - } + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type & val) + { + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); } - /// @} - + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } - //////////// - // lookup // - //////////// + // add element to array + m_value.object->insert(val); + } - /// @name lookup - /// @{ + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type & val) + { + push_back(val); + return *this; + } - /*! - @brief find an element in a JSON object + /*! + @brief add an object to an object - Finds an element in a JSON object with key equivalent to @a key. If the - element is not found or the JSON value is not an object, end() is - returned. + This function allows to use `push_back` with an initializer list. In case - @note This method always returns @ref end() when executed on a JSON type - that is not an object. + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, - @param[in] key key value of the element to search for + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). - @return Iterator to an element with key equivalent to @a key. If no such - element is found or the JSON value is not an object, past-the-end (see - @ref end()) iterator is returned. + @param[in] init an initializer list - @complexity Logarithmic in the size of the JSON object. + @complexity Linear in the size of the initializer list @a init. - @liveexample{The example shows how `find()` is used.,find__key_type} + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. - @since version 1.0.0 - */ - iterator find(typename object_t::key_type key) + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(std::initializer_list init) + { + if (is_object() and init.size() == 2 and init.begin()->is_string()) { - auto result = end(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; + const string_t key = *init.begin(); + push_back(typename object_t::value_type(key, *(init.begin() + 1))); } - - /*! - @brief find an element in a JSON object - @copydoc find(typename object_t::key_type) - */ - const_iterator find(typename object_t::key_type key) const + else { - auto result = cend(); - - if (is_object()) - { - result.m_it.object_iterator = m_value.object->find(key); - } - - return result; + push_back(basic_json(init)); } + } - /*! - @brief returns the number of occurrences of a key in a JSON object + /*! + @brief add an object to an object + @copydoc push_back(std::initializer_list) + */ + reference operator+=(std::initializer_list init) + { + push_back(init); + return *this; + } - Returns the number of elements with key @a key. If ObjectType is the - default `std::map` type, the return value will always be `0` (@a key was - not found) or `1` (@a key was found). + /*! + @brief add an object to an array - @note This method always returns `0` when executed on a JSON type that is - not an object. + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. - @param[in] key key value of the element to count + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object - @return Number of elements with key @a key. If the JSON value is not an - object, the return value will be `0`. + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` - @complexity Logarithmic in the size of the JSON object. + @complexity Amortized constant. - @liveexample{The example shows how `count()` is used.,count} + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} - @since version 1.0.0 - */ - size_type count(typename object_t::key_type key) const + @since version 2.0.8 + */ + template + void emplace_back(Args &&... args) + { + // emplace_back only works for null objects or arrays + if (not(is_null() or is_array())) { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(key) : 0; + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + type_name())); } - /// @} - - - /////////////// - // iterators // - /////////////// - - /// @name iterators - /// @{ + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } - /*! - @brief returns an iterator to the first element + // add element to array (perfect forwarding) + m_value.array->emplace_back(std::forward(args)...); + } - Returns an iterator to the first element. + /*! + @brief add an object to an object if key does not exist - @image html range-begin-end.svg "Illustration from cppreference.com" + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. - @return iterator to the first element + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object - @complexity Constant. + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` - @liveexample{The following code shows an example for `begin()`.,begin} + @complexity Logarithmic in the size of the container, O(log(`size()`)). - @sa @ref cbegin() -- returns a const iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} - @since version 1.0.0 - */ - iterator begin() noexcept + @since version 2.0.8 + */ + template + std::pair emplace(Args &&... args) + { + // emplace only works for null objects or arrays + if (not(is_null() or is_object())) { - iterator result(this); - result.set_begin(); - return result; + JSON_THROW(type_error::create(311, "cannot use emplace() with " + type_name())); } - /*! - @copydoc basic_json::cbegin() - */ - const_iterator begin() const noexcept + // transform null object into an object + if (is_null()) { - return cbegin(); + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); } - /*! - @brief returns a const iterator to the first element + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; - Returns a const iterator to the first element. + // return pair of iterator and boolean + return {it, res.second}; + } - @image html range-begin-end.svg "Illustration from cppreference.com" + /*! + @brief inserts element - @return const iterator to the first element + Inserts element @a val before iterator @a pos. - @complexity Constant. + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).begin()`. + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` - @liveexample{The following code shows an example for `cbegin()`.,cbegin} + @complexity Constant plus linear in the distance between @a pos and end of + the container. - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref end() -- returns an iterator to the end - @sa @ref cend() -- returns a const iterator to the end + @liveexample{The example shows how `insert()` is used.,insert} - @since version 1.0.0 - */ - const_iterator cbegin() const noexcept + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json & val) + { + // insert only works for arrays + if (is_array()) { - const_iterator result(this); - result.set_begin(); - return result; + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; } - /*! - @brief returns an iterator to one past the last element + JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); + } - Returns an iterator to one past the last element. + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json && val) + { + return insert(pos, val); + } - @image html range-begin-end.svg "Illustration from cppreference.com" + /*! + @brief inserts elements - @return iterator one past the last element + Inserts @a cnt copies of @a val before iterator @a pos. - @complexity Constant. + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` - @liveexample{The following code shows an example for `end()`.,end} + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. - @sa @ref cend() -- returns a const iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning + @liveexample{The example shows how `insert()` is used.,insert__count} - @since version 1.0.0 - */ - iterator end() noexcept + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json & val) + { + // insert only works for arrays + if (is_array()) { - iterator result(this); - result.set_end(); - return result; - } + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } - /*! - @copydoc basic_json::cend() - */ - const_iterator end() const noexcept - { - return cend(); + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; } - /*! - @brief returns a const iterator to one past the last element + JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); + } - Returns a const iterator to one past the last element. + /*! + @brief inserts elements - @image html range-begin-end.svg "Illustration from cppreference.com" + Inserts elements from range `[first, last)` before iterator @a pos. - @return const iterator one past the last element + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert - @complexity Constant. + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).end()`. + @return iterator pointing to the first element inserted, or @a pos if + `first==last` - @liveexample{The following code shows an example for `cend()`.,cend} + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. - @sa @ref end() -- returns an iterator to the end - @sa @ref begin() -- returns an iterator to the beginning - @sa @ref cbegin() -- returns a const iterator to the beginning + @liveexample{The example shows how `insert()` is used.,insert__range} - @since version 1.0.0 - */ - const_iterator cend() const noexcept + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (not is_array()) { - const_iterator result(this); - result.set_end(); - return result; + JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); } - /*! - @brief returns an iterator to the reverse-beginning + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + } + + // check if range iterators belong to the same JSON object + if (first.m_object != last.m_object) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + } + + if (first.m_object == this or last.m_object == this) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + } - Returns an iterator to the reverse-beginning; that is, the last element. + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = + m_value.array->insert(pos.m_it.array_iterator, first.m_it.array_iterator, last.m_it.array_iterator); + return result; + } - @image html range-rbegin-rend.svg "Illustration from cppreference.com" + /*! + @brief inserts elements - @complexity Constant. + Inserts elements from initializer list @a ilist before iterator @a pos. - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(end())`. + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from - @liveexample{The following code shows an example for `rbegin()`.,rbegin} + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` - @sa @ref crbegin() -- returns a const reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty - @since version 1.0.0 - */ - reverse_iterator rbegin() noexcept + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, std::initializer_list ilist) + { + // insert only works for arrays + if (not is_array()) { - return reverse_iterator(end()); + JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); } - /*! - @copydoc basic_json::crbegin() - */ - const_reverse_iterator rbegin() const noexcept + // check if iterator pos fits to this JSON value + if (pos.m_object != this) { - return crbegin(); + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); } - /*! - @brief returns an iterator to the reverse-end + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } - Returns an iterator to the reverse-end; that is, one before the first - element. + /*! + @brief inserts elements - @image html range-rbegin-rend.svg "Illustration from cppreference.com" + Inserts elements from range `[first, last)`. - @complexity Constant. + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `reverse_iterator(begin())`. + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` - @liveexample{The following code shows an example for `rend()`.,rend} + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. - @sa @ref crend() -- returns a const reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @liveexample{The example shows how `insert()` is used.,insert__range_object} - @since version 1.0.0 - */ - reverse_iterator rend() noexcept + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (not is_object()) { - return reverse_iterator(begin()); + JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); } - /*! - @copydoc basic_json::crend() - */ - const_reverse_iterator rend() const noexcept + // check if range iterators belong to the same JSON object + if (first.m_object != last.m_object) { - return crend(); + JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); } - /*! - @brief returns a const reverse iterator to the last element - - Returns a const iterator to the reverse-beginning; that is, the last - element. + // passed iterators must belong to objects + if (not first.m_object->is_object() or not first.m_object->is_object()) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); + } - @image html range-rbegin-rend.svg "Illustration from cppreference.com" + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } - @complexity Constant. + /*! + @brief exchanges the values - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rbegin()`. + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. - @liveexample{The following code shows an example for `crbegin()`.,crbegin} + @param[in,out] other JSON value to exchange the contents with - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref crend() -- returns a const reverse iterator to the end + @complexity Constant. - @since version 1.0.0 - */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} - /*! - @brief returns a const reverse iterator to one before the first + @since version 1.0.0 + */ + void swap(reference other) noexcept( + std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } - Returns a const reverse iterator to the reverse-end; that is, one before - the first element. + /*! + @brief exchanges the values - @image html range-rbegin-rend.svg "Illustration from cppreference.com" + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. - @complexity Constant. + @param[in,out] other array to exchange the contents with - @requirement This function helps `basic_json` satisfying the - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) - requirements: - - The complexity is constant. - - Has the semantics of `const_cast(*this).rend()`. + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` - @liveexample{The following code shows an example for `crend()`.,crend} + @complexity Constant. - @sa @ref rend() -- returns a reverse iterator to the end - @sa @ref rbegin() -- returns a reverse iterator to the beginning - @sa @ref crbegin() -- returns a const reverse iterator to the beginning + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} - @since version 1.0.0 - */ - const_reverse_iterator crend() const noexcept + @since version 1.0.0 + */ + void swap(array_t & other) + { + // swap only works for arrays + if (is_array()) + { + std::swap(*(m_value.array), other); + } + else { - return const_reverse_iterator(cbegin()); + JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); } + } - private: - // forward declaration - template class iteration_proxy; + /*! + @brief exchanges the values - public: - /*! - @brief wrapper to access iterator member functions in range-based for + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. - This function allows to access @ref iterator::key() and @ref - iterator::value() during range-based for loops. In these loops, a - reference to the JSON values is returned, so there is no access to the - underlying iterator. + @param[in,out] other object to exchange the contents with - @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` - @note The name of this function is not yet final and may change in the - future. - */ - static iteration_proxy iterator_wrapper(reference cont) + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t & other) + { + // swap only works for objects + if (is_object()) { - return iteration_proxy(cont); + std::swap(*(m_value.object), other); } - - /*! - @copydoc iterator_wrapper(reference) - */ - static iteration_proxy iterator_wrapper(const_reference cont) + else { - return iteration_proxy(cont); + JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); } + } - /// @} + /*! + @brief exchanges the values + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. - ////////////// - // capacity // - ////////////// + @param[in,out] other string to exchange the contents with - /// @name capacity - /// @{ - - /*! - @brief checks whether the container is empty + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. - Checks if a JSON value has no elements. + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t & other) + { + // swap only works for strings + if (is_string()) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); + } + } - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `true` - boolean | `false` - string | `false` - number | `false` - object | result of function `object_t::empty()` - array | result of function `array_t::empty()` + /// @} - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. +public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `empty()` functions have constant - complexity. + /// @name lexicographical comparison operators + /// @{ - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `begin() == end()`. + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Floating-point numbers are compared indirectly: two + floating-point numbers `f1` and `f2` are considered equal if neither + `f1 > f2` nor `f2 > f1` holds. Note than two NaN values are always + treated as unequal. + - Two JSON null values are equal. + + @note NaN values never compare equal to themselves or to other NaN values. - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } - @sa @ref size() -- returns the number of elements + return false; + } - @since version 1.0.0 - */ - bool empty() const noexcept + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs == basic_json(rhs)); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) == rhs); + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not(lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs != basic_json(rhs)); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) != rhs); + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + { + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } + } + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return true; - } + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs < basic_json(rhs)); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) < rhs); + } - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not(rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs <= basic_json(rhs)); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) <= rhs); + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not(lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs > basic_json(rhs)); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) > rhs); + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not(lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + { + return (lhs >= basic_json(rhs)); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template ::value, int>::type = 0> + friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + { + return (basic_json(lhs) >= rhs); + } + + /// @} + +private: + ///////////////////// + // output adapters // + ///////////////////// + + /// abstract output adapter interface + template + class output_adapter + { + public: + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType * s, size_t length) = 0; + virtual ~output_adapter() + { + } - default: - { - // all other types are nonempty - return false; - } - } + static std::shared_ptr> create(std::vector & vec) + { + return std::shared_ptr(new output_vector_adapter(vec)); } - /*! - @brief returns the number of elements - - Returns the number of elements in a JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` - boolean | `1` - string | `1` - number | `1` - object | result of function object_t::size() - array | result of function array_t::size() - - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their size() functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of `std::distance(begin(), end())`. - - @liveexample{The following code calls `size()` on the different value - types.,size} - - @sa @ref empty() -- checks whether the container is empty - @sa @ref max_size() -- returns the maximal number of elements - - @since version 1.0.0 - */ - size_type size() const noexcept + static std::shared_ptr> create(std::ostream & s) { - switch (m_type) - { - case value_t::null: - { - // null values are empty - return 0; - } + return std::shared_ptr(new output_stream_adapter(s)); + } - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } + static std::shared_ptr> create(std::string & s) + { + return std::shared_ptr(new output_string_adapter(s)); + } + }; - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } + /// a type to simplify interfaces + template + using output_adapter_t = std::shared_ptr>; - default: - { - // all other types have size 1 - return 1; - } - } + /// output adapter for byte vectors + template + class output_vector_adapter : public output_adapter + { + public: + output_vector_adapter(std::vector & vec) + : v(vec) + { } - /*! - @brief returns the maximum possible number of elements - - Returns the maximum number of elements a JSON value is able to hold due to - system or library implementation limitations, i.e. `std::distance(begin(), - end())` for the JSON value. - - @return The return value depends on the different types and is - defined as follows: - Value type | return value - ----------- | ------------- - null | `0` (same as `size()`) - boolean | `1` (same as `size()`) - string | `1` (same as `size()`) - number | `1` (same as `size()`) - object | result of function `object_t::max_size()` - array | result of function `array_t::max_size()` - - @complexity Constant, as long as @ref array_t and @ref object_t satisfy - the Container concept; that is, their `max_size()` functions have constant - complexity. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - Has the semantics of returning `b.size()` where `b` is the largest - possible JSON value. - - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - - @sa @ref size() -- returns the number of elements - - @since version 1.0.0 - */ - size_type max_size() const noexcept + void write_character(CharType c) override { - switch (m_type) - { - case value_t::array: - { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } + v.push_back(c); + } - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } + void write_characters(const CharType * s, size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } - default: - { - // all other types have max_size() == size() - return size(); - } - } + private: + std::vector & v; + }; + + /// putput adatpter for output streams + template + class output_stream_adapter : public output_adapter + { + public: + output_stream_adapter(std::basic_ostream & s) + : stream(s) + { + } + + void write_character(CharType c) override + { + stream.put(c); } - /// @} + void write_characters(const CharType * s, size_t length) override + { + stream.write(s, static_cast(length)); + } + private: + std::basic_ostream & stream; + }; - /////////////// - // modifiers // - /////////////// + /// output adapter for basic_string + template + class output_string_adapter : public output_adapter + { + public: + output_string_adapter(std::string & s) + : str(s) + { + } - /// @name modifiers - /// @{ + void write_character(CharType c) override + { + str.push_back(c); + } - /*! - @brief clears the contents + void write_characters(const CharType * s, size_t length) override + { + str.append(s, length); + } - Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called: + private: + std::basic_string & str; + }; + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ + +private: + /*! + @brief wrapper around the serialization functions + */ + class serializer + { + private: + serializer(const serializer &) = delete; + serializer & operator=(const serializer &) = delete; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + */ + serializer(output_adapter_t s, const char ichar) + : o(s) + , loc(std::localeconv()) + , thousands_sep(!loc->thousands_sep ? '\0' : loc->thousands_sep[0]) + , decimal_point(!loc->decimal_point ? '\0' : loc->decimal_point[0]) + , indent_char(ichar) + , indent_string(512, indent_char) + { + } - Value type | initial value - ----------- | ------------- - null | `null` - boolean | `false` - string | `""` - number | `0` - object | `{}` - array | `[]` + /*! + @brief internal implementation of the serialization function - @complexity Linear in the size of the JSON value. + This function is called by the public member function dump and + organizes the serialization internally. The indentation level is + propagated as additional parameter. In case of arrays and objects, the + function is called recursively. - @liveexample{The example below shows the effect of `clear()` to different - JSON types.,clear} + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format - @since version 1.0.0 + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) */ - void clear() noexcept + void dump( + const basic_json & val, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) { - switch (m_type) + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) { - case value_t::number_integer: - { - m_value.number_integer = 0; - break; - } + o->write_characters("{}", 2); + return; + } - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } + if (pretty_print) + { + o->write_characters("{\n", 2); - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (indent_string.size() < new_indent) + { + indent_string.resize(new_indent, ' '); + } - case value_t::boolean: - { - m_value.boolean = false; - break; - } + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first); + o->write_characters("\": ", 3); + dump(i->second, true, indent_step, new_indent); + o->write_characters(",\n", 2); + } - case value_t::string: - { - m_value.string->clear(); - break; - } + // last element + assert(i != val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first); + o->write_characters("\": ", 3); + dump(i->second, true, indent_step, new_indent); - case value_t::array: - { - m_value.array->clear(); - break; - } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); - case value_t::object: - { - m_value.object->clear(); - break; - } + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first); + o->write_characters("\":", 2); + dump(i->second, false, indent_step, current_indent); + o->write_character(','); + } - default: - { - break; - } + // last element + assert(i != val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first); + o->write_characters("\":", 2); + dump(i->second, false, indent_step, current_indent); + + o->write_character('}'); } - } - /*! - @brief add an object to an array + return; + } - Appends the given element @a val to the end of the JSON value. If the - function is called on a JSON null value, an empty array is created before - appending @a val. + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } - @param[in] val the value to add to the JSON array + if (pretty_print) + { + o->write_characters("[\n", 2); - @throw type_error.308 when called on a type other than JSON array or - null; example: `"cannot use push_back() with number"` + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (indent_string.size() < new_indent) + { + indent_string.resize(new_indent, ' '); + } - @complexity Amortized constant. + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, indent_step, new_indent); + o->write_characters(",\n", 2); + } - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON array. Note how the `null` value was silently - converted to a JSON array.,push_back} + // last element + assert(not val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, indent_step, new_indent); - @since version 1.0.0 - */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, indent_step, current_indent); + o->write_character(','); + } + + // last element + assert(not val.m_value.array->empty()); + dump(val.m_value.array->back(), false, indent_step, current_indent); + + o->write_character(']'); } - // transform null object into an array - if (is_null()) + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string); + o->write_character('\"'); + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); + o->write_characters("false", 5); } + return; + } - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } - /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + } } + private: /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) - */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); + @brief calculates the extra space to escape a JSON string + + @param[in] s the string to escape + @return the number of characters required to escape string @a s + + @complexity Linear in the length of string @a s. + */ + static std::size_t extra_space(const string_t & s) noexcept + { + return std::accumulate(s.begin(), s.end(), size_t{}, [](size_t res, typename string_t::value_type c) { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + return res + 1; + } + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0b: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + { + // from c (1 byte) to \uxxxx (6 bytes) + return res + 5; } - // transform null object into an array - if (is_null()) + default: { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); + return res; } - - // add element to array - m_value.array->push_back(val); + } + }); } /*! - @brief add an object to an array - @copydoc push_back(basic_json&&) + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence + of an escape character (backslash) and another character and other + control characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + + @complexity Linear in the length of string @a s. */ - reference operator+=(const basic_json& val) + void dump_escaped(const string_t & s) const { - push_back(val); - return *this; - } + const auto space = extra_space(s); + if (space == 0) + { + o->write_characters(s.c_str(), s.size()); + return; + } - /*! - @brief add an object to an object + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; + + for (const auto & c : s) + { + switch (c) + { + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } + + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } - Inserts the given element @a val to the JSON object. If the function is - called on a JSON null value, an empty object is created before inserting - @a val. + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } - @param[in] val the value to add to the JSON object + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } - @throw type_error.308 when called on a type other than JSON object or - null; example: `"cannot use push_back() with number"` + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } - @complexity Logarithmic in the size of the container, O(log(`size()`)). + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } - @liveexample{The example shows how `push_back()` and `+=` can be used to - add elements to a JSON object. Note how the `null` value was silently - converted to a JSON object.,push_back__object_t__value} + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } - @since version 1.0.0 - */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (not(is_null() or is_object())) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0b: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: { - JSON_THROW(type_error::create(308, "cannot use push_back() with " + type_name())); + // convert a number 0..15 to its hex representation + // (0..f) + static const char hexify[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + // print character c as \uxxxx + for (const char m : {'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]}) + { + result[++pos] = m; + } + + ++pos; + break; } - // transform null object into an object - if (is_null()) + default: { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); + // all other characters are added as-is + result[pos++] = c; + break; + } } + } - // add element to array - m_value.object->insert(val); + assert(pos == s.size() + space); + o->write_characters(result.c_str(), result.size()); } /*! - @brief add an object to an object - @copydoc push_back(const typename object_t::value_type&) + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t */ - reference operator+=(const typename object_t::value_type& val) + template < + typename NumberType, + detail::enable_if_t< + std::is_same::value or std::is_same::value, + int> = 0> + void dump_integer(NumberType x) { - push_back(val); - return *this; - } + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } - /*! - @brief add an object to an object + const bool is_negative = x < 0; + size_t i = 0; - This function allows to use `push_back` with an initializer list. In case + // spare 1 byte for '\0' + while (x != 0 and i < number_buffer.size() - 1) + { + const auto digit = std::labs(static_cast(x % 10)); + number_buffer[i++] = static_cast('0' + digit); + x /= 10; + } - 1. the current value is an object, - 2. the initializer list @a init contains only two elements, and - 3. the first element of @a init is a string, + // make sure the number has been processed completely + assert(x == 0); - @a init is converted into an object element and added using - @ref push_back(const typename object_t::value_type&). Otherwise, @a init - is converted to a JSON value and added using @ref push_back(basic_json&&). + if (is_negative) + { + // make sure there is capacity for the '-' + assert(i < number_buffer.size() - 2); + number_buffer[i++] = '-'; + } - @param[in] init an initializer list + std::reverse(number_buffer.begin(), number_buffer.begin() + i); + o->write_characters(number_buffer.data(), i); + } - @complexity Linear in the size of the initializer list @a init. + /*! + @brief dump a floating-point number - @note This function is required to resolve an ambiguous overload error, - because pairs like `{"key", "value"}` can be both interpreted as - `object_t::value_type` or `std::initializer_list`, see - https://github.com/nlohmann/json/issues/235 for more information. + Dump a given floating-point number to output stream @a o. Works + internally with @a number_buffer. - @liveexample{The example shows how initializer lists are treated as - objects when possible.,push_back__initializer_list} + @param[in] x floating-point number to dump */ - void push_back(std::initializer_list init) + void dump_float(number_float_t x) { - if (is_object() and init.size() == 2 and init.begin()->is_string()) + // NaN / inf + if (not std::isfinite(x) or std::isnan(x)) + { + o->write_characters("null", 4); + return; + } + + // special case for 0.0 and -0.0 + if (x == 0) + { + if (std::signbit(x)) { - const string_t key = *init.begin(); - push_back(typename object_t::value_type(key, *(init.begin() + 1))); + o->write_characters("-0.0", 4); } else { - push_back(basic_json(init)); + o->write_characters("0.0", 3); } - } + return; + } - /*! - @brief add an object to an object - @copydoc push_back(std::initializer_list) - */ - reference operator+=(std::initializer_list init) - { - push_back(init); - return *this; - } + // get number of digits for a text -> float -> text round-trip + static constexpr auto d = std::numeric_limits::digits10; - /*! - @brief add an object to an array + // the actual conversion + std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), "%.*g", d, x); - Creates a JSON value from the passed parameters @a args to the end of the - JSON value. If the function is called on a JSON null value, an empty array - is created before appending the value created from @a args. + // negative value indicates an error + assert(len > 0); + // check if buffer was large enough + assert(static_cast(len) < number_buffer.size()); - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object + // erase thousands separator + if (thousands_sep != '\0') + { + const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + assert((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } - @throw type_error.311 when called on a type other than JSON array or - null; example: `"cannot use emplace_back() with number"` + // convert decimal point to '.' + if (decimal_point != '\0' and decimal_point != '.') + { + for (auto & c : number_buffer) + { + if (c == decimal_point) + { + c = '.'; + break; + } + } + } - @complexity Amortized constant. + o->write_characters(number_buffer.data(), static_cast(len)); - @liveexample{The example shows how `push_back()` can be used to add - elements to a JSON array. Note how the `null` value was silently converted - to a JSON array.,emplace_back} + // determine if need to append ".0" + const bool value_is_int_like = std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, [](char c) { + return c == '.' or c == 'e'; + }); - @since version 2.0.8 - */ - template - void emplace_back(Args&& ... args) - { - // emplace_back only works for null objects or arrays - if (not(is_null() or is_array())) - { - JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + type_name())); - } - - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } - - // add element to array (perfect forwarding) - m_value.array->emplace_back(std::forward(args)...); + if (value_is_int_like) + { + o->write_characters(".0", 2); + } } - /*! - @brief add an object to an object if key does not exist - - Inserts a new element into a JSON object constructed in-place with the - given @a args if there is no element with the key in the container. If the - function is called on a JSON null value, an empty object is created before - appending the value created from @a args. - - @param[in] args arguments to forward to a constructor of @ref basic_json - @tparam Args compatible types to create a @ref basic_json object - - @return a pair consisting of an iterator to the inserted element, or the - already-existing element if no insertion happened, and a bool - denoting whether the insertion took place. + private: + /// the output of the serializer + output_adapter_t o = nullptr; - @throw type_error.311 when called on a type other than JSON object or - null; example: `"cannot use emplace() with number"` + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv * loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; - @complexity Logarithmic in the size of the container, O(log(`size()`)). + /// the indentation character + const char indent_char; - @liveexample{The example shows how `emplace()` can be used to add elements - to a JSON object. Note how the `null` value was silently converted to a - JSON object. Further note how no value is added if there was already one - value stored with the same key.,emplace} + /// the indentation string + string_t indent_string; + }; + +public: + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation characrer can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentaction character added in version 3.0.0 + */ + friend std::ostream & operator<<(std::ostream & o, const basic_json & j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); - @since version 2.0.8 - */ - template - std::pair emplace(Args&& ... args) + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(output_adapter::create(o), o.fill()); + s.dump(j, pretty_print, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::ostream& operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + */ + JSON_DEPRECATED + friend std::ostream & operator>>(const basic_json & j, std::ostream & o) + { + return o << j; + } + + /// @} + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from an array + + This function reads from an array of 1-byte values. + + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @param[in] array array to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @since version 2.0.3 + */ + template + static basic_json parse(T (&array)[N], const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(array), std::end(array), cb); + } + + /*! + @brief deserialize from string literal + + @tparam CharT character/literal type with size of 1 byte + @param[in] s string literal to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + @note String containers like `std::string` or @ref string_t can be parsed + with @ref parse(const ContiguousContainer&, const parser_callback_t) + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @sa @ref parse(std::istream&, const parser_callback_t) for a version that + reads from an input stream + + @since version 1.0.0 (originally for @ref string_t) + */ + template < + typename CharT, + typename std::enable_if< + std::is_pointer::value and std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + static basic_json parse(const CharT s, const parser_callback_t cb = nullptr) + { + return parser(input_adapter::create(s), cb).parse(true); + } + + /*! + @brief deserialize from stream + + @param[in,out] i stream to read a serialized JSON value from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @sa @ref parse(const CharT, const parser_callback_t) for a version + that reads from a string + + @since version 1.0.0 + */ + static basic_json parse(std::istream & i, const parser_callback_t cb = nullptr) + { + return parser(input_adapter::create(i), cb).parse(true); + } + + /*! + @copydoc parse(std::istream&, const parser_callback_t) + */ + static basic_json parse(std::istream && i, const parser_callback_t cb = nullptr) + { + return parser(input_adapter::create(i), cb).parse(true); + } + + /*! + @brief deserialize from an iterator range with contiguous storage + + This function reads from an iterator range of a container with contiguous + storage of 1-byte values. Compatible container types include + `std::vector`, `std::string`, `std::array`, `std::valarray`, and + `std::initializer_list`. Furthermore, C-style arrays can be used with + `std::begin()`/`std::end()`. User-defined containers can be used as long + as they implement random-access iterators and a contiguous storage. + + @pre The iterator range is contiguous. Violating this precondition yields + undefined behavior. **This precondition is enforced with an assertion.** + @pre Each element in the range has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with noncompliant iterators and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam IteratorType iterator of container with contiguous storage + @param[in] first begin of the range to parse (included) + @param[in] last end of the range to parse (excluded) + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an iterator range.,parse__iteratortype__parser_callback_t} + + @since version 2.0.3 + */ + template < + class IteratorType, + typename std::enable_if< + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits::iterator_category>::value, + int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) + { + return parser(input_adapter::create(first, last), cb).parse(true); + } + + /*! + @brief deserialize from a container with contiguous storage + + This function reads from a container with contiguous storage of 1-byte + values. Compatible container types include `std::vector`, `std::string`, + `std::array`, and `std::initializer_list`. User-defined containers can be + used as long as they implement random-access iterators and a contiguous + storage. + + @pre The container storage is contiguous. Violating this precondition + yields undefined behavior. **This precondition is enforced with an + assertion.** + @pre Each element of the container has a size of 1 byte. Violating this + precondition yields undefined behavior. **This precondition is enforced + with a static assertion.** + + @warning There is no way to enforce all preconditions at compile-time. If + the function is called with a noncompliant container and with + assertions switched off, the behavior is undefined and will most + likely yield segmentation violation. + + @tparam ContiguousContainer container type with contiguous storage + @param[in] c container to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + + @return result of the deserialization + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 + */ + template < + class ContiguousContainer, + typename std::enable_if< + not std::is_pointer::value and + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits< + decltype(std::begin(std::declval()))>::iterator_category>::value, + int>::type = 0> + static basic_json parse(const ContiguousContainer & c, const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(c), std::end(c), cb); + } + + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::istream& operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + */ + JSON_DEPRECATED + friend std::istream & operator<<(basic_json & j, std::istream & i) + { + j = parser(input_adapter::create(i)).parse(false); + return i; + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + @throw parse_error.111 if input stream is in a bad state + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream & operator>>(std::istream & i, basic_json & j) + { + j = parser(input_adapter::create(i)).parse(false); + return i; + } + + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return basically a string representation of a the @a m_type member + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @since version 1.0.0, public since 2.1.0 + */ + std::string type_name() const + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } + } + } + +private: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + +private: + /////////////// + // iterators // + /////////////// + + /*! + @brief an iterator for primitive JSON types + + This class models an iterator for primitive JSON types (boolean, number, + string). It's only purpose is to allow the iterator/const_iterator classes + to "iterate" over primitive values. Internally, the iterator is modeled by + a `difference_type` variable. Value begin_value (`0`) models the begin, + end_value (`1`) models past the end. + */ + class primitive_iterator_t + { + public: + difference_type get_value() const noexcept { - // emplace only works for null objects or arrays - if (not(is_null() or is_object())) - { - JSON_THROW(type_error::create(311, "cannot use emplace() with " + type_name())); - } - - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } - - // add element to array (perfect forwarding) - auto res = m_value.object->emplace(std::forward(args)...); - // create result iterator and set iterator to the result of emplace - auto it = begin(); - it.m_it.object_iterator = res.first; - - // return pair of iterator and boolean - return {it, res.second}; + return m_it; + } + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; } - /*! - @brief inserts element - - Inserts element @a val before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] val element to insert - @return iterator pointing to the inserted @a val. - - @throw type_error.309 if called on JSON values other than arrays; - example: `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } - @complexity Constant plus linear in the distance between @a pos and end of - the container. + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return (m_it == begin_value); + } - @liveexample{The example shows how `insert()` is used.,insert} + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return (m_it == end_value); + } - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const basic_json& val) + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } + return lhs.m_it == rhs.m_it; + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } + friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return !(lhs == rhs); + } - JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; } - /*! - @brief inserts element - @copydoc insert(const_iterator, const basic_json&) - */ - iterator insert(const_iterator pos, basic_json&& val) + friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept { - return insert(pos, val); + return lhs.m_it <= rhs.m_it; } - /*! - @brief inserts elements + friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it > rhs.m_it; + } - Inserts @a cnt copies of @a val before iterator @a pos. + friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it >= rhs.m_it; + } - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] cnt number of copies of @a val to insert - @param[in] val element to insert - @return iterator pointing to the first element inserted, or @a pos if - `cnt==0` + primitive_iterator_t operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } - @complexity Linear in @a cnt plus linear in the distance between @a pos - and end of the container. + friend std::ostream & operator<<(std::ostream & os, primitive_iterator_t it) + { + return os << it.m_it; + } - @liveexample{The example shows how `insert()` is used.,insert__count} + primitive_iterator_t & operator++() + { + ++m_it; + return *this; + } - @since version 1.0.0 - */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + primitive_iterator_t operator++(int) { - // insert only works for arrays - if (is_array()) - { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } + auto result = *this; + m_it++; + return result; + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } + primitive_iterator_t & operator--() + { + --m_it; + return *this; + } - JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); + primitive_iterator_t operator--(int) + { + auto result = *this; + m_it--; + return result; } - /*! - @brief inserts elements + primitive_iterator_t & operator+=(difference_type n) + { + m_it += n; + return *this; + } - Inserts elements from range `[first, last)` before iterator @a pos. + primitive_iterator_t & operator-=(difference_type n) + { + m_it -= n; + return *this; + } - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; + + /*! + @brief an iterator value + + @note This structure could easily be a union, but MSVC currently does not + allow unions members with complex constructors, see + https://github.com/nlohmann/json/pull/105. + */ + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; + + /// create an uninitialized internal_iterator + internal_iterator() noexcept + : object_iterator() + , array_iterator() + , primitive_iterator() + { + } + }; + + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal + { + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; + + public: + explicit iteration_proxy_internal(IteratorType it) noexcept + : anchor(it) + { + } + + /// dereference operator (needed for range-based for) + iteration_proxy_internal & operator*() + { + return *this; + } - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` - @throw invalid_iterator.211 if @a first or @a last are iterators into - container for which insert is called; example: `"passed iterators may not - belong to container"` + /// increment operator (needed for range-based for) + iteration_proxy_internal & operator++() + { + ++anchor; + ++array_index; - @return iterator pointing to the first element inserted, or @a pos if - `first==last` + return *this; + } - @complexity Linear in `std::distance(first, last)` plus linear in the - distance between @a pos and end of the container. + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_internal & o) const + { + return anchor != o.anchor; + } - @liveexample{The example shows how `insert()` is used.,insert__range} + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); - @since version 1.0.0 - */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (not is_array()) + switch (anchor.m_object->type()) { - JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); - } - - // check if iterator pos fits to this JSON value - if (pos.m_object != this) + // use integer array index as key + case value_t::array: { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); + return std::to_string(array_index); } - // check if range iterators belong to the same JSON object - if (first.m_object != last.m_object) + // use key from the object + case value_t::object: { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); + return anchor.key(); } - if (first.m_object == this or last.m_object == this) + // use an empty key for all primitive types + default: { - JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container")); + return ""; } + } + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } - - /*! - @brief inserts elements - - Inserts elements from initializer list @a ilist before iterator @a pos. - - @param[in] pos iterator before which the content will be inserted; may be - the end() iterator - @param[in] ilist initializer list to insert the values from - - @throw type_error.309 if called on JSON values other than arrays; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if @a pos is not an iterator of *this; - example: `"iterator does not fit current value"` + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; - @return iterator pointing to the first element inserted, or @a pos if - `ilist` is empty + /// the container to iterate + typename IteratorType::reference container; - @complexity Linear in `ilist.size()` plus linear in the distance between - @a pos and end of the container. + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) + { + } - @liveexample{The example shows how `insert()` is used.,insert__ilist} + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } - @since version 1.0.0 - */ - iterator insert(const_iterator pos, std::initializer_list ilist) + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept { - // insert only works for arrays - if (not is_array()) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); - } + return iteration_proxy_internal(container.end()); + } + }; - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value")); - } +public: + /*! + @brief a template for a random access iterator for the @ref basic_json class - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); - return result; - } + This class implements a both iterators (iterator and const_iterator) for the + @ref basic_json class. - /*! - @brief inserts elements + @note An iterator is called *initialized* when a pointer to a JSON value + has been set (e.g., by a constructor or a copy assignment). If the + iterator is default-constructed, it is *uninitialized* and most + methods are undefined. **The library uses assertions to detect calls + on uninitialized iterators.** - Inserts elements from range `[first, last)`. + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. - @param[in] first begin of the range of elements to insert - @param[in] last end of the range of elements to insert + @since version 1.0.0, simplified in version 2.0.9 + */ + template + class iter_impl : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; - @throw type_error.309 if called on JSON values other than objects; example: - `"cannot use insert() with string"` - @throw invalid_iterator.202 if iterator @a first or @a last does does not - point to an object; example: `"iterators first and last must point to - objects"` - @throw invalid_iterator.210 if @a first and @a last do not belong to the - same JSON value; example: `"iterators do not fit"` + // make sure U is basic_json or const basic_json + static_assert( + std::is_same::value or std::is_same::value, + "iter_impl only accepts (const) basic_json"); - @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number - of elements to insert. + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std:: + conditional::value, typename basic_json::const_pointer, typename basic_json::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = typename std::conditional< + std::is_const::value, + typename basic_json::const_reference, + typename basic_json::reference>::type; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; - @liveexample{The example shows how `insert()` is used.,insert__range_object} + /// default constructor + iter_impl() = default; - @since version 3.0.0 + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. */ - void insert(const_iterator first, const_iterator last) + explicit iter_impl(pointer object) noexcept + : m_object(object) { - // insert only works for objects - if (not is_object()) - { - JSON_THROW(type_error::create(309, "cannot use insert() with " + type_name())); - } + assert(m_object != nullptr); - // check if range iterators belong to the same JSON object - if (first.m_object != last.m_object) - { - JSON_THROW(invalid_iterator::create(210, "iterators do not fit")); - } + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } - // passed iterators must belong to objects - if (not first.m_object->is_object() or not first.m_object->is_object()) - { - JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); - } + case basic_json::value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } - m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } } - /*! - @brief exchanges the values - - Exchanges the contents of the JSON value with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other JSON value to exchange the contents with - - @complexity Constant. + /* + Use operator `const_iterator` instead of `const_iterator(const iterator& + other) noexcept` to avoid two class definitions for @ref iterator and + @ref const_iterator. - @liveexample{The example below shows how JSON values can be swapped with - `swap()`.,swap__reference} - - @since version 1.0.0 + This function is only called if this class is an @ref iterator. If this + class is a @ref const_iterator this function is not called. */ - void swap(reference other) noexcept ( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) + operator const_iterator() const { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } - - /*! - @brief exchanges the values + const_iterator ret; - Exchanges the contents of a JSON array with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. + if (m_object) + { + ret.m_object = m_object; + ret.m_it = m_it; + } - @param[in,out] other array to exchange the contents with - - @throw type_error.310 when JSON value is not an array; example: `"cannot - use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how arrays can be swapped with - `swap()`.,swap__array_t} + return ret; + } - @since version 1.0.0 + /*! + @brief copy constructor + @param[in] other iterator to copy from + @note It is not checked whether @a other is initialized. */ - void swap(array_t& other) + iter_impl(const iter_impl & other) noexcept + : m_object(other.m_object) + , m_it(other.m_it) { - // swap only works for arrays - if (is_array()) - { - std::swap(*(m_value.array), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); - } } /*! - @brief exchanges the values - - Exchanges the contents of a JSON object with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. - - @param[in,out] other object to exchange the contents with - - @throw type_error.310 when JSON value is not an object; example: - `"cannot use swap() with string"` - - @complexity Constant. - - @liveexample{The example below shows how objects can be swapped with - `swap()`.,swap__object_t} - - @since version 1.0.0 + @brief copy assignment + @param[in,out] other iterator to copy from + @note It is not checked whether @a other is initialized. */ - void swap(object_t& other) + iter_impl & operator=(iter_impl other) noexcept( + std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and + std::is_nothrow_move_constructible::value and + std::is_nothrow_move_assignable::value) { - // swap only works for objects - if (is_object()) - { - std::swap(*(m_value.object), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); - } + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; } + private: /*! - @brief exchanges the values - - Exchanges the contents of a JSON string with those of @a other. Does not - invoke any move, copy, or swap operations on individual elements. All - iterators and references remain valid. The past-the-end iterator is - invalidated. + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + assert(m_object != nullptr); - @param[in,out] other string to exchange the contents with + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } - @throw type_error.310 when JSON value is not a string; example: `"cannot - use swap() with boolean"` + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } - @complexity Constant. + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } - @liveexample{The example below shows how strings can be swapped with - `swap()`.,swap__string_t} + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } - @since version 1.0.0 + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - void swap(string_t& other) + void set_end() noexcept { - // swap only works for strings - if (is_string()) - { - std::swap(*(m_value.string), other); - } - else - { - JSON_THROW(type_error::create(310, "cannot use swap() with " + type_name())); - } - } + assert(m_object != nullptr); - /// @} + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } - public: - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } - /// @name lexicographical comparison operators - /// @{ + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + public: /*! - @brief comparison: equal + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + assert(m_object != nullptr); - Compares two JSON values for equality according to the following rules: - - Two JSON values are equal if (1) they are from the same type and (2) - their stored values are the same according to their respective - `operator==`. - - Integer and floating-point numbers are automatically converted before - comparison. Floating-point numbers are compared indirectly: two - floating-point numbers `f1` and `f2` are considered equal if neither - `f1 > f2` nor `f2 > f1` holds. Note than two NaN values are always - treated as unequal. - - Two JSON null values are equal. + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } - @note NaN values never compare equal to themselves or to other NaN values. + case basic_json::value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are equal + case basic_json::value_t::null: + { + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } - @complexity Linear. + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__equal} + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } + } - @since version 1.0.0 + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept + pointer operator->() const { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); + assert(m_object != nullptr); - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array == *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object == *rhs.m_value.object; - } - case value_t::null: - { - return true; - } - case value_t::string: - { - return *lhs.m_value.string == *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean == rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer == rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float == rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case basic_json::value_t::array: + { + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + default: + { + if (m_it.primitive_iterator.is_begin()) { - return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + return m_object; } - return false; + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } } /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept + iter_impl operator++(int) { - return (lhs == basic_json(rhs)); + auto result = *this; + ++(*this); + return result; } /*! - @brief comparison: equal - @copydoc operator==(const_reference, const_reference) + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept + iter_impl & operator++() { - return (basic_json(lhs) == rhs); - } - - /*! - @brief comparison: not equal - - Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + assert(m_object != nullptr); - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether the values @a lhs and @a rhs are not equal + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } - @complexity Linear. + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__notequal} + default: + { + ++m_it.primitive_iterator; + break; + } + } - @since version 1.0.0 - */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); + return *this; } /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept + iter_impl operator--(int) { - return (lhs != basic_json(rhs)); + auto result = *this; + --(*this); + return result; } /*! - @brief comparison: not equal - @copydoc operator!=(const_reference, const_reference) + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept + iter_impl & operator--() { - return (basic_json(lhs) != rhs); - } - - /*! - @brief comparison: less than + assert(m_object != nullptr); - Compares whether one JSON value @a lhs is less than another JSON value @a - rhs according to the following rules: - - If @a lhs and @a rhs have the same type, the values are compared using - the default `<` operator. - - Integer and floating-point numbers are automatically converted before - comparison - - In case @a lhs and @a rhs have different types, the values are ignored - and the order of the types is considered, see - @ref operator<(const value_t, const value_t). + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than @a rhs + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } - @complexity Linear. + default: + { + --m_it.primitive_iterator; + break; + } + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__less} + return *this; + } - @since version 1.0.0 + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept + bool operator==(const iter_impl & other) const { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } - if (lhs_type == rhs_type) - { - switch (lhs_type) - { - case value_t::array: - { - return *lhs.m_value.array < *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object < *rhs.m_value.object; - } - case value_t::null: - { - return false; - } - case value_t::string: - { - return *lhs.m_value.string < *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean < rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer < rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float < rhs.m_value.number_float; - } - default: - { - return false; - } - } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } } /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept + bool operator!=(const iter_impl & other) const { - return (lhs < basic_json(rhs)); + return not operator==(other); } /*! - @brief comparison: less than - @copydoc operator<(const_reference, const_reference) + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept + bool operator<(const iter_impl & other) const { - return (basic_json(lhs) < rhs); - } + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); + } - /*! - @brief comparison: less than or equal - - Compares whether one JSON value @a lhs is less than or equal to another - JSON value by calculating `not (rhs < lhs)`. + assert(m_object != nullptr); - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is less than or equal to @a rhs + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); + } - @complexity Linear. + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__greater} + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + } - @since version 1.0.0 + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + bool operator<=(const iter_impl & other) const { - return not (rhs < lhs); + return not other.operator<(*this); } /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept + bool operator>(const iter_impl & other) const { - return (lhs <= basic_json(rhs)); + return not operator<=(other); } /*! - @brief comparison: less than or equal - @copydoc operator<=(const_reference, const_reference) + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept + bool operator>=(const iter_impl & other) const { - return (basic_json(lhs) <= rhs); + return not operator<(other); } /*! - @brief comparison: greater than + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl & operator+=(difference_type i) + { + assert(m_object != nullptr); - Compares whether one JSON value @a lhs is greater than another - JSON value by calculating `not (lhs <= rhs)`. + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + } - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than to @a rhs + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } - @complexity Linear. + default: + { + m_it.primitive_iterator += i; + break; + } + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__lessequal} + return *this; + } - @since version 1.0.0 + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept + iter_impl & operator-=(difference_type i) { - return not (lhs <= rhs); + return operator+=(-i); } /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept + iter_impl operator+(difference_type i) { - return (lhs > basic_json(rhs)); + auto result = *this; + result += i; + return result; } /*! - @brief comparison: greater than - @copydoc operator>(const_reference, const_reference) + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept + iter_impl operator-(difference_type i) { - return (basic_json(lhs) > rhs); + auto result = *this; + result -= i; + return result; } /*! - @brief comparison: greater than or equal - - Compares whether one JSON value @a lhs is greater than or equal to another - JSON value by calculating `not (lhs < rhs)`. + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl & other) const + { + assert(m_object != nullptr); - @param[in] lhs first JSON value to consider - @param[in] rhs second JSON value to consider - @return whether @a lhs is greater than or equal to @a rhs + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); + } - @complexity Linear. + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } - @liveexample{The example demonstrates comparing several JSON - types.,operator__greaterequal} + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + } - @since version 1.0.0 + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + reference operator[](difference_type n) const { - return not (lhs < rhs); + assert(m_object != nullptr); + + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); + } + + case basic_json::value_t::array: + { + return *std::next(m_it.array_iterator, n); + } + + case basic_json::value_t::null: + { + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + + default: + { + if (m_it.primitive_iterator.get_value() == -n) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value")); + } + } } /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept + typename object_t::key_type key() const { - return (lhs >= basic_json(rhs)); + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); } /*! - @brief comparison: greater than or equal - @copydoc operator>=(const_reference, const_reference) + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - template::value, int>::type = 0> - friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept + reference value() const { - return (basic_json(lhs) >= rhs); + return operator*(); } - /// @} - private: - ///////////////////// - // output adapters // - ///////////////////// + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; + + /*! + @brief a template for a reverse iterator class + + @tparam Base the base iterator type to reverse. Valid types are @ref + iterator (to create @ref reverse_iterator) and @ref const_iterator (to + create @ref const_reverse_iterator). + + @requirement The class satisfies the following concept requirements: + - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): + The iterator that can be moved to point (forward and backward) to any + element in constant time. + - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + + @since version 1.0.0 + */ + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; - /// abstract output adapter interface - template - class output_adapter + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type & it) noexcept + : base_iterator(it) { - public: - virtual void write_character(CharType c) = 0; - virtual void write_characters(const CharType* s, size_t length) = 0; - virtual ~output_adapter() {} - - static std::shared_ptr> create(std::vector& vec) - { - return std::shared_ptr(new output_vector_adapter(vec)); - } - - static std::shared_ptr> create(std::ostream& s) - { - return std::shared_ptr(new output_stream_adapter(s)); - } - - static std::shared_ptr> create(std::string& s) - { - return std::shared_ptr(new output_string_adapter(s)); - } - }; - - /// a type to simplify interfaces - template - using output_adapter_t = std::shared_ptr>; + } - /// output adapter for byte vectors - template - class output_vector_adapter : public output_adapter + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator & it) noexcept + : base_iterator(it) { - public: - output_vector_adapter(std::vector& vec) - : v(vec) - {} - - void write_character(CharType c) override - { - v.push_back(c); - } - - void write_characters(const CharType* s, size_t length) override - { - std::copy(s, s + length, std::back_inserter(v)); - } + } - private: - std::vector& v; - }; + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } - /// putput adatpter for output streams - template - class output_stream_adapter : public output_adapter + /// pre-increment (++it) + json_reverse_iterator & operator++() { - public: - output_stream_adapter(std::basic_ostream& s) - : stream(s) - {} + base_iterator::operator++(); + return *this; + } - void write_character(CharType c) override - { - stream.put(c); - } + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } - void write_characters(const CharType* s, size_t length) override - { - stream.write(s, static_cast(length)); - } + /// pre-decrement (--it) + json_reverse_iterator & operator--() + { + base_iterator::operator--(); + return *this; + } - private: - std::basic_ostream& stream; - }; + /// add to iterator + json_reverse_iterator & operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } - /// output adapter for basic_string - template - class output_string_adapter : public output_adapter + /// add to iterator + json_reverse_iterator operator+(difference_type i) const { - public: - output_string_adapter(std::string& s) - : str(s) - {} + auto result = *this; + result += i; + return result; + } - void write_character(CharType c) override - { - str.push_back(c); - } + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } - void write_characters(const CharType* s, size_t length) override - { - str.append(s, length); - } + /// return difference + difference_type operator-(const json_reverse_iterator & other) const + { + return this->base() - other.base(); + } - private: - std::basic_string& str; - }; + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } - /////////////////// - // serialization // - /////////////////// + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator*(); + } + }; - /// @name serialization - /// @{ +private: + //////////////////// + // input adapters // + //////////////////// - private: - /*! - @brief wrapper around the serialization functions - */ - class serializer + /// abstract input adapter interface + class input_adapter + { + public: + virtual int get_character() = 0; + virtual std::string read(size_t offset, size_t length) = 0; + virtual ~input_adapter() { - private: - serializer(const serializer&) = delete; - serializer& operator=(const serializer&) = delete; + } - public: - /*! - @param[in] s output stream to serialize to - @param[in] ichar indentation character to use - */ - serializer(output_adapter_t s, const char ichar) - : o(s), loc(std::localeconv()), - thousands_sep(!loc->thousands_sep ? '\0' : loc->thousands_sep[0]), - decimal_point(!loc->decimal_point ? '\0' : loc->decimal_point[0]), - indent_char(ichar), indent_string(512, indent_char) - {} - - /*! - @brief internal implementation of the serialization function - - This function is called by the public member function dump and - organizes the serialization internally. The indentation level is - propagated as additional parameter. In case of arrays and objects, the - function is called recursively. - - - strings and object keys are escaped using `escape_string()` - - integer numbers are converted implicitly via `operator<<` - - floating-point numbers are converted to a string using `"%g"` format - - @param[in] val value to serialize - @param[in] pretty_print whether the output shall be pretty-printed - @param[in] indent_step the indent level - @param[in] current_indent the current indent level (only used internally) - */ - void dump(const basic_json& val, - const bool pretty_print, - const unsigned int indent_step, - const unsigned int current_indent = 0) - { - switch (val.m_type) - { - case value_t::object: - { - if (val.m_value.object->empty()) - { - o->write_characters("{}", 2); - return; - } - - if (pretty_print) - { - o->write_characters("{\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (indent_string.size() < new_indent) - { - indent_string.resize(new_indent, ' '); - } - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first); - o->write_characters("\": ", 3); - dump(i->second, true, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(i != val.m_value.object->cend()); - o->write_characters(indent_string.c_str(), new_indent); - o->write_character('\"'); - dump_escaped(i->first); - o->write_characters("\": ", 3); - dump(i->second, true, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character('}'); - } - else - { - o->write_character('{'); - - // first n-1 elements - auto i = val.m_value.object->cbegin(); - for (size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) - { - o->write_character('\"'); - dump_escaped(i->first); - o->write_characters("\":", 2); - dump(i->second, false, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(i != val.m_value.object->cend()); - o->write_character('\"'); - dump_escaped(i->first); - o->write_characters("\":", 2); - dump(i->second, false, indent_step, current_indent); - - o->write_character('}'); - } - - return; - } + // native support - case value_t::array: - { - if (val.m_value.array->empty()) - { - o->write_characters("[]", 2); - return; - } - - if (pretty_print) - { - o->write_characters("[\n", 2); - - // variable to hold indentation for recursive calls - const auto new_indent = current_indent + indent_step; - if (indent_string.size() < new_indent) - { - indent_string.resize(new_indent, ' '); - } - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) - { - o->write_characters(indent_string.c_str(), new_indent); - dump(*i, true, indent_step, new_indent); - o->write_characters(",\n", 2); - } - - // last element - assert(not val.m_value.array->empty()); - o->write_characters(indent_string.c_str(), new_indent); - dump(val.m_value.array->back(), true, indent_step, new_indent); - - o->write_character('\n'); - o->write_characters(indent_string.c_str(), current_indent); - o->write_character(']'); - } - else - { - o->write_character('['); - - // first n-1 elements - for (auto i = val.m_value.array->cbegin(); i != val.m_value.array->cend() - 1; ++i) - { - dump(*i, false, indent_step, current_indent); - o->write_character(','); - } - - // last element - assert(not val.m_value.array->empty()); - dump(val.m_value.array->back(), false, indent_step, current_indent); - - o->write_character(']'); - } - - return; - } + /// input adapter for input stream + static std::shared_ptr create(std::istream & i, const size_t buffer_size = 16384) + { + return std::shared_ptr(new cached_input_stream_adapter(i, buffer_size)); + } - case value_t::string: - { - o->write_character('\"'); - dump_escaped(*val.m_value.string); - o->write_character('\"'); - return; - } + /// input adapter for input stream + static std::shared_ptr create(std::istream && i, const size_t buffer_size = 16384) + { + return std::shared_ptr(new cached_input_stream_adapter(i, buffer_size)); + } - case value_t::boolean: - { - if (val.m_value.boolean) - { - o->write_characters("true", 4); - } - else - { - o->write_characters("false", 5); - } - return; - } + /// input adapter for buffer + static std::shared_ptr create(const char * b, size_t l) + { + return std::shared_ptr(new input_buffer_adapter(b, l)); + } - case value_t::number_integer: - { - dump_integer(val.m_value.number_integer); - return; - } + // derived support - case value_t::number_unsigned: - { - dump_integer(val.m_value.number_unsigned); - return; - } + /// input adapter for string literal + template < + typename CharT, + typename std::enable_if< + std::is_pointer::value and std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + static std::shared_ptr create(CharT b) + { + return create(reinterpret_cast(b), std::strlen(reinterpret_cast(b))); + } - case value_t::number_float: - { - dump_float(val.m_value.number_float); - return; - } + /// input adapter for iterator range with contiguous storage + template < + class IteratorType, + typename std::enable_if< + std::is_same< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag>::value, + int>::type = 0> + static std::shared_ptr create(IteratorType first, IteratorType last) + { + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate( + first, + last, + std::pair(true, 0), + [&first](std::pair res, decltype(*first) val) { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }) + .first); + + // assertion to check that each element is 1 byte long + static_assert( + sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); + + return create(reinterpret_cast(&(*first)), static_cast(std::distance(first, last))); + } + + /// input adapter for array + template + static std::shared_ptr create(T (&array)[N]) + { + // delegate the call to the iterator-range overload + return create(std::begin(array), std::end(array)); + } + + /// input adapter for contiguous container + template < + class ContiguousContainer, + typename std::enable_if< + not std::is_pointer::value and + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits< + decltype(std::begin(std::declval()))>::iterator_category>::value, + int>::type = 0> + static std::shared_ptr create(const ContiguousContainer & c) + { + // delegate the call to the iterator-range overload + return create(std::begin(c), std::end(c)); + } + }; + + /// a type to simplify interfaces + using input_adapter_t = std::shared_ptr; + + /// input adapter for cached stream input + class cached_input_stream_adapter : public input_adapter + { + public: + cached_input_stream_adapter(std::istream & i, const size_t buffer_size) + : is(i) + , start_position(is.tellg()) + , buffer(buffer_size, '\0') + { + // immediately abort if stream is erroneous + if (JSON_UNLIKELY(i.fail())) + { + JSON_THROW(parse_error::create(111, 0, "bad input stream")); + } - case value_t::discarded: - { - o->write_characters("", 11); - return; - } + // initial fill + is.read(buffer.data(), static_cast(buffer.size())); + // store number of bytes in the buffer + fill_size = static_cast(is.gcount()); - case value_t::null: - { - o->write_characters("null", 4); - return; - } - } - } + // skip byte-order mark + if (fill_size >= 3 and buffer[0] == '\xEF' and buffer[1] == '\xBB' and buffer[2] == '\xBF') + { + buffer_pos += 3; + processed_chars += 3; + } + } - private: - /*! - @brief calculates the extra space to escape a JSON string + ~cached_input_stream_adapter() override + { + // clear stream flags + is.clear(); + // set stream after last processed char + is.seekg(start_position + static_cast(processed_chars - 1)); + } - @param[in] s the string to escape - @return the number of characters required to escape string @a s + int get_character() override + { + // check if refilling is necessary and possible + if (buffer_pos == fill_size and not eof) + { + // refill + is.read(buffer.data(), static_cast(buffer.size())); + // store number of bytes in the buffer + fill_size = static_cast(is.gcount()); - @complexity Linear in the length of string @a s. - */ - static std::size_t extra_space(const string_t& s) noexcept + // remember that filling did not yield new input + if (fill_size == 0) { - return std::accumulate(s.begin(), s.end(), size_t{}, - [](size_t res, typename string_t::value_type c) - { - switch (c) - { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - return res + 1; - } - - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x0b: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - { - // from c (1 byte) to \uxxxx (6 bytes) - return res + 5; - } - - default: - { - return res; - } - } - }); + eof = true; } - /*! - @brief dump escaped string + // the buffer is ready + buffer_pos = 0; + } - Escape a string by replacing certain special characters by a sequence - of an escape character (backslash) and another character and other - control characters by a sequence of "\u" followed by a four-digit hex - representation. The escaped string is written to output stream @a o. + ++processed_chars; + return eof ? std::char_traits::eof() : buffer[buffer_pos++] & 0xFF; + } - @param[in] s the string to escape + std::string read(size_t offset, size_t length) override + { + // create buffer + std::string result(length, '\0'); - @complexity Linear in the length of string @a s. - */ - void dump_escaped(const string_t& s) const - { - const auto space = extra_space(s); - if (space == 0) - { - o->write_characters(s.c_str(), s.size()); - return; - } + // save stream position + auto current_pos = is.tellg(); + // save stream flags + auto flags = is.rdstate(); - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; + // clear stream flags + is.clear(); + // set stream position + is.seekg(static_cast(offset)); + // read bytes + is.read(&result[0], static_cast(length)); - for (const auto& c : s) - { - switch (c) - { - // quotation mark (0x22) - case '"': - { - result[pos + 1] = '"'; - pos += 2; - break; - } - - // reverse solidus (0x5c) - case '\\': - { - // nothing to change - pos += 2; - break; - } - - // backspace (0x08) - case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } - - // formfeed (0x0c) - case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } - - // newline (0x0a) - case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } - - // carriage return (0x0d) - case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } - - // horizontal tab (0x09) - case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } - - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x0b: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - { - // convert a number 0..15 to its hex representation - // (0..f) - static const char hexify[16] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - - // print character c as \uxxxx - for (const char m : - { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] - }) - { - result[++pos] = m; - } - - ++pos; - break; - } - - default: - { - // all other characters are added as-is - result[pos++] = c; - break; - } - } - } + // reset stream position + is.seekg(current_pos); + // reset stream flags + is.setstate(flags); - assert(pos == s.size() + space); - o->write_characters(result.c_str(), result.size()); - } + return result; + } - /*! - @brief dump an integer + private: + /// the associated input stream + std::istream & is; - Dump a given integer to output stream @a o. Works internally with - @a number_buffer. + /// chars returned via get_character() + size_t processed_chars = 0; + /// chars processed in the current buffer + size_t buffer_pos = 0; - @param[in] x integer number (signed or unsigned) to dump - @tparam NumberType either @a number_integer_t or @a number_unsigned_t - */ - template::value or - std::is_same::value, int> = 0> - void dump_integer(NumberType x) - { - // special case for "0" - if (x == 0) - { - o->write_character('0'); - return; - } + /// whether stream reached eof + bool eof = false; + /// how many chars have been copied to the buffer by last (re)fill + size_t fill_size = 0; - const bool is_negative = x < 0; - size_t i = 0; + /// position of the stream when we started + const std::streampos start_position; - // spare 1 byte for '\0' - while (x != 0 and i < number_buffer.size() - 1) - { - const auto digit = std::labs(static_cast(x % 10)); - number_buffer[i++] = static_cast('0' + digit); - x /= 10; - } + /// internal buffer + std::vector buffer; + }; - // make sure the number has been processed completely - assert(x == 0); + /// input adapter for buffer input + class input_buffer_adapter : public input_adapter + { + public: + input_buffer_adapter(const char * b, size_t l) + : input_adapter() + , cursor(b) + , limit(b + l) + , start(b) + { + } - if (is_negative) - { - // make sure there is capacity for the '-' - assert(i < number_buffer.size() - 2); - number_buffer[i++] = '-'; - } + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter &) = delete; + input_buffer_adapter & operator=(input_buffer_adapter &) = delete; - std::reverse(number_buffer.begin(), number_buffer.begin() + i); - o->write_characters(number_buffer.data(), i); - } + int get_character() override + { + if (JSON_LIKELY(cursor < limit)) + { + return *(cursor++) & 0xFF; + } + else + { + return std::char_traits::eof(); + } + } - /*! - @brief dump a floating-point number + std::string read(size_t offset, size_t length) override + { + // avoid reading too many characters + const size_t max_length = static_cast(limit - start); + return std::string(start + offset, std::min(length, max_length - offset)); + } - Dump a given floating-point number to output stream @a o. Works - internally with @a number_buffer. + private: + /// pointer to the current character + const char * cursor; + /// pointer past the last character + const char * limit; + /// pointer to the first character + const char * start; + }; + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + +private: + /*! + @brief deserialization of CBOR and MessagePack values + */ + class binary_reader + { + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(input_adapter_t adapter) + : ia(adapter) + , is_little_endian(little_endianess()) + { + assert(ia); + } + + /*! + @brief create a JSON value from CBOR input + + @param[in] get_char whether a new character should be retrieved from + the input (true, default) or whether the last + read character should be considered instead + + @return JSON value created from CBOR input + + @throw parse_error.110 if input ended unexpectedly + @throw parse_error.112 if unsupported byte was read + */ + basic_json parse_cbor(const bool get_char = true) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + { + return static_cast(current); + } + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + return get_number(); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + return get_number(); + } + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + return get_number(); + } + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + return get_number(); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + { + return static_cast(0x20 - 1 - current); + } + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + // must be uint8_t ! + return static_cast(-1) - get_number(); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + return static_cast(-1) - get_number(); + } + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + return static_cast(-1) - static_cast(get_number()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7f: // UTF-8 string (indefinite length) + { + return get_cbor_string(); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + { + basic_json result = value_t::array; + const auto len = static_cast(current & 0x1f); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_cbor()); + } + return result; + } - @param[in] x floating-point number to dump - */ - void dump_float(number_float_t x) + case 0x98: // array (one-byte uint8_t for n follows) + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) { - // NaN / inf - if (not std::isfinite(x) or std::isnan(x)) - { - o->write_characters("null", 4); - return; - } - - // special case for 0.0 and -0.0 - if (x == 0) - { - if (std::signbit(x)) - { - o->write_characters("-0.0", 4); - } - else - { - o->write_characters("0.0", 3); - } - return; - } + result.push_back(parse_cbor()); + } + return result; + } - // get number of digits for a text -> float -> text round-trip - static constexpr auto d = std::numeric_limits::digits10; + case 0x99: // array (two-byte uint16_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_cbor()); + } + return result; + } - // the actual conversion - std::ptrdiff_t len = snprintf(number_buffer.data(), number_buffer.size(), - "%.*g", d, x); + case 0x9a: // array (four-byte uint32_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_cbor()); + } + return result; + } - // negative value indicates an error - assert(len > 0); - // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); + case 0x9b: // array (eight-byte uint64_t for n follow) + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_cbor()); + } + return result; + } - // erase thousands separator - if (thousands_sep != '\0') - { - const auto end = std::remove(number_buffer.begin(), - number_buffer.begin() + len, - thousands_sep); - std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); - len = (end - number_buffer.begin()); - } + case 0x9f: // array (indefinite length) + { + basic_json result = value_t::array; + while (get() != 0xff) + { + result.push_back(parse_cbor(false)); + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case 0xa0: + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + { + basic_json result = value_t::object; + const auto len = static_cast(current & 0x1f); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_cbor_string(); + result[key] = parse_cbor(); + } + return result; + } - // convert decimal point to '.' - if (decimal_point != '\0' and decimal_point != '.') - { - for (auto& c : number_buffer) - { - if (c == decimal_point) - { - c = '.'; - break; - } - } - } + case 0xb8: // map (one-byte uint8_t for n follows) + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_cbor_string(); + result[key] = parse_cbor(); + } + return result; + } - o->write_characters(number_buffer.data(), static_cast(len)); + case 0xb9: // map (two-byte uint16_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_cbor_string(); + result[key] = parse_cbor(); + } + return result; + } - // determine if need to append ".0" - const bool value_is_int_like = std::none_of(number_buffer.begin(), - number_buffer.begin() + len + 1, - [](char c) - { - return c == '.' or c == 'e'; - }); + case 0xba: // map (four-byte uint32_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_cbor_string(); + result[key] = parse_cbor(); + } + return result; + } - if (value_is_int_like) - { - o->write_characters(".0", 2); - } + case 0xbb: // map (eight-byte uint64_t for n follow) + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_cbor_string(); + result[key] = parse_cbor(); } + return result; + } - private: - /// the output of the serializer - output_adapter_t o = nullptr; + case 0xbf: // map (indefinite length) + { + basic_json result = value_t::object; + while (get() != 0xff) + { + auto key = get_cbor_string(); + result[key] = parse_cbor(); + } + return result; + } - /// a (hopefully) large enough character buffer - std::array number_buffer{{}}; + case 0xf4: // false + { + return false; + } + + case 0xf5: // true + { + return true; + } + + case 0xf6: // null + { + return value_t::null; + } + + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + { + const int byte1 = get(); + check_eof(); + const int byte2 = get(); + check_eof(); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const int half = (byte1 << 8) + byte2; + const int exp = (half >> 10) & 0x1f; + const int mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = std::ldexp(mant, -24); + } + else if (exp != 31) + { + val = std::ldexp(mant + 1024, exp - 25); + } + else + { + val = mant == 0 ? std::numeric_limits::infinity() : std::numeric_limits::quiet_NaN(); + } + return (half & 0x8000) != 0 ? -val : val; + } + + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + { + return get_number(); + } + + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + return get_number(); + } + + default: // anything else (0xFF is handled inside the other types) + { + std::stringstream ss; + ss << std::setw(2) << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief create a JSON value from MessagePack input + + @return JSON value created from MessagePack input + + @throw parse_error.110 if input ended unexpectedly + @throw parse_error.112 if unsupported byte was read + */ + basic_json parse_msgpack() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + case 0x7f: + { + return static_cast(current); + } + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + { + basic_json result = value_t::object; + const auto len = static_cast(current & 0x0f); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_msgpack_string(); + result[key] = parse_msgpack(); + } + return result; + } + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + { + basic_json result = value_t::array; + const auto len = static_cast(current & 0x0f); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_msgpack()); + } + return result; + } + + // fixstr + case 0xa0: + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + { + return get_msgpack_string(); + } + + case 0xc0: // nil + { + return value_t::null; + } + + case 0xc2: // false + { + return false; + } + + case 0xc3: // true + { + return true; + } + + case 0xca: // float 32 + { + return get_number(); + } + + case 0xcb: // float 64 + { + return get_number(); + } + + case 0xcc: // uint 8 + { + return get_number(); + } + + case 0xcd: // uint 16 + { + return get_number(); + } + + case 0xce: // uint 32 + { + return get_number(); + } + + case 0xcf: // uint 64 + { + return get_number(); + } + + case 0xd0: // int 8 + { + return get_number(); + } + + case 0xd1: // int 16 + { + return get_number(); + } + + case 0xd2: // int 32 + { + return get_number(); + } + + case 0xd3: // int 64 + { + return get_number(); + } + + case 0xd9: // str 8 + case 0xda: // str 16 + case 0xdb: // str 32 + { + return get_msgpack_string(); + } + + case 0xdc: // array 16 + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_msgpack()); + } + return result; + } - /// the locale - const std::lconv* loc = nullptr; - /// the locale's thousand separator character - const char thousands_sep = '\0'; - /// the locale's decimal point character - const char decimal_point = '\0'; + case 0xdd: // array 32 + { + basic_json result = value_t::array; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + result.push_back(parse_msgpack()); + } + return result; + } - /// the indentation character - const char indent_char; + case 0xde: // map 16 + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_msgpack_string(); + result[key] = parse_msgpack(); + } + return result; + } - /// the indentation string - string_t indent_string; - }; + case 0xdf: // map 32 + { + basic_json result = value_t::object; + const auto len = static_cast(get_number()); + for (size_t i = 0; i < len; ++i) + { + get(); + auto key = get_msgpack_string(); + result[key] = parse_msgpack(); + } + return result; + } + + // positive fixint + case 0xe0: + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe6: + case 0xe7: + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xed: + case 0xee: + case 0xef: + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + case 0xfc: + case 0xfd: + case 0xfe: + case 0xff: + { + return static_cast(current); + } + + default: // anything else + { + std::stringstream ss; + ss << std::setw(2) << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief determine system byte order + + @return true iff system's byte order is little endian + + @note from http://stackoverflow.com/a/1001328/266378 + */ + static bool little_endianess() noexcept + { + int num = 1; + return (*reinterpret_cast(&num) == 1); + } - public: + private: /*! - @brief serialize to stream + @brief get next character from the input - Serialize the given JSON value @a j to the output stream @a o. The JSON - value will be serialized using the @ref dump member function. + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns + `std::char_traits::eof()` in that case. - - The indentation of the output can be controlled with the member variable - `width` of the output stream @a o. For instance, using the manipulator - `std::setw(4)` on @a o sets the indentation level to `4` and the - serialization result is the same as calling `dump(4)`. - - - The indentation characrer can be controlled with the member variable - `fill` of the output stream @a o. For instance, the manipulator - `std::setfill('\\t')` sets indentation to use a tab character rather than - the default space character. + @return character read from the input + */ + int get() + { + ++chars_read; + return (current = ia->get_character()); + } - @param[in,out] o stream to serialize to - @param[in] j JSON value to serialize + /* + @brief read a number from the input - @return the stream @a o + @tparam T the type of the number - @complexity Linear. + @return number of type @a T - @liveexample{The example below shows the serialization with different - parameters to `width` to adjust the indentation level.,operator_serialize} + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. - @since version 1.0.0; indentaction character added in version 3.0.0 + @throw parse_error.110 if input has less than `sizeof(T)` bytes */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + template + T get_number() { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // do the actual serialization - serializer s(output_adapter::create(o), o.fill()); - s.dump(j, pretty_print, static_cast(indentation)); - return o; - } + // step 1: read input into array with system's byte order + std::array vec; + for (size_t i = 0; i < sizeof(T); ++i) + { + get(); + check_eof(); - /*! - @brief serialize to stream - @deprecated This stream operator is deprecated and will be removed in a - future version of the library. Please use - @ref std::ostream& operator<<(std::ostream&, const basic_json&) - instead; that is, replace calls like `j >> o;` with `o << j;`. - */ - JSON_DEPRECATED - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + vec[sizeof(T) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); + } + } + + // step 2: convert array into number of type T and return + T result; + std::memcpy(&result, vec.data(), sizeof(T)); + return result; + } + + /*! + @brief create a string by reading characters from the input + + @param[in] len number of bytes to read + + @return string created by reading @a len bytes + + @throw parse_error.110 if input has less than @a len bytes + */ + std::string get_string(const size_t len) + { + std::string result; + for (size_t i = 0; i < len; ++i) + { + get(); + check_eof(); + result.append(1, static_cast(current)); + } + return result; + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpexted byte is read + */ + std::string get_cbor_string() + { + check_eof(); + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + const auto len = static_cast(current & 0x1f); + return get_string(len); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0x7f: // UTF-8 string (indefinite length) + { + std::string result; + while (get() != 0xff) + { + check_eof(); + result.append(1, static_cast(current)); + } + return result; + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @return string + + @throw parse_error.110 if input ended + @throw parse_error.113 if an unexpexted byte is read + */ + std::string get_msgpack_string() + { + check_eof(); + + switch (current) + { + // fixstr + case 0xa0: + case 0xa1: + case 0xa2: + case 0xa3: + case 0xa4: + case 0xa5: + case 0xa6: + case 0xa7: + case 0xa8: + case 0xa9: + case 0xaa: + case 0xab: + case 0xac: + case 0xad: + case 0xae: + case 0xaf: + case 0xb0: + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + case 0xb7: + case 0xb8: + case 0xb9: + case 0xba: + case 0xbb: + case 0xbc: + case 0xbd: + case 0xbe: + case 0xbf: + { + const auto len = static_cast(current & 0x1f); + return get_string(len); + } + + case 0xd9: // str 8 + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0xda: // str 16 + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + case 0xdb: // str 32 + { + const auto len = static_cast(get_number()); + return get_string(len); + } + + default: + { + std::stringstream ss; + ss << std::setw(2) << std::setfill('0') << std::hex << current; + JSON_THROW(parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + ss.str())); + } + } + } + + /*! + @brief check if input ended + @throw parse_error.110 if input ended + */ + void check_eof() const + { + if (JSON_UNLIKELY(current == std::char_traits::eof())) + { + JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); + } } - /// @} + private: + /// input adapter + input_adapter_t ia = nullptr; + /// the current character + int current = std::char_traits::eof(); - ///////////////////// - // deserialization // - ///////////////////// + /// the number of characters read + size_t chars_read = 0; - /// @name deserialization - /// @{ + /// whether we can assume little endianess + const bool is_little_endian = true; + }; + /*! + @brief serialization to CBOR and MessagePack values + */ + class binary_writer + { + public: /*! - @brief deserialize from an array - - This function reads from an array of 1-byte values. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @param[in] array array to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) + : is_little_endian(binary_reader::little_endianess()) + , oa(adapter) + { + assert(oa); + } + + /*! + @brief[in] j JSON value to serialize + */ + void write_cbor(const basic_json & j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(0xf6); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean ? 0xf5 : 0xf4); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(0x18); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(0x19); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(0x1a); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(0x1b); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(0x38); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(0x39); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(0x3a); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(0x3b); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(0x18); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(0x19); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(0x1a); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(0x1b); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } - @return result of the deserialization + case value_t::number_float: + { + // Double-Precision Float + oa->write_character(0xfb); + write_number(j.m_value.number_float); + break; + } - @throw parse_error.101 if a parse error occurs; example: `""unexpected end - of input; expected string literal""` - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an array.,parse__array__parser_callback_t} - - @since version 2.0.3 - */ - template - static basic_json parse(T (&array)[N], - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(array), std::end(array), cb); - } - - /*! - @brief deserialize from string literal - - @tparam CharT character/literal type with size of 1 byte - @param[in] s string literal to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - @note String containers like `std::string` or @ref string_t can be parsed - with @ref parse(const ContiguousContainer&, const parser_callback_t) - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__string__parser_callback_t} - - @sa @ref parse(std::istream&, const parser_callback_t) for a version that - reads from an input stream - - @since version 1.0.0 (originally for @ref string_t) - */ - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> - static basic_json parse(const CharT s, - const parser_callback_t cb = nullptr) - { - return parser(input_adapter::create(s), cb).parse(true); - } - - /*! - @brief deserialize from stream - - @param[in,out] i stream to read a serialized JSON value from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - @throw parse_error.111 if input stream is in a bad state - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function with - and without callback function.,parse__istream__parser_callback_t} - - @sa @ref parse(const CharT, const parser_callback_t) for a version - that reads from a string - - @since version 1.0.0 - */ - static basic_json parse(std::istream& i, - const parser_callback_t cb = nullptr) - { - return parser(input_adapter::create(i), cb).parse(true); - } - - /*! - @copydoc parse(std::istream&, const parser_callback_t) - */ - static basic_json parse(std::istream&& i, - const parser_callback_t cb = nullptr) - { - return parser(input_adapter::create(i), cb).parse(true); - } - - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr) - { - return parser(input_adapter::create(first, last), cb).parse(true); - } - - /*! - @brief deserialize from a container with contiguous storage - - This function reads from a container with contiguous storage of 1-byte - values. Compatible container types include `std::vector`, `std::string`, - `std::array`, and `std::initializer_list`. User-defined containers can be - used as long as they implement random-access iterators and a contiguous - storage. - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam ContiguousContainer container type with contiguous storage - @param[in] c container to read from - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - - @return result of the deserialization - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from a contiguous container.,parse__contiguouscontainer__parser_callback_t} - - @since version 2.0.3 - */ - template::value and - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits()))>::iterator_category>::value - , int>::type = 0> - static basic_json parse(const ContiguousContainer& c, - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(c), std::end(c), cb); - } - - /*! - @brief deserialize from stream - @deprecated This stream operator is deprecated and will be removed in a - future version of the library. Please use - @ref std::istream& operator>>(std::istream&, basic_json&) - instead; that is, replace calls like `j << i;` with `i >> j;`. - */ - JSON_DEPRECATED - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(input_adapter::create(i)).parse(false); - return i; - } - - /*! - @brief deserialize from stream - - Deserializes an input stream to a JSON value. - - @param[in,out] i input stream to read a serialized JSON value from - @param[in,out] j JSON value to write the deserialized input to - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - @throw parse_error.111 if input stream is in a bad state - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below shows how a JSON value is constructed by - reading a serialization from a stream.,operator_deserialize} - - @sa parse(std::istream&, const parser_callback_t) for a variant with a - parser callback function to filter values while parsing - - @since version 1.0.0 - */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - j = parser(input_adapter::create(i)).parse(false); - return i; - } - - /// @} - - /////////////////////////// - // convenience functions // - /////////////////////////// - - /*! - @brief return the type as string - - Returns the type name as string to be used in error messages - usually to - indicate that a function was called on a wrong JSON type. - - @return basically a string representation of a the @a m_type member - - @complexity Constant. - - @liveexample{The following code exemplifies `type_name()` for all JSON - types.,type_name} - - @since version 1.0.0, public since 2.1.0 - */ - std::string type_name() const - { - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; - } - } - } - - - private: - ////////////////////// - // member variables // - ////////////////////// - - /// the type of the current element - value_t m_type = value_t::null; - - /// the value of the current element - json_value m_value = {}; - - - private: - /////////////// - // iterators // - /////////////// - - /*! - @brief an iterator for primitive JSON types - - This class models an iterator for primitive JSON types (boolean, number, - string). It's only purpose is to allow the iterator/const_iterator classes - to "iterate" over primitive values. Internally, the iterator is modeled by - a `difference_type` variable. Value begin_value (`0`) models the begin, - end_value (`1`) models past the end. - */ - class primitive_iterator_t - { - public: - - difference_type get_value() const noexcept - { - return m_it; - } - /// set iterator to a defined beginning - void set_begin() noexcept - { - m_it = begin_value; - } - - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } - - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return (m_it == begin_value); - } - - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return (m_it == end_value); - } - - friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it == rhs.m_it; - } - - friend constexpr bool operator!=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return !(lhs == rhs); - } - - friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it < rhs.m_it; - } - - friend constexpr bool operator<=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it <= rhs.m_it; - } - - friend constexpr bool operator>(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it > rhs.m_it; - } - - friend constexpr bool operator>=(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it >= rhs.m_it; - } - - primitive_iterator_t operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept - { - return lhs.m_it - rhs.m_it; - } - - friend std::ostream& operator<<(std::ostream& os, primitive_iterator_t it) - { - return os << it.m_it; - } - - primitive_iterator_t& operator++() - { - ++m_it; - return *this; - } - - primitive_iterator_t operator++(int) - { - auto result = *this; - m_it++; - return result; - } - - primitive_iterator_t& operator--() - { - --m_it; - return *this; - } - - primitive_iterator_t operator--(int) - { - auto result = *this; - m_it--; - return result; - } - - primitive_iterator_t& operator+=(difference_type n) - { - m_it += n; - return *this; - } - - primitive_iterator_t& operator-=(difference_type n) - { - m_it -= n; - return *this; - } - - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; - - /// iterator as signed integer type - difference_type m_it = std::numeric_limits::denorm_min(); - }; - - /*! - @brief an iterator value - - @note This structure could easily be a union, but MSVC currently does not - allow unions members with complex constructors, see - https://github.com/nlohmann/json/pull/105. - */ - struct internal_iterator - { - /// iterator for JSON objects - typename object_t::iterator object_iterator; - /// iterator for JSON arrays - typename array_t::iterator array_iterator; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator; - - /// create an uninitialized internal_iterator - internal_iterator() noexcept - : object_iterator(), array_iterator(), primitive_iterator() - {} - }; - - /// proxy class for the iterator_wrapper functions - template - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept - : anchor(it) - {} - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) const - { - return anchor != o.anchor; - } - - /// return key of the iterator - typename basic_json::string_t key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } - - // use key from the object - case value_t::object: - { - return anchor.key(); - } - - // use an empty key for all primitive types - default: - { - return ""; - } - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } - }; - - public: - /*! - @brief a template for a random access iterator for the @ref basic_json class - - This class implements a both iterators (iterator and const_iterator) for the - @ref basic_json class. - - @note An iterator is called *initialized* when a pointer to a JSON value - has been set (e.g., by a constructor or a copy assignment). If the - iterator is default-constructed, it is *uninitialized* and most - methods are undefined. **The library uses assertions to detect calls - on uninitialized iterators.** - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - @since version 1.0.0, simplified in version 2.0.9 - */ - template - class iter_impl : public std::iterator - { - /// allow basic_json to access private members - friend class basic_json; - - // make sure U is basic_json or const basic_json - static_assert(std::is_same::value - or std::is_same::value, - "iter_impl only accepts (const) basic_json"); - - public: - /// the type of the values when the iterator is dereferenced - using value_type = typename basic_json::value_type; - /// a type to represent differences between iterators - using difference_type = typename basic_json::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename std::conditional::value, - typename basic_json::const_pointer, - typename basic_json::pointer>::type; - /// defines a reference to the type iterated over (value_type) - using reference = typename std::conditional::value, - typename basic_json::const_reference, - typename basic_json::reference>::type; - /// the category of the iterator - using iterator_category = std::bidirectional_iterator_tag; - - /// default constructor - iter_impl() = default; - - /*! - @brief constructor for a given JSON instance - @param[in] object pointer to a JSON object for this iterator - @pre object != nullptr - @post The iterator is initialized; i.e. `m_object != nullptr`. - */ - explicit iter_impl(pointer object) noexcept - : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } - - /* - Use operator `const_iterator` instead of `const_iterator(const iterator& - other) noexcept` to avoid two class definitions for @ref iterator and - @ref const_iterator. - - This function is only called if this class is an @ref iterator. If this - class is a @ref const_iterator this function is not called. - */ - operator const_iterator() const - { - const_iterator ret; - - if (m_object) - { - ret.m_object = m_object; - ret.m_it = m_it; - } - - return ret; - } - - /*! - @brief copy constructor - @param[in] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl(const iter_impl& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} - - /*! - @brief copy assignment - @param[in,out] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - iter_impl& operator=(iter_impl other) noexcept( - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value and - std::is_nothrow_move_constructible::value and - std::is_nothrow_move_assignable::value - ) - { - std::swap(m_object, other.m_object); - std::swap(m_it, other.m_it); - return *this; - } - - private: - /*! - @brief set the iterator to the first value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } - - case basic_json::value_t::null: - { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } - - default: - { - m_it.primitive_iterator.set_begin(); - break; - } - } - } - - /*! - @brief set the iterator past the last value - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } - - default: - { - m_it.primitive_iterator.set_end(); - break; - } - } - } - - public: - /*! - @brief return a reference to the value pointed to by the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } - - case basic_json::value_t::null: - { - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief dereference the iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } - - default: - { - if (m_it.primitive_iterator.is_begin()) - { - return m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief post-increment (it++) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator++(int) - { - auto result = *this; - ++(*this); - return result; - } - - /*! - @brief pre-increment (++it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, 1); - break; - } - - default: - { - ++m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief post-decrement (it--) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator--(int) - { - auto result = *this; - --(*this); - return result; - } - - /*! - @brief pre-decrement (--it) - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, -1); - break; - } - - default: - { - --m_it.primitive_iterator; - break; - } - } - - return *this; - } - - /*! - @brief comparison: equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator==(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - return (m_it.object_iterator == other.m_it.object_iterator); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator == other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator == other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: not equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator!=(const iter_impl& other) const - { - return not operator==(other); - } - - /*! - @brief comparison: smaller - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<(const iter_impl& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators")); - } - - case basic_json::value_t::array: - { - return (m_it.array_iterator < other.m_it.array_iterator); - } - - default: - { - return (m_it.primitive_iterator < other.m_it.primitive_iterator); - } - } - } - - /*! - @brief comparison: less than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator<=(const iter_impl& other) const - { - return not other.operator < (*this); - } - - /*! - @brief comparison: greater than - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>(const iter_impl& other) const - { - return not operator<=(other); - } - - /*! - @brief comparison: greater than or equal - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - bool operator>=(const iter_impl& other) const - { - return not operator<(other); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - } - - case basic_json::value_t::array: - { - std::advance(m_it.array_iterator, i); - break; - } - - default: - { - m_it.primitive_iterator += i; - break; - } - } - - return *this; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl& operator-=(difference_type i) - { - return operator+=(-i); - } - - /*! - @brief add to iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } - - /*! - @brief subtract from iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - iter_impl operator-(difference_type i) - { - auto result = *this; - result -= i; - return result; - } - - /*! - @brief return difference - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - difference_type operator-(const iter_impl& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators")); - } - - case basic_json::value_t::array: - { - return m_it.array_iterator - other.m_it.array_iterator; - } - - default: - { - return m_it.primitive_iterator - other.m_it.primitive_iterator; - } - } - } - - /*! - @brief access to successor - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: - { - JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators")); - } - - case basic_json::value_t::array: - { - return *std::next(m_it.array_iterator, n); - } - - case basic_json::value_t::null: - { - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - - default: - { - if (m_it.primitive_iterator.get_value() == -n) - { - return *m_object; - } - - JSON_THROW(invalid_iterator::create(214, "cannot get value")); - } - } - } - - /*! - @brief return the key of an object iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (m_object->is_object()) - { - return m_it.object_iterator->first; - } - - JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators")); - } - - /*! - @brief return the value of an iterator - @pre The iterator is initialized; i.e. `m_object != nullptr`. - */ - reference value() const - { - return operator*(); - } - - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator m_it = internal_iterator(); - }; - - /*! - @brief a template for a reverse iterator class - - @tparam Base the base iterator type to reverse. Valid types are @ref - iterator (to create @ref reverse_iterator) and @ref const_iterator (to - create @ref const_reverse_iterator). - - @requirement The class satisfies the following concept requirements: - - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - The iterator that can be moved to point (forward and backward) to any - element in constant time. - - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - It is possible to write to the pointed-to element (only if @a Base is - @ref iterator). - - @since version 1.0.0 - */ - template - class json_reverse_iterator : public std::reverse_iterator - { - public: - /// shortcut to the reverse iterator adaptor - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; - - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) - {} - - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept - : base_iterator(it) - {} - - /// post-increment (it++) - json_reverse_iterator operator++(int) - { - return base_iterator::operator++(1); - } - - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - base_iterator::operator++(); - return *this; - } - - /// post-decrement (it--) - json_reverse_iterator operator--(int) - { - return base_iterator::operator--(1); - } - - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - base_iterator::operator--(); - return *this; - } - - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - base_iterator::operator+=(i); - return *this; - } - - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } - - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } - - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return this->base() - other.base(); - } - - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } - - /// return the key of an object iterator - typename object_t::key_type key() const - { - auto it = --this->base(); - return it.key(); - } - - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } - }; - - - private: - //////////////////// - // input adapters // - //////////////////// - - /// abstract input adapter interface - class input_adapter - { - public: - virtual int get_character() = 0; - virtual std::string read(size_t offset, size_t length) = 0; - virtual ~input_adapter() {} - - // native support - - /// input adapter for input stream - static std::shared_ptr create(std::istream& i, const size_t buffer_size = 16384) - { - return std::shared_ptr(new cached_input_stream_adapter(i, buffer_size)); - } - - /// input adapter for input stream - static std::shared_ptr create(std::istream&& i, const size_t buffer_size = 16384) - { - return std::shared_ptr(new cached_input_stream_adapter(i, buffer_size)); - } - - /// input adapter for buffer - static std::shared_ptr create(const char* b, size_t l) - { - return std::shared_ptr(new input_buffer_adapter(b, l)); - } - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> - static std::shared_ptr create(CharT b) - { - return create(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))); - } - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value - , int>::type - = 0> - static std::shared_ptr create(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate(first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert(sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - return create(reinterpret_cast(&(*first)), - static_cast(std::distance(first, last))); - } - - /// input adapter for array - template - static std::shared_ptr create(T (&array)[N]) - { - // delegate the call to the iterator-range overload - return create(std::begin(array), std::end(array)); - } - - /// input adapter for contiguous container - template::value and - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits()))>::iterator_category>::value - , int>::type = 0> - static std::shared_ptr create(const ContiguousContainer& c) - { - // delegate the call to the iterator-range overload - return create(std::begin(c), std::end(c)); - } - }; - - /// a type to simplify interfaces - using input_adapter_t = std::shared_ptr; - - /// input adapter for cached stream input - class cached_input_stream_adapter : public input_adapter - { - public: - cached_input_stream_adapter(std::istream& i, const size_t buffer_size) - : is(i), start_position(is.tellg()), buffer(buffer_size, '\0') - { - // immediately abort if stream is erroneous - if (JSON_UNLIKELY(i.fail())) - { - JSON_THROW(parse_error::create(111, 0, "bad input stream")); - } - - // initial fill - is.read(buffer.data(), static_cast(buffer.size())); - // store number of bytes in the buffer - fill_size = static_cast(is.gcount()); - - // skip byte-order mark - if (fill_size >= 3 and buffer[0] == '\xEF' and buffer[1] == '\xBB' and buffer[2] == '\xBF') - { - buffer_pos += 3; - processed_chars += 3; - } - } - - ~cached_input_stream_adapter() override - { - // clear stream flags - is.clear(); - // set stream after last processed char - is.seekg(start_position + static_cast(processed_chars - 1)); - } - - int get_character() override - { - // check if refilling is necessary and possible - if (buffer_pos == fill_size and not eof) - { - // refill - is.read(buffer.data(), static_cast(buffer.size())); - // store number of bytes in the buffer - fill_size = static_cast(is.gcount()); - - // remember that filling did not yield new input - if (fill_size == 0) - { - eof = true; - } - - // the buffer is ready - buffer_pos = 0; - } - - ++processed_chars; - return eof - ? std::char_traits::eof() - : buffer[buffer_pos++] & 0xFF; - } - - std::string read(size_t offset, size_t length) override - { - // create buffer - std::string result(length, '\0'); - - // save stream position - auto current_pos = is.tellg(); - // save stream flags - auto flags = is.rdstate(); - - // clear stream flags - is.clear(); - // set stream position - is.seekg(static_cast(offset)); - // read bytes - is.read(&result[0], static_cast(length)); - - // reset stream position - is.seekg(current_pos); - // reset stream flags - is.setstate(flags); - - return result; - } - - private: - /// the associated input stream - std::istream& is; - - /// chars returned via get_character() - size_t processed_chars = 0; - /// chars processed in the current buffer - size_t buffer_pos = 0; - - /// whether stream reached eof - bool eof = false; - /// how many chars have been copied to the buffer by last (re)fill - size_t fill_size = 0; - - /// position of the stream when we started - const std::streampos start_position; - - /// internal buffer - std::vector buffer; - }; - - /// input adapter for buffer input - class input_buffer_adapter : public input_adapter - { - public: - input_buffer_adapter(const char* b, size_t l) - : input_adapter(), cursor(b), limit(b + l), start(b) - {} - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - int get_character() override - { - if (JSON_LIKELY(cursor < limit)) - { - return *(cursor++) & 0xFF; - } - else - { - return std::char_traits::eof(); - } - } - - std::string read(size_t offset, size_t length) override - { - // avoid reading too many characters - const size_t max_length = static_cast(limit - start); - return std::string(start + offset, std::min(length, max_length - offset)); - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* limit; - /// pointer to the first character - const char* start; - }; - - ////////////////////////////////////////// - // binary serialization/deserialization // - ////////////////////////////////////////// - - /// @name binary serialization/deserialization support - /// @{ - - private: - /*! - @brief deserialization of CBOR and MessagePack values - */ - class binary_reader - { - public: - /*! - @brief create a binary reader - - @param[in] adapter input adapter to read from - */ - explicit binary_reader(input_adapter_t adapter) - : ia(adapter), is_little_endian(little_endianess()) - { - assert(ia); - } - - /*! - @brief create a JSON value from CBOR input - - @param[in] get_char whether a new character should be retrieved from - the input (true, default) or whether the last - read character should be considered instead - - @return JSON value created from CBOR input - - @throw parse_error.110 if input ended unexpectedly - @throw parse_error.112 if unsupported byte was read - */ - basic_json parse_cbor(const bool get_char = true) - { - switch (get_char ? get() : current) - { - // EOF - case std::char_traits::eof(): - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - - // Integer 0x00..0x17 (0..23) - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - { - return static_cast(current); - } - - case 0x18: // Unsigned integer (one-byte uint8_t follows) - { - return get_number(); - } - - case 0x19: // Unsigned integer (two-byte uint16_t follows) - { - return get_number(); - } - - case 0x1a: // Unsigned integer (four-byte uint32_t follows) - { - return get_number(); - } - - case 0x1b: // Unsigned integer (eight-byte uint64_t follows) - { - return get_number(); - } - - // Negative integer -1-0x00..-1-0x17 (-1..-24) - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - { - return static_cast(0x20 - 1 - current); - } - - case 0x38: // Negative integer (one-byte uint8_t follows) - { - // must be uint8_t ! - return static_cast(-1) - get_number(); - } - - case 0x39: // Negative integer -1-n (two-byte uint16_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) - { - return static_cast(-1) - get_number(); - } - - case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) - { - return static_cast(-1) - static_cast(get_number()); - } - - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) - case 0x7f: // UTF-8 string (indefinite length) - { - return get_cbor_string(); - } - - // array (0x00..0x17 data items follow) - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - { - basic_json result = value_t::array; - const auto len = static_cast(current & 0x1f); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_cbor()); - } - return result; - } - - case 0x98: // array (one-byte uint8_t for n follows) - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_cbor()); - } - return result; - } - - case 0x99: // array (two-byte uint16_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_cbor()); - } - return result; - } - - case 0x9a: // array (four-byte uint32_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_cbor()); - } - return result; - } - - case 0x9b: // array (eight-byte uint64_t for n follow) - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_cbor()); - } - return result; - } - - case 0x9f: // array (indefinite length) - { - basic_json result = value_t::array; - while (get() != 0xff) - { - result.push_back(parse_cbor(false)); - } - return result; - } - - // map (0x00..0x17 pairs of data items follow) - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - { - basic_json result = value_t::object; - const auto len = static_cast(current & 0x1f); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xb8: // map (one-byte uint8_t for n follows) - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xb9: // map (two-byte uint16_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xba: // map (four-byte uint32_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xbb: // map (eight-byte uint64_t for n follow) - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xbf: // map (indefinite length) - { - basic_json result = value_t::object; - while (get() != 0xff) - { - auto key = get_cbor_string(); - result[key] = parse_cbor(); - } - return result; - } - - case 0xf4: // false - { - return false; - } - - case 0xf5: // true - { - return true; - } - - case 0xf6: // null - { - return value_t::null; - } - - case 0xf9: // Half-Precision Float (two-byte IEEE 754) - { - const int byte1 = get(); - check_eof(); - const int byte2 = get(); - check_eof(); - - // code from RFC 7049, Appendix D, Figure 3: - // As half-precision floating-point numbers were only added - // to IEEE 754 in 2008, today's programming platforms often - // still only have limited support for them. It is very - // easy to include at least decoding support for them even - // without such support. An example of a small decoder for - // half-precision floating-point numbers in the C language - // is shown in Fig. 3. - const int half = (byte1 << 8) + byte2; - const int exp = (half >> 10) & 0x1f; - const int mant = half & 0x3ff; - double val; - if (exp == 0) - { - val = std::ldexp(mant, -24); - } - else if (exp != 31) - { - val = std::ldexp(mant + 1024, exp - 25); - } - else - { - val = mant == 0 - ? std::numeric_limits::infinity() - : std::numeric_limits::quiet_NaN(); - } - return (half & 0x8000) != 0 ? -val : val; - } - - case 0xfa: // Single-Precision Float (four-byte IEEE 754) - { - return get_number(); - } - - case 0xfb: // Double-Precision Float (eight-byte IEEE 754) - { - return get_number(); - } - - default: // anything else (0xFF is handled inside the other types) - { - std::stringstream ss; - ss << std::setw(2) << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading CBOR; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief create a JSON value from MessagePack input - - @return JSON value created from MessagePack input - - @throw parse_error.110 if input ended unexpectedly - @throw parse_error.112 if unsupported byte was read - */ - basic_json parse_msgpack() - { - switch (get()) - { - // EOF - case std::char_traits::eof(): - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } - - // positive fixint - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5a: - case 0x5b: - case 0x5c: - case 0x5d: - case 0x5e: - case 0x5f: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: - { - return static_cast(current); - } - - // fixmap - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - case 0x8e: - case 0x8f: - { - basic_json result = value_t::object; - const auto len = static_cast(current & 0x0f); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_msgpack_string(); - result[key] = parse_msgpack(); - } - return result; - } - - // fixarray - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9a: - case 0x9b: - case 0x9c: - case 0x9d: - case 0x9e: - case 0x9f: - { - basic_json result = value_t::array; - const auto len = static_cast(current & 0x0f); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_msgpack()); - } - return result; - } - - // fixstr - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - { - return get_msgpack_string(); - } - - case 0xc0: // nil - { - return value_t::null; - } - - case 0xc2: // false - { - return false; - } - - case 0xc3: // true - { - return true; - } - - case 0xca: // float 32 - { - return get_number(); - } - - case 0xcb: // float 64 - { - return get_number(); - } - - case 0xcc: // uint 8 - { - return get_number(); - } - - case 0xcd: // uint 16 - { - return get_number(); - } - - case 0xce: // uint 32 - { - return get_number(); - } - - case 0xcf: // uint 64 - { - return get_number(); - } - - case 0xd0: // int 8 - { - return get_number(); - } - - case 0xd1: // int 16 - { - return get_number(); - } - - case 0xd2: // int 32 - { - return get_number(); - } - - case 0xd3: // int 64 - { - return get_number(); - } - - case 0xd9: // str 8 - case 0xda: // str 16 - case 0xdb: // str 32 - { - return get_msgpack_string(); - } - - case 0xdc: // array 16 - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_msgpack()); - } - return result; - } - - case 0xdd: // array 32 - { - basic_json result = value_t::array; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - result.push_back(parse_msgpack()); - } - return result; - } - - case 0xde: // map 16 - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_msgpack_string(); - result[key] = parse_msgpack(); - } - return result; - } - - case 0xdf: // map 32 - { - basic_json result = value_t::object; - const auto len = static_cast(get_number()); - for (size_t i = 0; i < len; ++i) - { - get(); - auto key = get_msgpack_string(); - result[key] = parse_msgpack(); - } - return result; - } - - // positive fixint - case 0xe0: - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - case 0xe8: - case 0xe9: - case 0xea: - case 0xeb: - case 0xec: - case 0xed: - case 0xee: - case 0xef: - case 0xf0: - case 0xf1: - case 0xf2: - case 0xf3: - case 0xf4: - case 0xf5: - case 0xf6: - case 0xf7: - case 0xf8: - case 0xf9: - case 0xfa: - case 0xfb: - case 0xfc: - case 0xfd: - case 0xfe: - case 0xff: - { - return static_cast(current); - } - - default: // anything else - { - std::stringstream ss; - ss << std::setw(2) << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(112, chars_read, "error reading MessagePack; last byte: 0x" + ss.str())); - } - } - } - - /*! - @brief determine system byte order - - @return true iff system's byte order is little endian - - @note from http://stackoverflow.com/a/1001328/266378 - */ - static bool little_endianess() noexcept + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) { - int num = 1; - return (*reinterpret_cast(&num) == 1); + write_number(static_cast(0x60 + N)); } - - private: - /*! - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns - `std::char_traits::eof()` in that case. - - @return character read from the input - */ - int get() + else if (N <= 0xff) { - ++chars_read; - return (current = ia->get_character()); + oa->write_character(0x78); + write_number(static_cast(N)); } - - /* - @brief read a number from the input - - @tparam T the type of the number - - @return number of type @a T - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - - @throw parse_error.110 if input has less than `sizeof(T)` bytes - */ - template - T get_number() + else if (N <= 0xffff) { - // step 1: read input into array with system's byte order - std::array vec; - for (size_t i = 0; i < sizeof(T); ++i) - { - get(); - check_eof(); - - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - vec[sizeof(T) - i - 1] = static_cast(current); - } - else - { - vec[i] = static_cast(current); - } - } - - // step 2: convert array into number of type T and return - T result; - std::memcpy(&result, vec.data(), sizeof(T)); - return result; + oa->write_character(0x79); + write_number(static_cast(N)); } - - /*! - @brief create a string by reading characters from the input - - @param[in] len number of bytes to read - - @return string created by reading @a len bytes - - @throw parse_error.110 if input has less than @a len bytes - */ - std::string get_string(const size_t len) + else if (N <= 0xffffffff) { - std::string result; - for (size_t i = 0; i < len; ++i) - { - get(); - check_eof(); - result.append(1, static_cast(current)); - } - return result; + oa->write_character(0x7a); + write_number(static_cast(N)); } - - /*! - @brief reads a CBOR string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - Additionally, CBOR's strings with indefinite lengths are supported. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpexted byte is read - */ - std::string get_cbor_string() + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) { - check_eof(); - - switch (current) - { - // UTF-8 string (0x00..0x17 bytes follow) - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - { - const auto len = static_cast(current & 0x1f); - return get_string(len); - } - - case 0x78: // UTF-8 string (one-byte uint8_t for n follows) - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0x79: // UTF-8 string (two-byte uint16_t for n follow) - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0x7f: // UTF-8 string (indefinite length) - { - std::string result; - while (get() != 0xff) - { - check_eof(); - result.append(1, static_cast(current)); - } - return result; - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a CBOR string; last byte: 0x" + ss.str())); - } - } + oa->write_character(0x7b); + write_number(static_cast(N)); } + // LCOV_EXCL_STOP - /*! - @brief reads a MessagePack string - - This function first reads starting bytes to determine the expected - string length and then copies this number of bytes into a string. - - @return string - - @throw parse_error.110 if input ended - @throw parse_error.113 if an unexpexted byte is read - */ - std::string get_msgpack_string() - { - check_eof(); - - switch (current) - { - // fixstr - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: - case 0xa9: - case 0xaa: - case 0xab: - case 0xac: - case 0xad: - case 0xae: - case 0xaf: - case 0xb0: - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - case 0xbd: - case 0xbe: - case 0xbf: - { - const auto len = static_cast(current & 0x1f); - return get_string(len); - } - - case 0xd9: // str 8 - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0xda: // str 16 - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - case 0xdb: // str 32 - { - const auto len = static_cast(get_number()); - return get_string(len); - } - - default: - { - std::stringstream ss; - ss << std::setw(2) << std::setfill('0') << std::hex << current; - JSON_THROW(parse_error::create(113, chars_read, "expected a MessagePack string; last byte: 0x" + ss.str())); - } - } - } + // step 2: write the string + oa->write_characters(reinterpret_cast(j.m_value.string->c_str()), j.m_value.string->size()); + break; + } - /*! - @brief check if input ended - @throw parse_error.110 if input ended - */ - void check_eof() const + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) { - if (JSON_UNLIKELY(current == std::char_traits::eof())) - { - JSON_THROW(parse_error::create(110, chars_read, "unexpected end of input")); - } + write_number(static_cast(0x80 + N)); } - - private: - /// input adapter - input_adapter_t ia = nullptr; - - /// the current character - int current = std::char_traits::eof(); - - /// the number of characters read - size_t chars_read = 0; - - /// whether we can assume little endianess - const bool is_little_endian = true; - }; - - /*! - @brief serialization to CBOR and MessagePack values - */ - class binary_writer - { - public: - /*! - @brief create a binary writer - - @param[in] adapter output adapter to write to - */ - explicit binary_writer(output_adapter_t adapter) - : is_little_endian(binary_reader::little_endianess()), oa(adapter) + else if (N <= 0xff) { - assert(oa); + oa->write_character(0x98); + write_number(static_cast(N)); } - - /*! - @brief[in] j JSON value to serialize - */ - void write_cbor(const basic_json& j) + else if (N <= 0xffff) { - switch (j.type()) - { - case value_t::null: - { - oa->write_character(0xf6); - break; - } - - case value_t::boolean: - { - oa->write_character(j.m_value.boolean ? 0xf5 : 0xf4); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // CBOR does not differentiate between positive signed - // integers and unsigned integers. Therefore, we used the - // code from the value_t::number_unsigned case here. - if (j.m_value.number_integer <= 0x17) - { - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(0x18); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(0x19); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer <= (std::numeric_limits::max)()) - { - oa->write_character(0x1a); - write_number(static_cast(j.m_value.number_integer)); - } - else - { - oa->write_character(0x1b); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - // The conversions below encode the sign in the first - // byte, and the value is converted to a positive number. - const auto positive_number = -1 - j.m_value.number_integer; - if (j.m_value.number_integer >= -24) - { - write_number(static_cast(0x20 + positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(0x38); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(0x39); - write_number(static_cast(positive_number)); - } - else if (positive_number <= (std::numeric_limits::max)()) - { - oa->write_character(0x3a); - write_number(static_cast(positive_number)); - } - else - { - oa->write_character(0x3b); - write_number(static_cast(positive_number)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned <= 0x17) - { - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(0x18); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(0x19); - write_number(static_cast(j.m_value.number_unsigned)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - oa->write_character(0x1a); - write_number(static_cast(j.m_value.number_unsigned)); - } - else - { - oa->write_character(0x1b); - write_number(static_cast(j.m_value.number_unsigned)); - } - break; - } - - case value_t::number_float: - { - // Double-Precision Float - oa->write_character(0xfb); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 0x17) - { - write_number(static_cast(0x60 + N)); - } - else if (N <= 0xff) - { - oa->write_character(0x78); - write_number(static_cast(N)); - } - else if (N <= 0xffff) - { - oa->write_character(0x79); - write_number(static_cast(N)); - } - else if (N <= 0xffffffff) - { - oa->write_character(0x7a); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - oa->write_character(0x7b); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write the string - oa->write_characters(reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 0x17) - { - write_number(static_cast(0x80 + N)); - } - else if (N <= 0xff) - { - oa->write_character(0x98); - write_number(static_cast(N)); - } - else if (N <= 0xffff) - { - oa->write_character(0x99); - write_number(static_cast(N)); - } - else if (N <= 0xffffffff) - { - oa->write_character(0x9a); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - oa->write_character(0x9b); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_cbor(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 0x17) - { - write_number(static_cast(0xa0 + N)); - } - else if (N <= 0xff) - { - oa->write_character(0xb8); - write_number(static_cast(N)); - } - else if (N <= 0xffff) - { - oa->write_character(0xb9); - write_number(static_cast(N)); - } - else if (N <= 0xffffffff) - { - oa->write_character(0xba); - write_number(static_cast(N)); - } - // LCOV_EXCL_START - else if (N <= 0xffffffffffffffff) - { - oa->write_character(0xbb); - write_number(static_cast(N)); - } - // LCOV_EXCL_STOP - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_cbor(el.first); - write_cbor(el.second); - } - break; - } - - default: - { - break; - } - } + oa->write_character(0x99); + write_number(static_cast(N)); } - - /*! - @brief[in] j JSON value to serialize - */ - void write_msgpack(const basic_json& j) + else if (N <= 0xffffffff) { - switch (j.type()) - { - case value_t::null: - { - // nil - oa->write_character(0xc0); - break; - } - - case value_t::boolean: - { - // true and false - oa->write_character(j.m_value.boolean ? 0xc3 : 0xc2); - break; - } - - case value_t::number_integer: - { - if (j.m_value.number_integer >= 0) - { - // MessagePack does not differentiate between positive - // signed integers and unsigned integers. Therefore, we - // used the code from the value_t::number_unsigned case - // here. - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(0xcc); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(0xcd); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(0xce); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(0xcf); - write_number(static_cast(j.m_value.number_integer)); - } - } - else - { - if (j.m_value.number_integer >= -32) - { - // negative fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 8 - oa->write_character(0xd0); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 16 - oa->write_character(0xd1); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 32 - oa->write_character(0xd2); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_integer >= (std::numeric_limits::min)() and j.m_value.number_integer <= (std::numeric_limits::max)()) - { - // int 64 - oa->write_character(0xd3); - write_number(static_cast(j.m_value.number_integer)); - } - } - break; - } - - case value_t::number_unsigned: - { - if (j.m_value.number_unsigned < 128) - { - // positive fixnum - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 8 - oa->write_character(0xcc); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 16 - oa->write_character(0xcd); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 32 - oa->write_character(0xce); - write_number(static_cast(j.m_value.number_integer)); - } - else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) - { - // uint 64 - oa->write_character(0xcf); - write_number(static_cast(j.m_value.number_integer)); - } - break; - } - - case value_t::number_float: - { - // float 64 - oa->write_character(0xcb); - write_number(j.m_value.number_float); - break; - } - - case value_t::string: - { - // step 1: write control byte and the string length - const auto N = j.m_value.string->size(); - if (N <= 31) - { - // fixstr - write_number(static_cast(0xa0 | N)); - } - else if (N <= 255) - { - // str 8 - oa->write_character(0xd9); - write_number(static_cast(N)); - } - else if (N <= 65535) - { - // str 16 - oa->write_character(0xda); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // str 32 - oa->write_character(0xdb); - write_number(static_cast(N)); - } - - // step 2: write the string - oa->write_characters(reinterpret_cast(j.m_value.string->c_str()), - j.m_value.string->size()); - break; - } - - case value_t::array: - { - // step 1: write control byte and the array size - const auto N = j.m_value.array->size(); - if (N <= 15) - { - // fixarray - write_number(static_cast(0x90 | N)); - } - else if (N <= 0xffff) - { - // array 16 - oa->write_character(0xdc); - write_number(static_cast(N)); - } - else if (N <= 0xffffffff) - { - // array 32 - oa->write_character(0xdd); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.array) - { - write_msgpack(el); - } - break; - } - - case value_t::object: - { - // step 1: write control byte and the object size - const auto N = j.m_value.object->size(); - if (N <= 15) - { - // fixmap - write_number(static_cast(0x80 | (N & 0xf))); - } - else if (N <= 65535) - { - // map 16 - oa->write_character(0xde); - write_number(static_cast(N)); - } - else if (N <= 4294967295) - { - // map 32 - oa->write_character(0xdf); - write_number(static_cast(N)); - } - - // step 2: write each element - for (const auto& el : *j.m_value.object) - { - write_msgpack(el.first); - write_msgpack(el.second); - } - break; - } - - default: - { - break; - } - } + oa->write_character(0x9a); + write_number(static_cast(N)); } - - private: - /* - @brief write a number to output input - - @param[in] n number of type @a T - @tparam T the type of the number - - @note This function needs to respect the system's endianess, because - bytes in CBOR and MessagePack are stored in network order (big - endian) and therefore need reordering on little endian systems. - */ - template - void write_number(T n) + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) { - // step 1: write number to array of length T - std::array vec; - std::memcpy(vec.data(), &n, sizeof(T)); - - // step 2: write array to output (with possible reordering) - for (size_t i = 0; i < sizeof(T); ++i) - { - // reverse byte order prior to conversion if necessary - if (is_little_endian) - { - oa->write_character(vec[sizeof(T) - i - 1]); - } - else - { - oa->write_character(vec[i]); - } - } - } - - private: - /// whether we can assume little endianess - const bool is_little_endian = true; - - /// the output - output_adapter_t oa = nullptr; - }; - - public: - /*! - @brief create a CBOR serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the CBOR (Concise - Binary Object Representation) serialization format. CBOR is a binary - serialization format which aims to be more compact than JSON itself, yet - more efficient to parse. - - The library uses the following mapping from JSON values types to - CBOR types according to the CBOR specification (RFC 7049): - - JSON value type | value/range | CBOR type | first byte - --------------- | ------------------------------------------ | ---------------------------------- | --------------- - null | `null` | Null | 0xf6 - boolean | `true` | True | 0xf5 - boolean | `false` | False | 0xf4 - number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3b - number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3a - number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 - number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 - number_integer | -24..-1 | Negative integer | 0x20..0x37 - number_integer | 0..23 | Integer | 0x00..0x17 - number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a - number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b - number_unsigned | 0..23 | Integer | 0x00..0x17 - number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 - number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 - number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a - number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b - number_float | *any value* | Double-Precision Float | 0xfb - string | *length*: 0..23 | UTF-8 string | 0x60..0x77 - string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 - string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 - string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7a - string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7b - array | *size*: 0..23 | array | 0x80..0x97 - array | *size*: 23..255 | array (1 byte follow) | 0x98 - array | *size*: 256..65535 | array (2 bytes follow) | 0x99 - array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9a - array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9b - object | *size*: 0..23 | map | 0xa0..0xb7 - object | *size*: 23..255 | map (1 byte follow) | 0xb8 - object | *size*: 256..65535 | map (2 bytes follow) | 0xb9 - object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xba - object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xbb - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a CBOR value. - - @note The following CBOR types are not used in the conversion: - - byte strings (0x40..0x5f) - - UTF-8 strings terminated by "break" (0x7f) - - arrays terminated by "break" (0x9f) - - maps terminated by "break" (0xbf) - - date/time (0xc0..0xc1) - - bignum (0xc2..0xc3) - - decimal fraction (0xc4) - - bigfloat (0xc5) - - tagged items (0xc6..0xd4, 0xd8..0xdb) - - expected conversions (0xd5..0xd7) - - simple values (0xe0..0xf3, 0xf8) - - undefined (0xf7) - - half and single-precision floats (0xf9-0xfa) - - break (0xff) - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in CBOR format.,to_cbor} - - @sa http://cbor.io - @sa @ref from_cbor(const std::vector&, const size_t) for the - analogous deserialization - @sa @ref to_msgpack(const basic_json& for the related MessagePack format - - @since version 2.0.9 - */ - static std::vector to_cbor(const basic_json& j) - { - std::vector result; - binary_writer bw(output_adapter::create(result)); - bw.write_cbor(j); - return result; - } - - /*! - @brief create a MessagePack serialization of a given JSON value - - Serializes a given JSON value @a j to a byte vector using the MessagePack - serialization format. MessagePack is a binary serialization format which - aims to be more compact than JSON itself, yet more efficient to parse. - - The library uses the following mapping from JSON values types to - MessagePack types according to the MessagePack specification: - - JSON value type | value/range | MessagePack type | first byte - --------------- | --------------------------------- | ---------------- | ---------- - null | `null` | nil | 0xc0 - boolean | `true` | true | 0xc3 - boolean | `false` | false | 0xc2 - number_integer | -9223372036854775808..-2147483649 | int64 | 0xd3 - number_integer | -2147483648..-32769 | int32 | 0xd2 - number_integer | -32768..-129 | int16 | 0xd1 - number_integer | -128..-33 | int8 | 0xd0 - number_integer | -32..-1 | negative fixint | 0xe0..0xff - number_integer | 0..127 | positive fixint | 0x00..0x7f - number_integer | 128..255 | uint 8 | 0xcc - number_integer | 256..65535 | uint 16 | 0xcd - number_integer | 65536..4294967295 | uint 32 | 0xce - number_integer | 4294967296..18446744073709551615 | uint 64 | 0xcf - number_unsigned | 0..127 | positive fixint | 0x00..0x7f - number_unsigned | 128..255 | uint 8 | 0xcc - number_unsigned | 256..65535 | uint 16 | 0xcd - number_unsigned | 65536..4294967295 | uint 32 | 0xce - number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xcf - number_float | *any value* | float 64 | 0xcb - string | *length*: 0..31 | fixstr | 0xa0..0xbf - string | *length*: 32..255 | str 8 | 0xd9 - string | *length*: 256..65535 | str 16 | 0xda - string | *length*: 65536..4294967295 | str 32 | 0xdb - array | *size*: 0..15 | fixarray | 0x90..0x9f - array | *size*: 16..65535 | array 16 | 0xdc - array | *size*: 65536..4294967295 | array 32 | 0xdd - object | *size*: 0..15 | fix map | 0x80..0x8f - object | *size*: 16..65535 | map 16 | 0xde - object | *size*: 65536..4294967295 | map 32 | 0xdf - - @note The mapping is **complete** in the sense that any JSON value type - can be converted to a MessagePack value. - - @note The following values can **not** be converted to a MessagePack value: - - strings with more than 4294967295 bytes - - arrays with more than 4294967295 elements - - objects with more than 4294967295 elements - - @note The following MessagePack types are not used in the conversion: - - bin 8 - bin 32 (0xc4..0xc6) - - ext 8 - ext 32 (0xc7..0xc9) - - float 32 (0xca) - - fixext 1 - fixext 16 (0xd4..0xd8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @param[in] j JSON value to serialize - @return MessagePack serialization as byte vector - - @complexity Linear in the size of the JSON value @a j. - - @liveexample{The example shows the serialization of a JSON value to a byte - vector in MessagePack format.,to_msgpack} - - @sa http://msgpack.org - @sa @ref from_msgpack(const std::vector&, const size_t) for the - analogous deserialization - @sa @ref to_cbor(const basic_json& for the related CBOR format - - @since version 2.0.9 - */ - static std::vector to_msgpack(const basic_json& j) - { - std::vector result; - binary_writer bw(output_adapter::create(result)); - bw.write_msgpack(j); - return result; - } - - /*! - @brief create a JSON value from a byte vector in CBOR format - - Deserializes a given byte vector @a v to a JSON value using the CBOR - (Concise Binary Object Representation) serialization format. - - The library maps CBOR types to JSON value types as follows: - - CBOR type | JSON value type | first byte - ---------------------- | --------------- | ---------- - Integer | number_unsigned | 0x00..0x17 - Unsigned integer | number_unsigned | 0x18 - Unsigned integer | number_unsigned | 0x19 - Unsigned integer | number_unsigned | 0x1a - Unsigned integer | number_unsigned | 0x1b - Negative integer | number_integer | 0x20..0x37 - Negative integer | number_integer | 0x38 - Negative integer | number_integer | 0x39 - Negative integer | number_integer | 0x3a - Negative integer | number_integer | 0x3b - Negative integer | number_integer | 0x40..0x57 - UTF-8 string | string | 0x60..0x77 - UTF-8 string | string | 0x78 - UTF-8 string | string | 0x79 - UTF-8 string | string | 0x7a - UTF-8 string | string | 0x7b - UTF-8 string | string | 0x7f - array | array | 0x80..0x97 - array | array | 0x98 - array | array | 0x99 - array | array | 0x9a - array | array | 0x9b - array | array | 0x9f - map | object | 0xa0..0xb7 - map | object | 0xb8 - map | object | 0xb9 - map | object | 0xba - map | object | 0xbb - map | object | 0xbf - False | `false` | 0xf4 - True | `true` | 0xf5 - Nill | `null` | 0xf6 - Half-Precision Float | number_float | 0xf9 - Single-Precision Float | number_float | 0xfa - Double-Precision Float | number_float | 0xfb - - @warning The mapping is **incomplete** in the sense that not all CBOR - types can be converted to a JSON value. The following CBOR types - are not supported and will yield parse errors (parse_error.112): - - byte strings (0x40..0x5f) - - date/time (0xc0..0xc1) - - bignum (0xc2..0xc3) - - decimal fraction (0xc4) - - bigfloat (0xc5) - - tagged items (0xc6..0xd4, 0xd8..0xdb) - - expected conversions (0xd5..0xd7) - - simple values (0xe0..0xf3, 0xf8) - - undefined (0xf7) - - @warning CBOR allows map keys of any type, whereas JSON only allows - strings as keys in object values. Therefore, CBOR maps with keys - other than UTF-8 strings are rejected (parse_error.113). - - @note Any CBOR output created @ref to_cbor can be successfully parsed by - @ref from_cbor. - - @param[in] v a byte vector in CBOR format - @param[in] start_index the index to start reading from @a v (0 by default) - @return deserialized JSON value - - @throw parse_error.110 if the given vector ends prematurely - @throw parse_error.112 if unsupported features from CBOR were - used in the given vector @a v or if the input is not valid CBOR - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in CBOR - format to a JSON value.,from_cbor} - - @sa http://cbor.io - @sa @ref to_cbor(const basic_json&) for the analogous serialization - @sa @ref from_msgpack(const std::vector&, const size_t) for the - related MessagePack format - - @since version 2.0.9, parameter @a start_index since 2.1.1 - */ - static basic_json from_cbor(const std::vector& v, - const size_t start_index = 0) - { - binary_reader br(input_adapter::create(v.begin() + static_cast(start_index), v.end())); - return br.parse_cbor(); - } - - - /*! - @brief create a JSON value from a byte vector in MessagePack format - - Deserializes a given byte vector @a v to a JSON value using the MessagePack - serialization format. - - The library maps MessagePack types to JSON value types as follows: - - MessagePack type | JSON value type | first byte - ---------------- | --------------- | ---------- - positive fixint | number_unsigned | 0x00..0x7f - fixmap | object | 0x80..0x8f - fixarray | array | 0x90..0x9f - fixstr | string | 0xa0..0xbf - nil | `null` | 0xc0 - false | `false` | 0xc2 - true | `true` | 0xc3 - float 32 | number_float | 0xca - float 64 | number_float | 0xcb - uint 8 | number_unsigned | 0xcc - uint 16 | number_unsigned | 0xcd - uint 32 | number_unsigned | 0xce - uint 64 | number_unsigned | 0xcf - int 8 | number_integer | 0xd0 - int 16 | number_integer | 0xd1 - int 32 | number_integer | 0xd2 - int 64 | number_integer | 0xd3 - str 8 | string | 0xd9 - str 16 | string | 0xda - str 32 | string | 0xdb - array 16 | array | 0xdc - array 32 | array | 0xdd - map 16 | object | 0xde - map 32 | object | 0xdf - negative fixint | number_integer | 0xe0-0xff - - @warning The mapping is **incomplete** in the sense that not all - MessagePack types can be converted to a JSON value. The following - MessagePack types are not supported and will yield parse errors: - - bin 8 - bin 32 (0xc4..0xc6) - - ext 8 - ext 32 (0xc7..0xc9) - - fixext 1 - fixext 16 (0xd4..0xd8) - - @note Any MessagePack output created @ref to_msgpack can be successfully - parsed by @ref from_msgpack. - - @param[in] v a byte vector in MessagePack format - @param[in] start_index the index to start reading from @a v (0 by default) - @return deserialized JSON value - - @throw parse_error.110 if the given vector ends prematurely - @throw parse_error.112 if unsupported features from MessagePack were - used in the given vector @a v or if the input is not valid MessagePack - @throw parse_error.113 if a string was expected as map key, but not found - - @complexity Linear in the size of the byte vector @a v. - - @liveexample{The example shows the deserialization of a byte vector in - MessagePack format to a JSON value.,from_msgpack} - - @sa http://msgpack.org - @sa @ref to_msgpack(const basic_json&) for the analogous serialization - @sa @ref from_cbor(const std::vector&, const size_t) for the - related CBOR format - - @since version 2.0.9, parameter @a start_index since 2.1.1 - */ - static basic_json from_msgpack(const std::vector& v, - const size_t start_index = 0) - { - binary_reader br(input_adapter::create(v.begin() + static_cast(start_index), v.end())); - return br.parse_msgpack(); - } - - /// @} - - ////////////////////// - // lexer and parser // - ////////////////////// - - private: - /*! - @brief lexical analysis - - This class organizes the lexical analysis during JSON deserialization. - */ - class lexer - { - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input ///< indicating the end of the input buffer - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - default: - { - // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE - } - } + oa->write_character(0x9b); + write_number(static_cast(N)); } + // LCOV_EXCL_STOP - explicit lexer(input_adapter_t adapter) - : ia(adapter), decimal_point_char(get_decimal_point()) - {} - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept + // step 2: write each element + for (const auto & el : *j.m_value.array) { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0]; + write_cbor(el); } + break; + } - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - @return codepoint or -1 in case of an error (e.g. EOF or non-hex - character) - */ - int get_codepoint() + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - // byte 1: \uXxxx - switch (get()) - { - case '0': - break; - case '1': - codepoint += 0x1000; - break; - case '2': - codepoint += 0x2000; - break; - case '3': - codepoint += 0x3000; - break; - case '4': - codepoint += 0x4000; - break; - case '5': - codepoint += 0x5000; - break; - case '6': - codepoint += 0x6000; - break; - case '7': - codepoint += 0x7000; - break; - case '8': - codepoint += 0x8000; - break; - case '9': - codepoint += 0x9000; - break; - case 'A': - case 'a': - codepoint += 0xa000; - break; - case 'B': - case 'b': - codepoint += 0xb000; - break; - case 'C': - case 'c': - codepoint += 0xc000; - break; - case 'D': - case 'd': - codepoint += 0xd000; - break; - case 'E': - case 'e': - codepoint += 0xe000; - break; - case 'F': - case 'f': - codepoint += 0xf000; - break; - default: - return -1; - } - - // byte 2: \uxXxx - switch (get()) - { - case '0': - break; - case '1': - codepoint += 0x0100; - break; - case '2': - codepoint += 0x0200; - break; - case '3': - codepoint += 0x0300; - break; - case '4': - codepoint += 0x0400; - break; - case '5': - codepoint += 0x0500; - break; - case '6': - codepoint += 0x0600; - break; - case '7': - codepoint += 0x0700; - break; - case '8': - codepoint += 0x0800; - break; - case '9': - codepoint += 0x0900; - break; - case 'A': - case 'a': - codepoint += 0x0a00; - break; - case 'B': - case 'b': - codepoint += 0x0b00; - break; - case 'C': - case 'c': - codepoint += 0x0c00; - break; - case 'D': - case 'd': - codepoint += 0x0d00; - break; - case 'E': - case 'e': - codepoint += 0x0e00; - break; - case 'F': - case 'f': - codepoint += 0x0f00; - break; - default: - return -1; - } - - // byte 3: \uxxXx - switch (get()) - { - case '0': - break; - case '1': - codepoint += 0x0010; - break; - case '2': - codepoint += 0x0020; - break; - case '3': - codepoint += 0x0030; - break; - case '4': - codepoint += 0x0040; - break; - case '5': - codepoint += 0x0050; - break; - case '6': - codepoint += 0x0060; - break; - case '7': - codepoint += 0x0070; - break; - case '8': - codepoint += 0x0080; - break; - case '9': - codepoint += 0x0090; - break; - case 'A': - case 'a': - codepoint += 0x00a0; - break; - case 'B': - case 'b': - codepoint += 0x00b0; - break; - case 'C': - case 'c': - codepoint += 0x00c0; - break; - case 'D': - case 'd': - codepoint += 0x00d0; - break; - case 'E': - case 'e': - codepoint += 0x00e0; - break; - case 'F': - case 'f': - codepoint += 0x00f0; - break; - default: - return -1; - } - - // byte 4: \uxxxX - switch (get()) - { - case '0': - break; - case '1': - codepoint += 0x0001; - break; - case '2': - codepoint += 0x0002; - break; - case '3': - codepoint += 0x0003; - break; - case '4': - codepoint += 0x0004; - break; - case '5': - codepoint += 0x0005; - break; - case '6': - codepoint += 0x0006; - break; - case '7': - codepoint += 0x0007; - break; - case '8': - codepoint += 0x0008; - break; - case '9': - codepoint += 0x0009; - break; - case 'A': - case 'a': - codepoint += 0x000a; - break; - case 'B': - case 'b': - codepoint += 0x000b; - break; - case 'C': - case 'c': - codepoint += 0x000c; - break; - case 'D': - case 'd': - codepoint += 0x000d; - break; - case 'E': - case 'e': - codepoint += 0x000e; - break; - case 'F': - case 'f': - codepoint += 0x000f; - break; - default: - return -1; - } - - return codepoint; + write_number(static_cast(0xa0 + N)); } + else if (N <= 0xff) + { + oa->write_character(0xb8); + write_number(static_cast(N)); + } + else if (N <= 0xffff) + { + oa->write_character(0xb9); + write_number(static_cast(N)); + } + else if (N <= 0xffffffff) + { + oa->write_character(0xba); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= 0xffffffffffffffff) + { + oa->write_character(0xbb); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP - /*! - @brief create diagnostic representation of a codepoint - @return string "U+XXXX" for codepoint XXXX - */ - static std::string codepoint_to_string(int codepoint) + // step 2: write each element + for (const auto & el : *j.m_value.object) { - std::stringstream ss; - ss << "U+" << std::setw(4) << std::uppercase << std::setfill('0') << std::hex << codepoint; - return ss.str(); + write_cbor(el.first); + write_cbor(el.second); } + break; + } - /*! - @brief scan a string literal + default: + { + break; + } + } + } - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer yytext. Then the - function returns successfully, yytext is null-terminated and yylen - contains the number of bytes in the string. + /*! + @brief[in] j JSON value to serialize + */ + void write_msgpack(const basic_json & j) + { + switch (j.type()) + { + case value_t::null: + { + // nil + oa->write_character(0xc0); + break; + } - @return token_type::value_string if string could be successfully - scanned, token_type::parse_error otherwise + case value_t::boolean: + { + // true and false + oa->write_character(j.m_value.boolean ? 0xc3 : 0xc2); + break; + } - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) { - // reset yytext (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we + // used the code from the value_t::number_unsigned case + // here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(0xcc); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(0xcd); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(0xce); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(0xcf); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if ( + j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(0xd0); + write_number(static_cast(j.m_value.number_integer)); + } + else if ( + j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(0xd1); + write_number(static_cast(j.m_value.number_integer)); + } + else if ( + j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(0xd2); + write_number(static_cast(j.m_value.number_integer)); + } + else if ( + j.m_value.number_integer >= (std::numeric_limits::min)() and + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(0xd3); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(0xcc); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(0xcd); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(0xce); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(0xcf); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } - while (true) - { - // get next character - get(); + case value_t::number_float: + { + // float 64 + oa->write_character(0xcb); + write_number(j.m_value.number_float); + break; + } - switch (current) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - // terminate yytext - add('\0'); - --yylen; - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - int codepoint; - int codepoint1 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate " + codepoint_to_string(codepoint1) + " must be followed by U+DC00..U+DFFF instead of " + codepoint_to_string(codepoint2); - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate " + codepoint_to_string(codepoint1) + " must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate " + codepoint_to_string(codepoint1) + " must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - - // only work with first code point - codepoint = codepoint1; - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate code point to bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7ff) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xffff) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - case 0x1f: - { - error_message = "invalid string: control character " + codepoint_to_string(current) + " must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x2c: - case 0x2d: - case 0x2e: - case 0x2f: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - case 0x3c: - case 0x3d: - case 0x3e: - case 0x3f: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5a: - case 0x5b: - case 0x5d: - case 0x5e: - case 0x5f: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6a: - case 0x6b: - case 0x6c: - case 0x6d: - case 0x6e: - case 0x6f: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7a: - case 0x7b: - case 0x7c: - case 0x7d: - case 0x7e: - case 0x7f: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xc2: - case 0xc3: - case 0xc4: - case 0xc5: - case 0xc6: - case 0xc7: - case 0xc8: - case 0xc9: - case 0xca: - case 0xcb: - case 0xcc: - case 0xcd: - case 0xce: - case 0xcf: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xd3: - case 0xd4: - case 0xd5: - case 0xd6: - case 0xd7: - case 0xd8: - case 0xd9: - case 0xda: - case 0xdb: - case 0xdc: - case 0xdd: - case 0xde: - case 0xdf: - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xe0: - { - add(current); - get(); - if (JSON_LIKELY(0xa0 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xe1: - case 0xe2: - case 0xe3: - case 0xe4: - case 0xe5: - case 0xe6: - case 0xe7: - case 0xe8: - case 0xe9: - case 0xea: - case 0xeb: - case 0xec: - case 0xee: - case 0xef: - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xed: - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0x9f)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xf0: - { - add(current); - get(); - if (JSON_LIKELY(0x90 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xf1: - case 0xf2: - case 0xf3: - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xf4: - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0x8f)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - get(); - if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) - { - add(current); - continue; - } - } - } - - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xa0 | N)); } - - static void strtof(float& f, const char* str, char** endptr) noexcept + else if (N <= 255) { - f = std::strtof(str, endptr); + // str 8 + oa->write_character(0xd9); + write_number(static_cast(N)); } - - static void strtof(double& f, const char* str, char** endptr) noexcept + else if (N <= 65535) + { + // str 16 + oa->write_character(0xda); + write_number(static_cast(N)); + } + else if (N <= 4294967295) { - f = std::strtod(str, endptr); + // str 32 + oa->write_character(0xdb); + write_number(static_cast(N)); } - static void strtof(long double& f, const char* str, char** endptr) noexcept + // step 2: write the string + oa->write_characters(reinterpret_cast(j.m_value.string->c_str()), j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= 0xffff) { - f = std::strtold(str, endptr); + // array 16 + oa->write_character(0xdc); + write_number(static_cast(N)); + } + else if (N <= 0xffffffff) + { + // array 32 + oa->write_character(0xdd); + write_number(static_cast(N)); } - /*! - @brief scan a number literal + // step 2: write each element + for (const auto & el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } - This function scans a string according to Sect. 6 of RFC 7159. + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xf))); + } + else if (N <= 65535) + { + // map 16 + oa->write_character(0xde); + write_number(static_cast(N)); + } + else if (N <= 4294967295) + { + // map 32 + oa->write_character(0xdf); + write_number(static_cast(N)); + } - The function is realized with a deterministic finite state machine - derived from the grammar described in RFC 7159. Starting in state - "init", the input is read and used to determined the next state. Only - state "done" accepts the number. State "error" is a trap state to model - errors. In the table below, "anything" means any character but the ones - listed before. + // step 2: write each element + for (const auto & el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done + default: + { + break; + } + } + } - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. + private: + /* + @brief write a number to output input - During scanning, the read bytes are stored in yytext. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. + @param[in] n number of type @a T + @tparam T the type of the number - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise + @note This function needs to respect the system's endianess, because + bytes in CBOR and MessagePack are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(T n) + { + // step 1: write number to array of length T + std::array vec; + std::memcpy(vec.data(), &n, sizeof(T)); - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() + // step 2: write array to output (with possible reordering) + for (size_t i = 0; i < sizeof(T); ++i) + { + // reverse byte order prior to conversion if necessary + if (is_little_endian) + { + oa->write_character(vec[sizeof(T) - i - 1]); + } + else { - // reset yytext to store the number's bytes - reset(); + oa->write_character(vec[i]); + } + } + } - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; + private: + /// whether we can assume little endianess + const bool is_little_endian = true; + + /// the output + output_adapter_t oa = nullptr; + }; + +public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xf6 + boolean | `true` | True | 0xf5 + boolean | `false` | False | 0xf4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3b + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3a + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1a + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1b + number_float | *any value* | Double-Precision Float | 0xfb + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7a + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7b + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9a + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9b + object | *size*: 0..23 | map | 0xa0..0xb7 + object | *size*: 23..255 | map (1 byte follow) | 0xb8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xb9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xba + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xbb + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note The following CBOR types are not used in the conversion: + - byte strings (0x40..0x5f) + - UTF-8 strings terminated by "break" (0x7f) + - arrays terminated by "break" (0x9f) + - maps terminated by "break" (0xbf) + - date/time (0xc0..0xc1) + - bignum (0xc2..0xc3) + - decimal fraction (0xc4) + - bigfloat (0xc5) + - tagged items (0xc6..0xd4, 0xd8..0xdb) + - expected conversions (0xd5..0xd7) + - simple values (0xe0..0xf3, 0xf8) + - undefined (0xf7) + - half and single-precision floats (0xf9-0xfa) + - break (0xff) + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa @ref from_cbor(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_msgpack(const basic_json& for the related MessagePack format + + @since version 2.0.9 + */ + static std::vector to_cbor(const basic_json & j) + { + std::vector result; + binary_writer bw(output_adapter::create(result)); + bw.write_cbor(j); + return result; + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xc0 + boolean | `true` | true | 0xc3 + boolean | `false` | false | 0xc2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xd3 + number_integer | -2147483648..-32769 | int32 | 0xd2 + number_integer | -32768..-129 | int16 | 0xd1 + number_integer | -128..-33 | int8 | 0xd0 + number_integer | -32..-1 | negative fixint | 0xe0..0xff + number_integer | 0..127 | positive fixint | 0x00..0x7f + number_integer | 128..255 | uint 8 | 0xcc + number_integer | 256..65535 | uint 16 | 0xcd + number_integer | 65536..4294967295 | uint 32 | 0xce + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xcf + number_unsigned | 0..127 | positive fixint | 0x00..0x7f + number_unsigned | 128..255 | uint 8 | 0xcc + number_unsigned | 256..65535 | uint 16 | 0xcd + number_unsigned | 65536..4294967295 | uint 32 | 0xce + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xcf + number_float | *any value* | float 64 | 0xcb + string | *length*: 0..31 | fixstr | 0xa0..0xbf + string | *length*: 32..255 | str 8 | 0xd9 + string | *length*: 256..65535 | str 16 | 0xda + string | *length*: 65536..4294967295 | str 32 | 0xdb + array | *size*: 0..15 | fixarray | 0x90..0x9f + array | *size*: 16..65535 | array 16 | 0xdc + array | *size*: 65536..4294967295 | array 32 | 0xdd + object | *size*: 0..15 | fix map | 0x80..0x8f + object | *size*: 16..65535 | map 16 | 0xde + object | *size*: 65536..4294967295 | map 32 | 0xdf + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note The following MessagePack types are not used in the conversion: + - bin 8 - bin 32 (0xc4..0xc6) + - ext 8 - ext 32 (0xc7..0xc9) + - float 32 (0xca) + - fixext 1 - fixext 16 (0xd4..0xd8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa @ref from_msgpack(const std::vector&, const size_t) for the + analogous deserialization + @sa @ref to_cbor(const basic_json& for the related CBOR format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json & j) + { + std::vector result; + binary_writer bw(output_adapter::create(result)); + bw.write_msgpack(j); + return result; + } + + /*! + @brief create a JSON value from a byte vector in CBOR format + + Deserializes a given byte vector @a v to a JSON value using the CBOR + (Concise Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1a + Unsigned integer | number_unsigned | 0x1b + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3a + Negative integer | number_integer | 0x3b + Negative integer | number_integer | 0x40..0x57 + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7a + UTF-8 string | string | 0x7b + UTF-8 string | string | 0x7f + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9a + array | array | 0x9b + array | array | 0x9f + map | object | 0xa0..0xb7 + map | object | 0xb8 + map | object | 0xb9 + map | object | 0xba + map | object | 0xbb + map | object | 0xbf + False | `false` | 0xf4 + True | `true` | 0xf5 + Nill | `null` | 0xf6 + Half-Precision Float | number_float | 0xf9 + Single-Precision Float | number_float | 0xfa + Double-Precision Float | number_float | 0xfb + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - byte strings (0x40..0x5f) + - date/time (0xc0..0xc1) + - bignum (0xc2..0xc3) + - decimal fraction (0xc4) + - bigfloat (0xc5) + - tagged items (0xc6..0xd4, 0xd8..0xdb) + - expected conversions (0xd5..0xd7) + - simple values (0xe0..0xf3, 0xf8) + - undefined (0xf7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] v a byte vector in CBOR format + @param[in] start_index the index to start reading from @a v (0 by default) + @return deserialized JSON value + + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from CBOR were + used in the given vector @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the byte vector @a v. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa @ref to_cbor(const basic_json&) for the analogous serialization + @sa @ref from_msgpack(const std::vector&, const size_t) for the + related MessagePack format + + @since version 2.0.9, parameter @a start_index since 2.1.1 + */ + static basic_json from_cbor(const std::vector & v, const size_t start_index = 0) + { + binary_reader br(input_adapter::create(v.begin() + static_cast(start_index), v.end())); + return br.parse_cbor(); + } + + /*! + @brief create a JSON value from a byte vector in MessagePack format + + Deserializes a given byte vector @a v to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7f + fixmap | object | 0x80..0x8f + fixarray | array | 0x90..0x9f + fixstr | string | 0xa0..0xbf + nil | `null` | 0xc0 + false | `false` | 0xc2 + true | `true` | 0xc3 + float 32 | number_float | 0xca + float 64 | number_float | 0xcb + uint 8 | number_unsigned | 0xcc + uint 16 | number_unsigned | 0xcd + uint 32 | number_unsigned | 0xce + uint 64 | number_unsigned | 0xcf + int 8 | number_integer | 0xd0 + int 16 | number_integer | 0xd1 + int 32 | number_integer | 0xd2 + int 64 | number_integer | 0xd3 + str 8 | string | 0xd9 + str 16 | string | 0xda + str 32 | string | 0xdb + array 16 | array | 0xdc + array 32 | array | 0xdd + map 16 | object | 0xde + map 32 | object | 0xdf + negative fixint | number_integer | 0xe0-0xff + + @warning The mapping is **incomplete** in the sense that not all + MessagePack types can be converted to a JSON value. The following + MessagePack types are not supported and will yield parse errors: + - bin 8 - bin 32 (0xc4..0xc6) + - ext 8 - ext 32 (0xc7..0xc9) + - fixext 1 - fixext 16 (0xd4..0xd8) + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] v a byte vector in MessagePack format + @param[in] start_index the index to start reading from @a v (0 by default) + @return deserialized JSON value + + @throw parse_error.110 if the given vector ends prematurely + @throw parse_error.112 if unsupported features from MessagePack were + used in the given vector @a v or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the byte vector @a v. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa @ref to_msgpack(const basic_json&) for the analogous serialization + @sa @ref from_cbor(const std::vector&, const size_t) for the + related CBOR format + + @since version 2.0.9, parameter @a start_index since 2.1.1 + */ + static basic_json from_msgpack(const std::vector & v, const size_t start_index = 0) + { + binary_reader br(input_adapter::create(v.begin() + static_cast(start_index), v.end())); + return br.parse_msgpack(); + } + + /// @} + + ////////////////////// + // lexer and parser // + ////////////////////// + +private: + /*! + @brief lexical analysis + + This class organizes the lexical analysis during JSON deserialization. + */ + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } + /// return name of values of type token_type (only used for errors) + static const char * token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } + } + } + + explicit lexer(input_adapter_t adapter) + : ia(adapter) + , decimal_point_char(get_decimal_point()) + { + } - case '0': - { - add(current); - goto scan_number_zero; - } + private: + ///////////////////// + // locales + ///////////////////// - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } + /// return the locale-dependent decimal point + static char get_decimal_point() noexcept + { + const auto loc = localeconv(); + assert(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0]; + } - default: - { - // all other characters are rejected outside scan_number() - assert(false); // LCOV_EXCL_LINE - } - } + ///////////////////// + // scan functions + ///////////////////// -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } + /*! + @brief get codepoint from 4 hex characters following `\u` + + @return codepoint or -1 in case of an error (e.g. EOF or non-hex + character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + assert(current == 'u'); + int codepoint = 0; + + // byte 1: \uXxxx + switch (get()) + { + case '0': + break; + case '1': + codepoint += 0x1000; + break; + case '2': + codepoint += 0x2000; + break; + case '3': + codepoint += 0x3000; + break; + case '4': + codepoint += 0x4000; + break; + case '5': + codepoint += 0x5000; + break; + case '6': + codepoint += 0x6000; + break; + case '7': + codepoint += 0x7000; + break; + case '8': + codepoint += 0x8000; + break; + case '9': + codepoint += 0x9000; + break; + case 'A': + case 'a': + codepoint += 0xa000; + break; + case 'B': + case 'b': + codepoint += 0xb000; + break; + case 'C': + case 'c': + codepoint += 0xc000; + break; + case 'D': + case 'd': + codepoint += 0xd000; + break; + case 'E': + case 'e': + codepoint += 0xe000; + break; + case 'F': + case 'f': + codepoint += 0xf000; + break; + default: + return -1; + } + + // byte 2: \uxXxx + switch (get()) + { + case '0': + break; + case '1': + codepoint += 0x0100; + break; + case '2': + codepoint += 0x0200; + break; + case '3': + codepoint += 0x0300; + break; + case '4': + codepoint += 0x0400; + break; + case '5': + codepoint += 0x0500; + break; + case '6': + codepoint += 0x0600; + break; + case '7': + codepoint += 0x0700; + break; + case '8': + codepoint += 0x0800; + break; + case '9': + codepoint += 0x0900; + break; + case 'A': + case 'a': + codepoint += 0x0a00; + break; + case 'B': + case 'b': + codepoint += 0x0b00; + break; + case 'C': + case 'c': + codepoint += 0x0c00; + break; + case 'D': + case 'd': + codepoint += 0x0d00; + break; + case 'E': + case 'e': + codepoint += 0x0e00; + break; + case 'F': + case 'f': + codepoint += 0x0f00; + break; + default: + return -1; + } + + // byte 3: \uxxXx + switch (get()) + { + case '0': + break; + case '1': + codepoint += 0x0010; + break; + case '2': + codepoint += 0x0020; + break; + case '3': + codepoint += 0x0030; + break; + case '4': + codepoint += 0x0040; + break; + case '5': + codepoint += 0x0050; + break; + case '6': + codepoint += 0x0060; + break; + case '7': + codepoint += 0x0070; + break; + case '8': + codepoint += 0x0080; + break; + case '9': + codepoint += 0x0090; + break; + case 'A': + case 'a': + codepoint += 0x00a0; + break; + case 'B': + case 'b': + codepoint += 0x00b0; + break; + case 'C': + case 'c': + codepoint += 0x00c0; + break; + case 'D': + case 'd': + codepoint += 0x00d0; + break; + case 'E': + case 'e': + codepoint += 0x00e0; + break; + case 'F': + case 'f': + codepoint += 0x00f0; + break; + default: + return -1; + } + + // byte 4: \uxxxX + switch (get()) + { + case '0': + break; + case '1': + codepoint += 0x0001; + break; + case '2': + codepoint += 0x0002; + break; + case '3': + codepoint += 0x0003; + break; + case '4': + codepoint += 0x0004; + break; + case '5': + codepoint += 0x0005; + break; + case '6': + codepoint += 0x0006; + break; + case '7': + codepoint += 0x0007; + break; + case '8': + codepoint += 0x0008; + break; + case '9': + codepoint += 0x0009; + break; + case 'A': + case 'a': + codepoint += 0x000a; + break; + case 'B': + case 'b': + codepoint += 0x000b; + break; + case 'C': + case 'c': + codepoint += 0x000c; + break; + case 'D': + case 'd': + codepoint += 0x000d; + break; + case 'E': + case 'e': + codepoint += 0x000e; + break; + case 'F': + case 'f': + codepoint += 0x000f; + break; + default: + return -1; + } + + return codepoint; + } + + /*! + @brief create diagnostic representation of a codepoint + @return string "U+XXXX" for codepoint XXXX + */ + static std::string codepoint_to_string(int codepoint) + { + std::stringstream ss; + ss << "U+" << std::setw(4) << std::uppercase << std::setfill('0') << std::hex << codepoint; + return ss.str(); + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While + scanning, bytes are escaped and copied into buffer yytext. Then the + function returns successfully, yytext is null-terminated and yylen + contains the number of bytes in the string. + + @return token_type::value_string if string could be successfully + scanned, token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset yytext (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + assert(current == '\"'); + + while (true) + { + // get next character + get(); + + switch (current) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + // terminate yytext + add('\0'); + --yylen; + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } + // unicode escapes + case 'u': + { + int codepoint; + int codepoint1 = get_codepoint(); - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } + if (JSON_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; } -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) + // check if code point is a high surrogate + if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) { - case '.': + // expect next \uxxxx entry + if (JSON_LIKELY(get() == '\\' and get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_UNLIKELY(codepoint2 == -1)) { - add(decimal_point_char); - goto scan_number_decimal1; + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; } - case 'e': - case 'E': + // check if codepoint2 is a low surrogate + if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) { - add(current); - goto scan_number_exponent; + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; } - - default: + else { - goto scan_number_done; + error_message = "invalid string: surrogate " + codepoint_to_string(codepoint1) + + " must be followed by U+DC00..U+DFFF instead of " + codepoint_to_string(codepoint2); + return token_type::parse_error; } + } + else + { + error_message = "invalid string: surrogate " + codepoint_to_string(codepoint1) + + " must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) + else { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } + if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) + { + error_message = + "invalid string: surrogate " + codepoint_to_string(codepoint1) + " must follow U+D800..U+DBFF"; + return token_type::parse_error; + } - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } + // only work with first code point + codepoint = codepoint1; + } - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } + // result of the above calculation yields a proper codepoint + assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - default: - { - goto scan_number_done; - } + // translate code point to bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(codepoint); } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) + else if (codepoint <= 0x7ff) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } + // 2-byte characters: 110xxxxx 10xxxxxx + add(0xC0 | (codepoint >> 6)); + add(0x80 | (codepoint & 0x3F)); } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) + else if (codepoint <= 0xffff) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - { - goto scan_number_done; - } + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(0xE0 | (codepoint >> 12)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) + else { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(0xF0 | (codepoint >> 18)); + add(0x80 | ((codepoint >> 12) & 0x3F)); + add(0x80 | ((codepoint >> 6) & 0x3F)); + add(0x80 | (codepoint & 0x3F)); } -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } + break; + } - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + { + error_message = "invalid string: control character " + codepoint_to_string(current) + " must be escaped"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5d: + case 0x5e: + case 0x5f: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6a: + case 0x6b: + case 0x6c: + case 0x6d: + case 0x6e: + case 0x6f: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7c: + case 0x7d: + case 0x7e: + case 0x7f: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xc2: + case 0xc3: + case 0xc4: + case 0xc5: + case 0xc6: + case 0xc7: + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xd3: + case 0xd4: + case 0xd5: + case 0xd6: + case 0xd7: + case 0xd8: + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xe0: + { + add(current); + get(); + if (JSON_LIKELY(0xa0 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + } + + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xe1: + case 0xe2: + case 0xe3: + case 0xe4: + case 0xe5: + case 0xe6: + case 0xe7: + case 0xe8: + case 0xe9: + case 0xea: + case 0xeb: + case 0xec: + case 0xee: + case 0xef: + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + } + + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xed: + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0x9f)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + } + + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xf0: + { + add(current); + get(); + if (JSON_LIKELY(0x90 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + } + } -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } - default: - { - goto scan_number_done; - } + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xf1: + case 0xf2: + case 0xf3: + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } + } + } + + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xf4: + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0x8f)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + get(); + if (JSON_LIKELY(0x80 <= current and current <= 0xbf)) + { + add(current); + continue; + } } + } -scan_number_done: - // unget the character after the number (we only read it to know - // that we are done scanning a number) - --chars_read; - next_unget = true; + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } - // terminate token - add('\0'); - --yylen; + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - char* endptr = nullptr; - errno = 0; - const auto x = std::strtoull(yytext.data(), &endptr, 10); + static void strtof(float & f, const char * str, char ** endptr) noexcept + { + f = std::strtof(str, endptr); + } - // we checked the number format before - assert(endptr == yytext.data() + yylen); + static void strtof(double & f, const char * str, char ** endptr) noexcept + { + f = std::strtod(str, endptr); + } - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - char* endptr = nullptr; - errno = 0; - const auto x = std::strtoll(yytext.data(), &endptr, 10); + static void strtof(long double & f, const char * str, char ** endptr) noexcept + { + f = std::strtold(str, endptr); + } - // we checked the number format before - assert(endptr == yytext.data() + yylen); + /*! + @brief scan a number literal - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } + This function scans a string according to Sect. 6 of RFC 7159. + + The function is realized with a deterministic finite state machine + derived from the grammar described in RFC 7159. Starting in state + "init", the input is read and used to determined the next state. Only + state "done" accepts the number. State "error" is a trap state to model + errors. In the table below, "anything" means any character but the ones + listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in yytext. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() + { + // reset yytext to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + // all other characters are rejected outside scan_number() + assert(false); // LCOV_EXCL_LINE + } + } + + scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + + scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + { + goto scan_number_done; + } + } + + scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + { + goto scan_number_done; + } + } + + scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + + scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + { + goto scan_number_done; + } + } + + scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + + scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + + scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + goto scan_number_done; + } + } + + scan_number_done: + // unget the character after the number (we only read it to know + // that we are done scanning a number) + --chars_read; + next_unget = true; + + // terminate token + add('\0'); + --yylen; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + char * endptr = nullptr; + errno = 0; + const auto x = std::strtoull(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yylen); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + char * endptr = nullptr; + errno = 0; + const auto x = std::strtoll(yytext.data(), &endptr, 10); + + // we checked the number format before + assert(endptr == yytext.data() + yylen); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if + // an integer conversion above failed + strtof(value_float, yytext.data(), nullptr); + return token_type::value_float; + } + + token_type scan_true() + { + assert(current == 't'); + if (JSON_LIKELY((get() == 'r' and get() == 'u' and get() == 'e'))) + { + return token_type::literal_true; + } + + error_message = "invalid literal; expected 'true'"; + return token_type::parse_error; + } + + token_type scan_false() + { + assert(current == 'f'); + if (JSON_LIKELY((get() == 'a' and get() == 'l' and get() == 's' and get() == 'e'))) + { + return token_type::literal_false; + } + + error_message = "invalid literal; expected 'false'"; + return token_type::parse_error; + } + + token_type scan_null() + { + assert(current == 'n'); + if (JSON_LIKELY((get() == 'u' and get() == 'l' and get() == 'l'))) + { + return token_type::literal_null; + } - // this code is reached if we parse a floating-point number or if - // an integer conversion above failed - strtof(value_float, yytext.data(), nullptr); - return token_type::value_float; - } + error_message = "invalid literal; expected 'null'"; + return token_type::parse_error; + } - token_type scan_true() - { - assert(current == 't'); - if (JSON_LIKELY((get() == 'r' and get() == 'u' and get() == 'e'))) - { - return token_type::literal_true; - } + ///////////////////// + // input management + ///////////////////// - error_message = "invalid literal; expected 'true'"; - return token_type::parse_error; - } + /// reset yytext + void reset() noexcept + { + yylen = 0; + start_pos = chars_read - 1; + } - token_type scan_false() - { - assert(current == 'f'); - if (JSON_LIKELY((get() == 'a' and get() == 'l' and get() == 's' and get() == 'e'))) - { - return token_type::literal_false; - } + /// get a character from the input + int get() + { + ++chars_read; + return next_unget ? (next_unget = false, current) : (current = ia->get_character()); + } - error_message = "invalid literal; expected 'false'"; - return token_type::parse_error; - } + /// add a character to yytext + void add(int c) + { + // resize yytext if necessary; this condition is deemed unlikely, + // because we start with a 1024-byte buffer + if (JSON_UNLIKELY((yylen + 1 > yytext.capacity()))) + { + yytext.resize(2 * yytext.capacity(), '\0'); + } + yytext[yylen++] = static_cast(c); + } - token_type scan_null() - { - assert(current == 'n'); - if (JSON_LIKELY((get() == 'u' and get() == 'l' and get() == 'l'))) - { - return token_type::literal_null; - } + public: + ///////////////////// + // value getters + ///////////////////// - error_message = "invalid literal; expected 'null'"; - return token_type::parse_error; - } + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } - ///////////////////// - // input management - ///////////////////// + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } - /// reset yytext - void reset() noexcept - { - yylen = 0; - start_pos = chars_read - 1; - } + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } - /// get a character from the input - int get() - { - ++chars_read; - return next_unget - ? (next_unget = false, current) - : (current = ia->get_character()); - } + /// return string value + const std::string get_string() + { + // yytext cannot be returned as char*, because it may contain a + // null byte (parsed as "\u0000") + return std::string(yytext.data(), yylen); + } - /// add a character to yytext - void add(int c) - { - // resize yytext if necessary; this condition is deemed unlikely, - // because we start with a 1024-byte buffer - if (JSON_UNLIKELY((yylen + 1 > yytext.capacity()))) - { - yytext.resize(2 * yytext.capacity(), '\0'); - } - yytext[yylen++] = static_cast(c); - } + ///////////////////// + // diagnostics + ///////////////////// - public: - ///////////////////// - // value getters - ///////////////////// + /// return position of last read token + constexpr size_t get_position() const noexcept + { + return chars_read; + } - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } + /// return the last read token (for errors only) + std::string get_token_string() const + { + // get the raw byte sequence of the last token + std::string s = ia->read(start_pos, chars_read - start_pos); - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept + // escape control characters + std::string result; + for (auto c : s) + { + if (c == '\0' or c == std::char_traits::eof()) { - return value_unsigned; + // ignore EOF + continue; } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept + else if ('\x00' <= c and c <= '\x1f') { - return value_float; + // escape control characters + result += "<" + codepoint_to_string(c) + ">"; } - - /// return string value - const std::string get_string() + else { - // yytext cannot be returned as char*, because it may contain a - // null byte (parsed as "\u0000") - return std::string(yytext.data(), yylen); + // add character as is + result.append(1, c); } + } - ///////////////////// - // diagnostics - ///////////////////// + return result; + } - /// return position of last read token - constexpr size_t get_position() const noexcept - { - return chars_read; - } + /// return syntax error message + const std::string & get_error_message() const noexcept + { + return error_message; + } - /// return the last read token (for errors only) - std::string get_token_string() const - { - // get the raw byte sequence of the last token - std::string s = ia->read(start_pos, chars_read - start_pos); + ///////////////////// + // actual scanner + ///////////////////// - // escape control characters - std::string result; - for (auto c : s) - { - if (c == '\0' or c == std::char_traits::eof()) - { - // ignore EOF - continue; - } - else if ('\x00' <= c and c <= '\x1f') - { - // escape control characters - result += "<" + codepoint_to_string(c) + ">"; - } - else - { - // add character as is - result.append(1, c); - } - } + token_type scan() + { + // read next character and ignore whitespace + do + { + get(); + } while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + return scan_true(); + case 'f': + return scan_false(); + case 'n': + return scan_null(); + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } - return result; - } + private: + /// input adapter + input_adapter_t ia = nullptr; - /// return syntax error message - const std::string& get_error_message() const noexcept - { - return error_message; - } + /// the current character + int current = std::char_traits::eof(); - ///////////////////// - // actual scanner - ///////////////////// + /// whether get() should return the last character again + bool next_unget = false; - token_type scan() - { - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); + /// the number of characters read + size_t chars_read = 0; + /// the start position of the current token + size_t start_pos = 0; - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_true(); - case 'f': - return scan_false(); - case 'n': - return scan_null(); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } + /// buffer for variable-length tokens (numbers, strings) + std::vector yytext = std::vector(1024, '\0'); + /// current index in yytext + size_t yylen = 0; - private: - /// input adapter - input_adapter_t ia = nullptr; + /// a description of occurred lexer errors + std::string error_message = ""; - /// the current character - int current = std::char_traits::eof(); + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char decimal_point_char = '.'; + }; + + /*! + @brief syntax analysis + + This class implements a recursive decent parser. + */ + class parser + { + public: + /// a parser reading from an input adapter + explicit parser(input_adapter_t adapter, const parser_callback_t cb = nullptr) + : callback(cb) + , m_lexer(adapter) + { + } - /// whether get() should return the last character again - bool next_unget = false; + /*! + @brief public parser interface - /// the number of characters read - size_t chars_read = 0; - /// the start position of the current token - size_t start_pos = 0; + @param[in] strict whether to expect the last token to be EOF + @return parsed JSON value - /// buffer for variable-length tokens (numbers, strings) - std::vector yytext = std::vector(1024, '\0'); - /// current index in yytext - size_t yylen = 0; + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + basic_json parse(const bool strict = true) + { + // read first token + get_token(); - /// a description of occurred lexer errors - std::string error_message = ""; + basic_json result = parse_internal(true); + result.assert_invariant(); - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; + if (strict) + { + expect(lexer::token_type::end_of_input); + } - /// the decimal point - const char decimal_point_char = '.'; - }; + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : std::move(result); + } /*! - @brief syntax analysis + @brief public accept interface - This class implements a recursive decent parser. + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text */ - class parser + bool accept(const bool strict = true) { - public: - /// a parser reading from an input adapter - explicit parser(input_adapter_t adapter, - const parser_callback_t cb = nullptr) - : callback(cb), m_lexer(adapter) - {} + // read first token + get_token(); - /*! - @brief public parser interface - - @param[in] strict whether to expect the last token to be EOF - @return parsed JSON value + if (not accept_internal()) + { + return false; + } - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - basic_json parse(const bool strict = true) - { - // read first token - get_token(); + if (strict and last_token != lexer::token_type::end_of_input) + { + return false; + } - basic_json result = parse_internal(true); - result.assert_invariant(); + return true; + } - if (strict) - { - expect(lexer::token_type::end_of_input); - } + private: + /*! + @brief the actual parser + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + basic_json parse_internal(bool keep) + { + auto result = basic_json(value_t::discarded); - // return parser result and replace it with null in case the - // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : std::move(result); + switch (last_token) + { + case lexer::token_type::begin_object: + { + if (keep and (not callback or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; } - /*! - @brief public accept interface + // read next token + get_token(); - @param[in] strict whether to expect the last token to be EOF - @return whether the input is a proper JSON text - */ - bool accept(const bool strict = true) + // closing } -> we are done + if (last_token == lexer::token_type::end_object) { - // read first token - get_token(); + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // parse values + while (true) + { + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); - if (not accept_internal()) + bool keep_tag = false; + if (keep) + { + if (callback) { - return false; + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); } - - if (strict and last_token != lexer::token_type::end_of_input) + else { - return false; + keep_tag = true; } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } - return true; + // comma -> next value + if (last_token == lexer::token_type::value_separator) + { + get_token(); + continue; + } + + // closing } + expect(lexer::token_type::end_object); + get_token(); + break; } - private: - /*! - @brief the actual parser - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - */ - basic_json parse_internal(bool keep) + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) { - auto result = basic_json(value_t::discarded); + result = basic_json(value_t::discarded); + } - switch (last_token) - { - case lexer::token_type::begin_object: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) - { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } - - // read next token - get_token(); - - // closing } -> we are done - if (last_token == lexer::token_type::end_object) - { - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // parse values - while (true) - { - // store key - expect(lexer::token_type::value_string); - const auto key = m_lexer.get_string(); - - bool keep_tag = false; - if (keep) - { - if (callback) - { - basic_json k(key); - keep_tag = callback(depth, parse_event_t::key, k); - } - else - { - keep_tag = true; - } - } - - // parse separator (:) - get_token(); - expect(lexer::token_type::name_separator); - - // parse and add value - get_token(); - auto value = parse_internal(keep); - if (keep and keep_tag and not value.is_discarded()) - { - result[key] = std::move(value); - } - - // comma -> next value - if (last_token == lexer::token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - expect(lexer::token_type::end_object); - get_token(); - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } + return result; + } - case lexer::token_type::begin_array: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) - { - // explicitly set result to object to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; - } - - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == lexer::token_type::end_array) - { - get_token(); - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; - } - - // parse values - while (true) - { - // parse value - auto value = parse_internal(keep); - if (keep and not value.is_discarded()) - { - result.push_back(std::move(value)); - } - - // comma -> next value - if (last_token == lexer::token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - expect(lexer::token_type::end_array); - get_token(); - break; - } - - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - - return result; - } + case lexer::token_type::begin_array: + { + if (keep and (not callback or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } - case lexer::token_type::literal_null: - { - result.m_type = value_t::null; - get_token(); - break; - } + // read next token + get_token(); - case lexer::token_type::value_string: - { - result = basic_json(m_lexer.get_string()); - get_token(); - break; - } + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } - case lexer::token_type::literal_true: - { - result.m_type = value_t::boolean; - result.m_value = true; - get_token(); - break; - } + // parse values + while (true) + { + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) + { + result.push_back(std::move(value)); + } - case lexer::token_type::literal_false: - { - result.m_type = value_t::boolean; - result.m_value = false; - get_token(); - break; - } + // comma -> next value + if (last_token == lexer::token_type::value_separator) + { + get_token(); + continue; + } - case lexer::token_type::value_unsigned: - { - result.m_type = value_t::number_unsigned; - result.m_value = m_lexer.get_number_unsigned(); - get_token(); - break; - } + // closing ] + expect(lexer::token_type::end_array); + get_token(); + break; + } - case lexer::token_type::value_integer: - { - result.m_type = value_t::number_integer; - result.m_value = m_lexer.get_number_integer(); - get_token(); - break; - } + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } - case lexer::token_type::value_float: - { - result.m_type = value_t::number_float; - result.m_value = m_lexer.get_number_float(); + return result; + } + + case lexer::token_type::literal_null: + { + result.m_type = value_t::null; + get_token(); + break; + } + + case lexer::token_type::value_string: + { + result = basic_json(m_lexer.get_string()); + get_token(); + break; + } + + case lexer::token_type::literal_true: + { + result.m_type = value_t::boolean; + result.m_value = true; + get_token(); + break; + } + + case lexer::token_type::literal_false: + { + result.m_type = value_t::boolean; + result.m_value = false; + get_token(); + break; + } + + case lexer::token_type::value_unsigned: + { + result.m_type = value_t::number_unsigned; + result.m_value = m_lexer.get_number_unsigned(); + get_token(); + break; + } + + case lexer::token_type::value_integer: + { + result.m_type = value_t::number_integer; + result.m_value = m_lexer.get_number_integer(); + get_token(); + break; + } + + case lexer::token_type::value_float: + { + result.m_type = value_t::number_float; + result.m_value = m_lexer.get_number_float(); + + // throw in case of infinity or NAN + if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); + } + + get_token(); + break; + } + + default: + { + // the last token was unexpected + unexpect(last_token); + } + } + + if (keep and callback and not callback(depth, parse_event_t::value, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + /*! + @brief the acutal acceptor + */ + bool accept_internal() + { + switch (last_token) + { + case lexer::token_type::begin_object: + { + // read next token + get_token(); + + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + return true; + } + + // parse values + while (true) + { + // parse key + if (last_token != lexer::token_type::value_string) + { + return false; + } + + // parse separator (:) + get_token(); + if (last_token != lexer::token_type::name_separator) + { + return false; + } + + // parse value + get_token(); + if (not accept_internal()) + { + return false; + } + + // comma -> next value + if (last_token == lexer::token_type::value_separator) + { + get_token(); + continue; + } - // throw in case of infinity or NAN - if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float))) - { - JSON_THROW(out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); - } + // closing } + if (last_token != lexer::token_type::end_object) + { + return false; + } - get_token(); - break; - } + get_token(); + return true; + } + } - default: - { - // the last token was unexpected - unexpect(last_token); - } - } + case lexer::token_type::begin_array: + { + // read next token + get_token(); - if (keep and callback and not callback(depth, parse_event_t::value, result)) - { - result = basic_json(value_t::discarded); - } - return result; + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) + { + get_token(); + return true; } - /*! - @brief the acutal acceptor - */ - bool accept_internal() + // parse values + while (true) { - switch (last_token) - { - case lexer::token_type::begin_object: - { - // read next token - get_token(); - - // closing } -> we are done - if (last_token == lexer::token_type::end_object) - { - get_token(); - return true; - } - - // parse values - while (true) - { - // parse key - if (last_token != lexer::token_type::value_string) - { - return false; - } - - // parse separator (:) - get_token(); - if (last_token != lexer::token_type::name_separator) - { - return false; - } - - // parse value - get_token(); - if (not accept_internal()) - { - return false; - } - - // comma -> next value - if (last_token == lexer::token_type::value_separator) - { - get_token(); - continue; - } - - // closing } - if (last_token != lexer::token_type::end_object) - { - return false; - } - - get_token(); - return true; - } - } + // parse value + if (not accept_internal()) + { + return false; + } - case lexer::token_type::begin_array: - { - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == lexer::token_type::end_array) - { - get_token(); - return true; - } - - // parse values - while (true) - { - // parse value - if (not accept_internal()) - { - return false; - } - - // comma -> next value - if (last_token == lexer::token_type::value_separator) - { - get_token(); - continue; - } - - // closing ] - if (last_token != lexer::token_type::end_array) - { - return false; - } - - get_token(); - return true; - } - } + // comma -> next value + if (last_token == lexer::token_type::value_separator) + { + get_token(); + continue; + } + + // closing ] + if (last_token != lexer::token_type::end_array) + { + return false; + } + + get_token(); + return true; + } + } + + case lexer::token_type::literal_null: + case lexer::token_type::value_string: + case lexer::token_type::literal_true: + case lexer::token_type::literal_false: + case lexer::token_type::value_unsigned: + case lexer::token_type::value_integer: + case lexer::token_type::value_float: + { + get_token(); + return true; + } + + default: + { + // the last token was unexpected + return false; + } + } + } - case lexer::token_type::literal_null: - case lexer::token_type::value_string: - case lexer::token_type::literal_true: - case lexer::token_type::literal_false: - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - { - get_token(); - return true; - } + /// get next token from lexer + typename lexer::token_type get_token() + { + last_token = m_lexer.scan(); + return last_token; + } - default: - { - // the last token was unexpected - return false; - } - } + /*! + @throw parse_error.101 if expected token did not occur + */ + void expect(typename lexer::token_type t) const + { + if (JSON_UNLIKELY(t != last_token)) + { + std::string error_msg = "syntax error - "; + if (last_token == lexer::token_type::parse_error) + { + error_msg += m_lexer.get_error_message() + "; last read: '" + m_lexer.get_token_string() + "'"; } - - /// get next token from lexer - typename lexer::token_type get_token() + else { - last_token = m_lexer.scan(); - return last_token; + error_msg += "unexpected " + std::string(lexer::token_type_name(last_token)); } - /*! - @throw parse_error.101 if expected token did not occur - */ - void expect(typename lexer::token_type t) const - { - if (JSON_UNLIKELY(t != last_token)) - { - std::string error_msg = "syntax error - "; - if (last_token == lexer::token_type::parse_error) - { - error_msg += m_lexer.get_error_message() + "; last read: '" + m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer::token_type_name(last_token)); - } + error_msg += "; expected " + std::string(lexer::token_type_name(t)); + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + } - error_msg += "; expected " + std::string(lexer::token_type_name(t)); - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); - } + /*! + @throw parse_error.101 if unexpected token occurred + */ + void unexpect(typename lexer::token_type t) const + { + if (JSON_UNLIKELY(t == last_token)) + { + std::string error_msg = "syntax error - "; + if (last_token == lexer::token_type::parse_error) + { + error_msg += m_lexer.get_error_message() + "; last read '" + m_lexer.get_token_string() + "'"; } - - /*! - @throw parse_error.101 if unexpected token occurred - */ - void unexpect(typename lexer::token_type t) const + else { - if (JSON_UNLIKELY(t == last_token)) - { - std::string error_msg = "syntax error - "; - if (last_token == lexer::token_type::parse_error) - { - error_msg += m_lexer.get_error_message() + "; last read '" + m_lexer.get_token_string() + "'"; - } - else - { - error_msg += "unexpected " + std::string(lexer::token_type_name(last_token)); - } - - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); - } + error_msg += "unexpected " + std::string(lexer::token_type_name(last_token)); } - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - typename lexer::token_type last_token = lexer::token_type::uninitialized; - /// the lexer - lexer m_lexer; - }; + JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + } + } + + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; + +public: + /*! + @brief JSON Pointer + + A JSON pointer defines a string syntax for identifying a specific value + within a JSON document. It can be used with functions `at` and + `operator[]`. Furthermore, JSON pointers are the base for JSON patches. + + @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + class json_pointer + { + /// allow basic_json to access private members + friend class basic_json; public: /*! - @brief JSON Pointer + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the + empty string is assumed which references the whole JSON + value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and + does not begin with a slash (`/`); see example below - A JSON pointer defines a string syntax for identifying a specific value - within a JSON document. It can be used with functions `at` and - `operator[]`. Furthermore, JSON pointers are the base for JSON patches. + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s + is not followed by `0` (representing `~`) or `1` (representing `/`); + see example below - @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + @liveexample{The example shows the construction several valid JSON + pointers as well as the exceptional behavior.,json_pointer} @since version 2.0.0 */ - class json_pointer + explicit json_pointer(const std::string & s = "") + : reference_tokens(split(s)) { - /// allow basic_json to access private members - friend class basic_json; + } - public: - /*! - @brief create JSON pointer + /*! + @brief return a string representation of the JSON pointer - Create a JSON pointer according to the syntax described in - [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode - @param[in] s string representing the JSON pointer; if omitted, the - empty string is assumed which references the whole JSON - value + @return a string representation of the JSON pointer - @throw parse_error.107 if the given JSON pointer @a s is nonempty and - does not begin with a slash (`/`); see example below + @liveexample{The example shows the result of `to_string`., + json_pointer__to_string} - @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s - is not followed by `0` (representing `~`) or `1` (representing `/`); - see example below + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate( + reference_tokens.begin(), + reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) { + return a + "/" + escape(b); + }); + } - @liveexample{The example shows the construction several valid JSON - pointers as well as the exceptional behavior.,json_pointer} + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } - @since version 2.0.0 - */ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} + private: + /*! + @brief remove and return last reference pointer + @throw out_of_range.405 if JSON pointer has no parent + */ + std::string pop_back() + { + if (is_root()) + { + JSON_THROW(out_of_range::create(405, "JSON pointer has no parent")); + } + + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } + + /// return whether pointer points to the root document + bool is_root() const + { + return reference_tokens.empty(); + } - /*! - @brief return a string representation of the JSON pointer + json_pointer top() const + { + if (is_root()) + { + JSON_THROW(out_of_range::create(405, "JSON pointer has no parent")); + } - @invariant For each JSON pointer `ptr`, it holds: - @code {.cpp} - ptr == json_pointer(ptr.to_string()); - @endcode + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } - @return a string representation of the JSON pointer + /*! + @brief create and return a reference to the pointed to value - @liveexample{The example shows the result of `to_string`., - json_pointer__to_string} + @complexity Linear in the number of reference tokens. - @since version 2.0.0 - */ - std::string to_string() const noexcept + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + reference get_and_create(reference j) const + { + pointer result = &j; + + // in case no reference tokens exist, return a reference to the + // JSON value j which will be overwritten by a primitive value + for (const auto & reference_token : reference_tokens) + { + switch (result->m_type) { - return std::accumulate(reference_tokens.begin(), - reference_tokens.end(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); + case value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; } - /// @copydoc to_string() - operator std::string() const + case value_t::object: { - return to_string(); + // create an entry in the object + result = &result->operator[](reference_token); + break; } - private: - /*! - @brief remove and return last reference pointer - @throw out_of_range.405 if JSON pointer has no parent - */ - std::string pop_back() + case value_t::array: { - if (is_root()) - { - JSON_THROW(out_of_range::create(405, "JSON pointer has no parent")); - } - - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; + // create an entry in the array + JSON_TRY + { + result = &result->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument &) + { + JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; } - /// return whether pointer points to the root document - bool is_root() const + /* + The following code is only reached if there exists a + reference token _and_ the current value is primitive. In + this case, we have an error situation, because primitive + values may only occur as single value; that is, with an + empty list of reference tokens. + */ + default: { - return reference_tokens.empty(); + JSON_THROW(type_error::create(313, "invalid value to unflatten")); } + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries + to create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer - json_pointer top() const + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + reference get_unchecked(pointer ptr) const + { + for (const auto & reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->m_type == value_t::null) { - if (is_root()) - { - JSON_THROW(out_of_range::create(405, "JSON pointer has no parent")); - } + // check if reference token is a number + const bool nums = std::all_of(reference_token.begin(), reference_token.end(), [](const char x) { + return (x >= '0' and x <= '9'); + }); - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; + // change value to array for numbers or "-" or to object + // otherwise + if (nums or reference_token == "-") + { + *ptr = value_t::array; + } + else + { + *ptr = value_t::object; + } } - /*! - @brief create and return a reference to the pointed to value - - @complexity Linear in the number of reference tokens. + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } - @throw parse_error.109 if array index is not a number - @throw type_error.313 if value cannot be unflattened - */ - reference get_and_create(reference j) const + case value_t::array: { - pointer result = &j; + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); + } - // in case no reference tokens exist, return a reference to the - // JSON value j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + JSON_TRY { - switch (result->m_type) - { - case value_t::null: - { - if (reference_token == "0") - { - // start a new array if reference token is 0 - result = &result->operator[](0); - } - else - { - // start a new object otherwise - result = &result->operator[](reference_token); - } - break; - } - - case value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - - case value_t::array: - { - // create an entry in the array - JSON_TRY - { - result = &result->operator[](static_cast(std::stoi(reference_token))); - } - JSON_CATCH (std::invalid_argument&) - { - JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - /* - The following code is only reached if there exists a - reference token _and_ the current value is primitive. In - this case, we have an error situation, because primitive - values may only occur as single value; that is, with an - empty list of reference tokens. - */ - default: - { - JSON_THROW(type_error::create(313, "invalid value to unflatten")); - } - } + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); } + JSON_CATCH(std::invalid_argument &) + { + JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + } + break; + } - return *result; + default: + { + JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } } + } - /*! - @brief return a reference to the pointed to value + return *ptr; + } - @note This version does not throw if a value is not present, but tries - to create nested values instead. For instance, calling this function - with pointer `"/this/that"` on a null value is equivalent to calling - `operator[]("this").operator[]("that")` on that value, effectively - changing the null value to an object. + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + reference get_checked(pointer ptr) const + { + for (const auto & reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } - @param[in] ptr a JSON value + case value_t::array: + { + if (reference_token == "-") + { + // "-" always fails the range check + JSON_THROW(out_of_range::create( + 402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range")); + } - @return reference to the JSON value pointed to by the JSON pointer + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); + } - @complexity Linear in the length of the JSON pointer. + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument &) + { + JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - reference get_unchecked(pointer ptr) const + default: { - for (const auto& reference_token : reference_tokens) - { - // convert null values to arrays or objects before continuing - if (ptr->m_type == value_t::null) - { - // check if reference token is a number - const bool nums = std::all_of(reference_token.begin(), - reference_token.end(), - [](const char x) - { - return (x >= '0' and x <= '9'); - }); - - // change value to array for numbers or "-" or to object - // otherwise - if (nums or reference_token == "-") - { - *ptr = value_t::array; - } - else - { - *ptr = value_t::object; - } - } + JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + } - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); - } - - if (reference_token == "-") - { - // explicitly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); - } - else - { - // convert array index to number; unchecked access - JSON_TRY - { - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); - } - JSON_CATCH (std::invalid_argument&) - { - JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - } - break; - } - - default: - { - JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - } + return *ptr; + } - return *ptr; - } + /*! + @brief return a const reference to the pointed to value - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - reference get_checked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - JSON_THROW(out_of_range::create(402, "array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - } - JSON_CATCH (std::invalid_argument&) - { - JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - { - JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - } + @param[in] ptr a JSON value - return *ptr; + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const_reference get_unchecked(const_pointer ptr) const + { + for (const auto & reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; } - /*! - @brief return a const reference to the pointed to value + case value_t::array: + { + if (reference_token == "-") + { + // "-" cannot be used for const access + JSON_THROW(out_of_range::create( + 402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range")); + } - @param[in] ptr a JSON value + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); + } - @return const reference to the JSON value pointed to by the JSON - pointer + // use unchecked array access + JSON_TRY + { + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument &) + { + JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; + } - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const_reference get_unchecked(const_pointer ptr) const + default: { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" cannot be used for const access - JSON_THROW(out_of_range::create(402, "array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); - } - - // use unchecked array access - JSON_TRY - { - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); - } - JSON_CATCH (std::invalid_argument&) - { - JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - { - JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - } + JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + } + + return *ptr; + } - return *ptr; + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const_reference get_checked(const_pointer ptr) const + { + for (const auto & reference_token : reference_tokens) + { + switch (ptr->m_type) + { + case value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; } - /*! - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved - */ - const_reference get_checked(const_pointer ptr) const + case value_t::array: { - for (const auto& reference_token : reference_tokens) - { - switch (ptr->m_type) - { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: - { - if (reference_token == "-") - { - // "-" always fails the range check - JSON_THROW(out_of_range::create(402, "array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range")); - } - - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') - { - JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); - } - - // note: at performs range check - JSON_TRY - { - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - } - JSON_CATCH (std::invalid_argument&) - { - JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); - } - break; - } - - default: - { - JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); - } - } - } + if (reference_token == "-") + { + // "-" always fails the range check + JSON_THROW(out_of_range::create( + 402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range")); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + JSON_THROW(parse_error::create(106, 0, "array index '" + reference_token + "' must not begin with '0'")); + } - return *ptr; + // note: at performs range check + JSON_TRY + { + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + } + JSON_CATCH(std::invalid_argument &) + { + JSON_THROW(parse_error::create(109, 0, "array index '" + reference_token + "' is not a number")); + } + break; } - /*! - @brief split the string input to reference tokens + default: + { + JSON_THROW(out_of_range::create(404, "unresolved reference token '" + reference_token + "'")); + } + } + } - @note This function is only called by the json_pointer constructor. - All exceptions below are documented there. + return *ptr; + } - @throw parse_error.107 if the pointer is not empty or begins with '/' - @throw parse_error.108 if character '~' is not followed by '0' or '1' - */ - static std::vector split(const std::string& reference_string) - { - std::vector result; + /*! + @brief split the string input to reference tokens - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; - } + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. - // check if nonempty reference string begins with slash - if (reference_string[0] != '/') - { - JSON_THROW(parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'")); - } + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string & reference_string) + { + std::vector result; - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - size_t slash = reference_string.find_first_of('/', 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of('/', start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); - - // check reference tokens are properly escaped - for (size_t pos = reference_token.find_first_of('~'); - pos != std::string::npos; - pos = reference_token.find_first_of('~', pos + 1)) - { - assert(reference_token[pos] == '~'); - - // ~ must be followed by 0 or 1 - if (pos == reference_token.size() - 1 or - (reference_token[pos + 1] != '0' and - reference_token[pos + 1] != '1')) - { - JSON_THROW(parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); - } - } + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (reference_string[0] != '/') + { + JSON_THROW(parse_error::create( + 107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'")); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (size_t pos = reference_token.find_first_of('~'); pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + assert(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (pos == reference_token.size() - 1 or + (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) + { + JSON_THROW(parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); + } + } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + /*! + @brief replace all occurrences of a substring by another string + + @param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t + @param[in] f the substring to replace with @a t + @param[in] t the string to replace @a f + + @pre The search string @a f must not be empty. **This precondition is + enforced with an assertion.** - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); - } + @since version 2.0.0 + */ + static void replace_substring(std::string & s, const std::string & f, const std::string & t) + { + assert(not f.empty()); - return result; - } + for (size_t pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t + pos = s.find(f, pos + t.size()) // find next occurrence of f + ) + ; + } - /*! - @brief replace all occurrences of a substring by another string + /// escape tilde and slash + static std::string escape(std::string s) + { + // escape "~"" to "~0" and "/" to "~1" + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } - @param[in,out] s the string to manipulate; changed so that all - occurrences of @a f are replaced with @a t - @param[in] f the substring to replace with @a t - @param[in] t the string to replace @a f + /// unescape tilde and slash + static void unescape(std::string & s) + { + // first transform any occurrence of the sequence '~1' to '/' + replace_substring(s, "~1", "/"); + // then transform any occurrence of the sequence '~0' to '~' + replace_substring(s, "~0", "~"); + } - @pre The search string @a f must not be empty. **This precondition is - enforced with an assertion.** + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to - @since version 2.0.0 - */ - static void replace_substring(std::string& s, - const std::string& f, - const std::string& t) + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string & reference_string, const basic_json & value, basic_json & result) + { + switch (value.m_type) + { + case value_t::array: + { + if (value.m_value.array->empty()) { - assert(not f.empty()); - - for ( - size_t pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t - pos = s.find(f, pos + t.size()) // find next occurrence of f - ); + // flatten empty array as null + result[reference_string] = nullptr; } - - /// escape tilde and slash - static std::string escape(std::string s) + else { - // escape "~"" to "~0" and "/" to "~1" - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; + // iterate array and use index as reference string + for (size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), value.m_value.array->operator[](i), result); + } } + break; + } - /// unescape tilde and slash - static void unescape(std::string& s) + case value_t::object: + { + if (value.m_value.object->empty()) { - // first transform any occurrence of the sequence '~1' to '/' - replace_substring(s, "~1", "/"); - // then transform any occurrence of the sequence '~0' to '~' - replace_substring(s, "~0", "~"); + // flatten empty object as null + result[reference_string] = nullptr; } - - /*! - @param[in] reference_string the reference string to the current value - @param[in] value the value to consider - @param[in,out] result the result object to insert values to - - @note Empty objects or arrays are flattened to `null`. - */ - static void flatten(const std::string& reference_string, - const basic_json& value, - basic_json& result) + else { - switch (value.m_type) - { - case value_t::array: - { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else - { - // iterate array and use index as reference string - for (size_t i = 0; i < value.m_value.array->size(); ++i) - { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); - } - } - break; - } + // iterate object and use keys as reference string + for (const auto & element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), element.second, result); + } + } + break; + } - case value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else - { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) - { - flatten(reference_string + "/" + escape(element.first), - element.second, result); - } - } - break; - } + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; - } - } - } + /*! + @param[in] value flattened JSON - /*! - @param[in] value flattened JSON + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static basic_json unflatten(const basic_json & value) + { + if (not value.is_object()) + { + JSON_THROW(type_error::create(314, "only objects can be unflattened")); + } - @return unflattened JSON + basic_json result; - @throw parse_error.109 if array index is not a number - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitive - @throw type_error.313 if value cannot be unflattened - */ - static basic_json unflatten(const basic_json& value) + // iterate the JSON object values + for (const auto & element : *value.m_value.object) + { + if (not element.second.is_primitive()) { - if (not value.is_object()) - { - JSON_THROW(type_error::create(314, "only objects can be unflattened")); - } - - basic_json result; + JSON_THROW(type_error::create(315, "values in object must be primitive")); + } - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (not element.second.is_primitive()) - { - JSON_THROW(type_error::create(315, "values in object must be primitive")); - } + // assign value to reference pointed to by JSON pointer; Note + // that if the JSON pointer is "" (i.e., points to the whole + // value), function get_and_create returns a reference to + // result itself. An assignment will then create a primitive + // value. + json_pointer(element.first).get_and_create(result) = element.second; + } - // assign value to reference pointed to by JSON pointer; Note - // that if the JSON pointer is "" (i.e., points to the whole - // value), function get_and_create returns a reference to - // result itself. An assignment will then create a primitive - // value. - json_pointer(element.first).get_and_create(result) = element.second; - } + return result; + } - return result; - } + friend bool operator==(json_pointer const & lhs, json_pointer const & rhs) noexcept + { + return lhs.reference_tokens == rhs.reference_tokens; + } - friend bool operator==(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return lhs.reference_tokens == rhs.reference_tokens; - } + friend bool operator!=(json_pointer const & lhs, json_pointer const & rhs) noexcept + { + return !(lhs == rhs); + } - friend bool operator!=(json_pointer const& lhs, - json_pointer const& rhs) noexcept - { - return !(lhs == rhs); - } + /// the reference tokens + std::vector reference_tokens{}; + }; - /// the reference tokens - std::vector reference_tokens {}; - }; + ////////////////////////// + // JSON Pointer support // + ////////////////////////// - ////////////////////////// - // JSON Pointer support // - ////////////////////////// + /// @name JSON Pointer functions + /// @{ - /// @name JSON Pointer functions - /// @{ + /*! + @brief access specified element via JSON Pointer - /*! - @brief access specified element via JSON Pointer + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. Similar to @ref operator[](const typename - object_t::key_type&), `null` values are created in arrays and objects if - necessary. + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. - In particular: - - If the JSON pointer points to an object key that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. - - If the JSON pointer points to an array index that does not exist, it - is created an filled with a `null` value before a reference to it - is returned. All indices between the current maximum and the given - index are also filled with `null`. - - The special value `-` is treated as a synonym for the index past the - end. + @param[in] ptr a JSON pointer - @param[in] ptr a JSON pointer + @return reference to the element pointed to by @a ptr - @return reference to the element pointed to by @a ptr + @complexity Constant. - @complexity Constant. + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.404 if the JSON pointer can not be resolved + @liveexample{The behavior is shown in the example.,operatorjson_pointer} - @liveexample{The behavior is shown in the example.,operatorjson_pointer} + @since version 2.0.0 + */ + reference operator[](const json_pointer & ptr) + { + return ptr.get_unchecked(this); + } - @since version 2.0.0 - */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } + /*! + @brief access specified element via JSON Pointer - /*! - @brief access specified element via JSON Pointer + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the the special value + `-` yields an exception. - Uses a JSON pointer to retrieve a reference to the respective JSON value. - No bound checking is performed. The function does not change the JSON - value; no `null` values are created. In particular, the the special value - `-` yields an exception. + @param[in] ptr JSON pointer to the desired element - @param[in] ptr JSON pointer to the desired element + @return const reference to the element pointed to by @a ptr - @return const reference to the element pointed to by @a ptr + @complexity Constant. - @complexity Constant. + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved - @throw parse_error.106 if an array index begins with '0' - @throw parse_error.109 if an array index was not a number - @throw out_of_range.402 if the array index '-' is used - @throw out_of_range.404 if the JSON pointer can not be resolved + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} - @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + @since version 2.0.0 + */ + const_reference operator[](const json_pointer & ptr) const + { + return ptr.get_unchecked(this); + } - @since version 2.0.0 - */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } + /*! + @brief access specified element via JSON Pointer - /*! - @brief access specified element via JSON Pointer + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. - Returns a reference to the element at with specified JSON pointer @a ptr, - with bounds checking. + @param[in] ptr JSON pointer to the desired element - @param[in] ptr JSON pointer to the desired element + @return reference to the element pointed to by @a ptr - @return reference to the element pointed to by @a ptr + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + @complexity Constant. - @complexity Constant. + @since version 2.0.0 - @since version 2.0.0 + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer & ptr) + { + return ptr.get_checked(this); + } - @liveexample{The behavior is shown in the example.,at_json_pointer} - */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } + /*! + @brief access specified element via JSON Pointer - /*! - @brief access specified element via JSON Pointer + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. - Returns a const reference to the element at with specified JSON pointer @a - ptr, with bounds checking. + @param[in] ptr JSON pointer to the desired element - @param[in] ptr JSON pointer to the desired element + @return reference to the element pointed to by @a ptr - @return reference to the element pointed to by @a ptr + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. - @throw parse_error.106 if an array index in the passed JSON pointer @a ptr - begins with '0'. See example below. + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. - @throw parse_error.109 if an array index in the passed JSON pointer @a ptr - is not a number. See example below. + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. - @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr - is out of range. See example below. + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. - @throw out_of_range.402 if the array index '-' is used in the passed JSON - pointer @a ptr. As `at` provides checked access (and no elements are - implicitly inserted), the index '-' is always invalid. See example below. + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. - @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. - See example below. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. - @exceptionsafety Strong guarantee: if an exception is thrown, there are no - changes in the JSON value. + @complexity Constant. - @complexity Constant. + @since version 2.0.0 - @since version 2.0.0 + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer & ptr) const + { + return ptr.get_checked(this); + } - @liveexample{The behavior is shown in the example.,at_json_pointer_const} - */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } + /*! + @brief return flattened JSON value - /*! - @brief return flattened JSON value + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. - The function creates a JSON object whose keys are JSON pointers (see [RFC - 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all - primitive. The original JSON value can be restored using the @ref - unflatten() function. + @return an object that maps JSON pointers to primitive values - @return an object that maps JSON pointers to primitive values + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. - @note Empty objects and arrays are flattened to `null` and will not be - reconstructed correctly by the @ref unflatten() function. + @complexity Linear in the size the JSON value. - @complexity Linear in the size the JSON value. + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} - @liveexample{The following code shows how a JSON object is flattened to an - object whose keys consist of JSON pointers.,flatten} + @sa @ref unflatten() for the reverse function - @sa @ref unflatten() for the reverse function + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } - @since version 2.0.0 - */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } + /*! + @brief unflatten a previously flattened JSON value - /*! - @brief unflatten a previously flattened JSON value + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. - The function restores the arbitrary nesting of a JSON value that has been - flattened before using the @ref flatten() function. The JSON value must - meet certain constraints: - 1. The value must be an object. - 2. The keys must be JSON pointers (see - [RFC 6901](https://tools.ietf.org/html/rfc6901)) - 3. The mapped values must be primitive JSON types. + @return the original JSON from a flattened version - @return the original JSON from a flattened version + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. - @note Empty objects and arrays are flattened by @ref flatten() to `null` - values and can not unflattened to their original type. Apart from - this example, for a JSON value `j`, the following is always true: - `j == j.flatten().unflatten()`. + @complexity Linear in the size the JSON value. - @complexity Linear in the size the JSON value. + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitve - @throw type_error.314 if value is not an object - @throw type_error.315 if object values are not primitve + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} - @liveexample{The following code shows how a flattened JSON object is - unflattened into the original nested JSON object.,unflatten} + @sa @ref flatten() for the reverse function - @sa @ref flatten() for the reverse function + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } - @since version 2.0.0 - */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } + /// @} - /// @} + ////////////////////////// + // JSON Patch functions // + ////////////////////////// - ////////////////////////// - // JSON Patch functions // - ////////////////////////// + /// @name JSON Patch functions + /// @{ - /// @name JSON Patch functions - /// @{ + /*! + @brief applies a JSON patch - /*! - @brief applies a JSON patch + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. - [JSON Patch](http://jsonpatch.com) defines a JSON document structure for - expressing a sequence of operations to apply to a JSON) document. With - this function, a JSON Patch is applied to the current JSON value by - executing all operations from the patch. + @param[in] json_patch JSON patch document + @return patched document - @param[in] json_patch JSON patch document - @return patched document + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. - @note The application of a patch is atomic: Either all operations succeed - and the patched document is returned or an exception is thrown. In - any case, the original value is not changed: the patch is applied - to a copy of the value. + @throw parse_error.104 if the JSON patch does not consist of an array of + objects - @throw parse_error.104 if the JSON patch does not consist of an array of - objects + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` - @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory - attributes are missing); example: `"operation add must have member path"` + @throw out_of_range.401 if an array index is out of range. - @throw out_of_range.401 if an array index is out of range. + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` - @throw out_of_range.403 if a JSON pointer inside the patch could not be - resolved successfully in the current JSON value; example: `"key baz not - found"` + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") - @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", - "move") + @throw other_error.501 if "test" operation was unsuccessful - @throw other_error.501 if "test" operation was unsuccessful + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. - @complexity Linear in the size of the JSON value and the length of the - JSON patch. As usually only a fraction of the JSON value is affected by - the patch, the complexity can usually be neglected. + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} - @liveexample{The following code shows how a JSON patch is applied to a - value.,patch} + @sa @ref diff -- create a JSON patch by comparing two JSON values - @sa @ref diff -- create a JSON patch by comparing two JSON values + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) - @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + @since version 2.0.0 + */ + basic_json patch(const basic_json & json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; - @since version 2.0.0 - */ - basic_json patch(const basic_json& json_patch) const + // the valid JSON Patch operations + enum class patch_operations { - // make a working copy to apply the patch to - basic_json result = *this; + add, + remove, + replace, + move, + copy, + test, + invalid + }; - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + const auto get_op = [](const std::string & op) { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; - const auto get_op = [](const std::string & op) + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) { + // adding to the root of the target document means replacing it + if (ptr.is_root()) + { + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json & parent = result[ptr]; - return patch_operations::invalid; - }; + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) + case value_t::array: { - // adding to the root of the target document means replacing it - if (ptr.is_root()) + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = std::stoi(last_path); + if (static_cast(idx) > parent.size()) { - result = val; + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); } else { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) - { - result.at(top_pointer); - } - - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; - - switch (parent.m_type) - { - case value_t::null: - case value_t::object: - { - // use operator[] to add value - parent[last_path] = val; - break; - } - - case value_t::array: - { - if (last_path == "-") - { - // special case: append to back - parent.push_back(val); - } - else - { - const auto idx = std::stoi(last_path); - if (static_cast(idx) > parent.size()) - { - // avoid undefined behavior - JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); - } - else - { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); - } - } - break; - } - - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE - } - } + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); } - }; + } + break; + } - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) + default: { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } + } + } + }; - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (it != parent.end()) - { - parent.erase(it); - } - else - { - JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast(std::stoi(last_path))); - } - }; + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json & parent = result.at(ptr); - // type check: top level value must be an array - if (not json_patch.is_array()) + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (it != parent.end()) + { + parent.erase(it); + } + else { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found")); } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(static_cast(std::stoi(last_path))); + } + }; + + // type check: top level value must be an array + if (not json_patch.is_array()) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } - // iterate and apply the operations - for (const auto& val : json_patch) + // iterate and apply the operations + for (const auto & val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val]( + const std::string & op, const std::string & member, bool string_type) -> basic_json & { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (it == val.m_value.object->end()) { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json& - { - // find value - auto it = val.m_value.object->find(member); + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); + } - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + // check if result is of type string + if (string_type and not it->second.is_string()) + { + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); + } - // check if desired value is present - if (it == val.m_value.object->end()) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'")); - } + // no error: return value + return it->second; + }; - // check if result is of type string - if (string_type and not it->second.is_string()) - { - JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); - } + // type check: every element of the array must be an object + if (not val.is_object()) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); + } - // no error: return value - return it->second; - }; + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); - // type check: every element of the array must be an object - if (not val.is_object()) - { - JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); - } + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); + case patch_operations::remove: + { + operation_remove(ptr); + break; + } - switch (get_op(op)) - { - case patch_operations::add: - { - operation_add(ptr, get_value("add", "value", false)); - break; - } + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } - case patch_operations::remove: - { - operation_remove(ptr); - break; - } + case patch_operations::move: + { + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); - - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); - - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; - } + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } - case patch_operations::copy: - { - const std::string from_path = get_value("copy", "from", true);; - const json_pointer from_ptr(from_path); + case patch_operations::copy: + { + const std::string from_path = get_value("copy", "from", true); + ; + const json_pointer from_ptr(from_path); - // the "from" location must exist - use at() - result[ptr] = result.at(from_ptr); - break; - } + // the "from" location must exist - use at() + result[ptr] = result.at(from_ptr); + break; + } - case patch_operations::test: - { - bool success = false; - JSON_TRY - { - // check if "value" matches the one at "path" - // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); - } - JSON_CATCH (out_of_range&) - { - // ignore out of range errors: success remains false - } - - // throw an exception if test fails - if (not success) - { - JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); - } - - break; - } + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_CATCH(out_of_range &) + { + // ignore out of range errors: success remains false + } - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); - } - } + // throw an exception if test fails + if (not success) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); } - return result; + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid")); + } + } } - /*! - @brief creates a diff as a JSON patch + return result; + } - Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can - be changed into the value @a target by calling @ref patch function. + /*! + @brief creates a diff as a JSON patch - @invariant For two JSON values @a source and @a target, the following code - yields always `true`: - @code {.cpp} - source.patch(diff(source, target)) == target; - @endcode + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. - @note Currently, only `remove`, `add`, and `replace` operations are - generated. + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode - @param[in] source JSON value to compare from - @param[in] target JSON value to compare against - @param[in] path helper value to create JSON pointers + @note Currently, only `remove`, `add`, and `replace` operations are + generated. - @return a JSON patch to convert the @a source to @a target + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers - @complexity Linear in the lengths of @a source and @a target. + @return a JSON patch to convert the @a source to @a target - @liveexample{The following code shows how a JSON patch is created as a - diff for two JSON values.,diff} + @complexity Linear in the lengths of @a source and @a target. - @sa @ref patch -- apply a JSON patch + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} - @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa @ref patch -- apply a JSON patch - @since version 2.0.0 - */ - static basic_json diff(const basic_json& source, - const basic_json& target, - const std::string& path = "") + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + static basic_json diff(const basic_json & source, const basic_json & target, const std::string & path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back({{"op", "replace"}, {"path", path}, {"value", target}}); + } + else { - // the patch - basic_json result(value_t::array); + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } - // if the values are the same, return empty patch - if (source == target) + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) { - return result; + // add operations in reverse order to avoid invalid + // indices + result.insert( + result.begin() + end_index, object({{"op", "remove"}, {"path", path + "/" + std::to_string(i)}})); + ++i; } - if (source.type() != target.type()) + // add other remaining elements + while (i < target.size()) { - // different types: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); + result.push_back({{"op", "add"}, {"path", path + "/" + std::to_string(i)}, {"value", target[i]}}); + ++i; } - else + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.begin(); it != source.end(); ++it) { - switch (source.type()) - { - case value_t::array: - { - // first pass: traverse common elements - size_t i = 0; - while (i < source.size() and i < target.size()) - { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } - - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements - - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( - { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } - - // add other remaining elements - while (i < target.size()) - { - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } - - break; - } + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.begin(); it != source.end(); ++it) - { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else - { - // found a key that is not in o -> remove it - result.push_back(object( - { - {"op", "remove"}, - {"path", path + "/" + key} - })); - } - } - - // second pass: traverse other object's elements - for (auto it = target.begin(); it != target.end(); ++it) - { - if (source.find(it.key()) == source.end()) - { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( - { - {"op", "add"}, - {"path", path + "/" + key}, - {"value", it.value()} - }); - } - } - - break; - } + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object({{"op", "remove"}, {"path", path + "/" + key}})); + } + } - default: - { - // both primitive type: replace value - result.push_back( - { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - break; - } - } + // second pass: traverse other object's elements + for (auto it = target.begin(); it != target.end(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back({{"op", "add"}, {"path", path + "/" + key}, {"value", it.value()}}); + } } - return result; + break; + } + + default: + { + // both primitive type: replace value + result.push_back({{"op", "replace"}, {"path", path}, {"value", target}}); + break; + } + } } - /// @} + return result; + } + + /// @} }; ///////////// @@ -14358,8 +14380,7 @@ uses the standard template types. @since version 1.0.0 */ using json = basic_json<>; -} // namespace nlohmann - +} // namespace nlohmann /////////////////////// // nonmember support // @@ -14373,49 +14394,45 @@ namespace std @since version 1.0.0 */ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value - ) +template <> +inline void swap(nlohmann::json & j1, nlohmann::json & j2) noexcept( + is_nothrow_move_constructible::value and is_nothrow_move_assignable::value) { - j1.swap(j2); + j1.swap(j2); } /// hash value for JSON objects -template<> +template <> struct hash { - /*! - @brief return a hash value for a JSON object - - @since version 1.0.0 - */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash(); - return h(j.dump()); - } + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json & j) const + { + // a naive hashing via the string representation + const auto & h = hash(); + return h(j.dump()); + } }; /// specialization for std::less template <> struct less<::nlohmann::detail::value_t> { - /*! - @brief compare two value_t enum values - @since version 3.0.0 - */ - bool operator()(nlohmann::detail::value_t lhs, - nlohmann::detail::value_t rhs) const noexcept - { - return nlohmann::detail::operator<(lhs, rhs); - } + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } }; -} // namespace std +} // namespace std /*! @brief user-defined string literal for JSON values @@ -14430,9 +14447,9 @@ if no parse error occurred. @since version 1.0.0 */ -inline nlohmann::json operator "" _json(const char* s, std::size_t n) +inline nlohmann::json operator"" _json(const char * s, std::size_t n) { - return nlohmann::json::parse(s, s + n); + return nlohmann::json::parse(s, s + n); } /*! @@ -14448,17 +14465,17 @@ object if no parse error occurred. @since version 2.0.0 */ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +inline nlohmann::json::json_pointer operator"" _json_pointer(const char * s, std::size_t n) { - return nlohmann::json::json_pointer(std::string(s, n)); + return nlohmann::json::json_pointer(std::string(s, n)); } // restore GCC/clang diagnostic settings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #if defined(__clang__) - #pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif // clean up diff --git a/sc-memory/sc-memory/kpm/sc_agent.cpp b/sc-memory/sc-memory/kpm/sc_agent.cpp index 7330f04619..e02b957bbf 100644 --- a/sc-memory/sc-memory/kpm/sc_agent.cpp +++ b/sc-memory/sc-memory/kpm/sc_agent.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_agent.hpp" @@ -11,11 +11,10 @@ namespace { - bool gInitializeResult = false; bool gIsInitialized = false; -} // namespace +} // namespace bool ScAgentInit(bool force /* = false */) { @@ -28,7 +27,6 @@ bool ScAgentInit(bool force /* = false */) return gInitializeResult; } - ScAgent::ScAgent(char const * name, sc_uint8 accessLvl) : m_memoryCtx(accessLvl, name) { @@ -38,7 +36,6 @@ ScAgent::~ScAgent() { } - // --------------------------- ScAgentAction::ScAgentAction(ScAddr const & cmdClassAddr, char const * name, sc_uint8 accessLvl) : ScAgent(name, accessLvl) @@ -61,7 +58,8 @@ sc_result ScAgentAction::Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, if (m_memoryCtx.HelperCheckEdge(m_cmdClassAddr, cmdAddr, ScType::EdgeAccessConstPosPerm)) { m_memoryCtx.EraseElement(edgeAddr); - ScAddr progressAddr = m_memoryCtx.CreateEdge(ScType::EdgeAccessConstPosTemp, ScKeynodes::kCommandProgressdAddr, cmdAddr); + ScAddr progressAddr = + m_memoryCtx.CreateEdge(ScType::EdgeAccessConstPosTemp, ScKeynodes::kCommandProgressdAddr, cmdAddr); assert(progressAddr.IsValid()); ScAddr resultAddr = m_memoryCtx.CreateNode(ScType::NodeConstStruct); assert(resultAddr.IsValid()); @@ -85,11 +83,8 @@ sc_result ScAgentAction::Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr ScAgentAction::GetParam(ScAddr const & cmdAddr, ScAddr const & relationAddr, ScType const & paramType) const { - ScIterator5Ptr iter = m_memoryCtx.Iterator5(cmdAddr, - ScType::EdgeAccessConstPosPerm, - paramType, - ScType::EdgeAccessConstPosPerm, - relationAddr); + ScIterator5Ptr iter = m_memoryCtx.Iterator5( + cmdAddr, ScType::EdgeAccessConstPosPerm, paramType, ScType::EdgeAccessConstPosPerm, relationAddr); if (!iter->Next()) return ScAddr(); @@ -120,7 +115,9 @@ ScAddr const & ScAgentAction::GetNrelResultAddr() ScAddr ScAgentAction::CreateCommand(ScMemoryContext & ctx, ScAddr const & cmdClassAddr, ScAddrVector const & params) { if (params.size() >= ScKeynodes::GetRrelIndexNum()) - SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You should use <= " + std::to_string(ScKeynodes::GetRrelIndexNum()) + " params"); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidParams, + "You should use <= " + std::to_string(ScKeynodes::GetRrelIndexNum()) + " params"); SC_ASSERT(cmdClassAddr.IsValid(), ()); @@ -152,11 +149,13 @@ bool ScAgentAction::InitiateCommand(ScMemoryContext & ctx, ScAddr const & cmdAdd return ctx.CreateEdge(ScType::EdgeAccessConstPosTemp, ScKeynodes::kCommandInitiatedAddr, cmdAddr).IsValid(); } -bool ScAgentAction::InitiateCommandWait(ScMemoryContext & ctx, ScAddr const & cmdAddr, uint32_t waitTimeOutMS/* = 5000 */) +bool ScAgentAction::InitiateCommandWait( + ScMemoryContext & ctx, + ScAddr const & cmdAddr, + uint32_t waitTimeOutMS /* = 5000 */) { ScWaitActionFinished waiter(ctx, cmdAddr); - waiter.SetOnWaitStartDelegate([&]() - { + waiter.SetOnWaitStartDelegate([&]() { ScAgentAction::InitiateCommand(ctx, cmdAddr); }); return waiter.Wait(waitTimeOutMS); @@ -165,11 +164,11 @@ bool ScAgentAction::InitiateCommandWait(ScMemoryContext & ctx, ScAddr const & cm ScAddr ScAgentAction::GetCommandResultAddr(ScMemoryContext & ctx, ScAddr const & cmdAddr) { ScIterator5Ptr it = ctx.Iterator5( - cmdAddr, - ScType::EdgeDCommonConst, - ScType::NodeConstStruct, - ScType::EdgeAccessConstPosPerm, - ScKeynodes::kNrelResult); + cmdAddr, + ScType::EdgeDCommonConst, + ScType::NodeConstStruct, + ScType::EdgeAccessConstPosPerm, + ScKeynodes::kNrelResult); if (it->Next()) return it->Get(2); @@ -190,14 +189,8 @@ ScAddr ScAgentAction::GetCommandResultCodeAddr(ScMemoryContext & ctx, ScAddr con return ScAddr(); ScTemplate templ; - templ.Triple( - ScKeynodes::kScResult, - ScType::EdgeAccessVarPosPerm, - ScType::NodeVarClass >> "result_class"); - templ.Triple( - "result_class", - ScType::EdgeAccessVarPosPerm, - resultAddr); + templ.Triple(ScKeynodes::kScResult, ScType::EdgeAccessVarPosPerm, ScType::NodeVarClass >> "result_class"); + templ.Triple("result_class", ScType::EdgeAccessVarPosPerm, resultAddr); ScTemplateSearchResult searchResult; if (!ctx.HelperSearchTemplate(templ, searchResult)) @@ -209,10 +202,7 @@ ScAddr ScAgentAction::GetCommandResultCodeAddr(ScMemoryContext & ctx, ScAddr con ScAgentAction::State ScAgentAction::GetCommandState(ScMemoryContext & ctx, ScAddr const & cmdAddr) { - ScIterator3Ptr it = ctx.Iterator3( - ScType::NodeConstClass, - ScType::EdgeAccessConstPosTemp, - cmdAddr); + ScIterator3Ptr it = ctx.Iterator3(ScType::NodeConstClass, ScType::EdgeAccessConstPosTemp, cmdAddr); ScAddr stateAddr; while (it->Next()) diff --git a/sc-memory/sc-memory/kpm/sc_agent.hpp b/sc-memory/sc-memory/kpm/sc_agent.hpp index 7deacd540c..e175135ef2 100644 --- a/sc-memory/sc-memory/kpm/sc_agent.hpp +++ b/sc-memory/sc-memory/kpm/sc_agent.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -14,7 +14,6 @@ #include "../generated/sc_agent.generated.hpp" - /* Call this function before agent module usage. * If module initialized, then returns true; otherwise returns false */ @@ -44,7 +43,6 @@ class ScAgentAction : public ScAgent SC_GENERATED_BODY() public: - enum class State : uint8_t { Unknown = 0, @@ -53,11 +51,15 @@ class ScAgentAction : public ScAgent Finished }; - _SC_EXTERN explicit ScAgentAction(ScAddr const & cmdClassAddr, char const * name, sc_uint8 accessLvl = sc_access_lvl_make_max); + _SC_EXTERN explicit ScAgentAction( + ScAddr const & cmdClassAddr, + char const * name, + sc_uint8 accessLvl = sc_access_lvl_make_max); _SC_EXTERN virtual ~ScAgentAction(); protected: - _SC_EXTERN virtual sc_result Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) override; + _SC_EXTERN virtual sc_result Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) + override; _SC_EXTERN ScAddr GetParam(ScAddr const & cmdAddr, ScAddr const & relationAddr, ScType const & paramType) const; /* This funtion returns parameter by index. It's equal to call @@ -80,7 +82,8 @@ class ScAgentAction : public ScAgent * Returns ScAddr of created command instance. If addr is not valid, then * command doesn't created */ - static _SC_EXTERN ScAddr CreateCommand(ScMemoryContext & ctx, ScAddr const & cmdClassAddr, ScAddrVector const & params); + static _SC_EXTERN ScAddr + CreateCommand(ScMemoryContext & ctx, ScAddr const & cmdClassAddr, ScAddrVector const & params); /* Init specified command. * cmdAddr - ScAddr of command instance @@ -93,7 +96,10 @@ class ScAgentAction : public ScAgent * waitTimeOutMS - timeout for a waiting (milliseconds) * Returns true, if command initiated and finished; otherwise returns false (wait timeout) */ - static _SC_EXTERN bool InitiateCommandWait(ScMemoryContext & ctx, ScAddr const & cmdAddr, uint32_t waitTimeOutMS = 5000); + static _SC_EXTERN bool InitiateCommandWait( + ScMemoryContext & ctx, + ScAddr const & cmdAddr, + uint32_t waitTimeOutMS = 5000); /* Returns ScAddr of result structure of specified command */ @@ -120,24 +126,22 @@ class ScAgentAction : public ScAgent static _SC_EXTERN bool IsCommandFishined(ScMemoryContext & ctx, ScAddr const & cmdAddr); /* Reutrns true, if specified command included into set of initiated commands - */ + */ static _SC_EXTERN bool IsCommandInitiated(ScMemoryContext & ctx, ScAddr const & cmdAddr); /* Reutrns true, if specified command included into set of in-progress commands - */ + */ static _SC_EXTERN bool IsCommandInProgress(ScMemoryContext & ctx, ScAddr const & cmdAddr); private: ScAddr m_cmdClassAddr; private: - }; #define AGENT_NAME_TYPE(__Name__) __Name__##Type #define AGENT_NAME_CLASS(__Name__) __Name__##_Agent -#define AGENT_NAME_INST(__Name__) __Name__/*##(__LINE__)##(__FILE__)*/ - +#define AGENT_NAME_INST(__Name__) __Name__ /*##(__LINE__)##(__FILE__)*/ #define SC_AGENT_IMPLEMENTATION(__AgentName__) \ SC_COMBINE(ScFileID, _, __AgentName__, _impl) \ @@ -147,10 +151,8 @@ class ScAgentAction : public ScAgent SC_COMBINE(ScFileID, _, __AgentName__, _impl) \ sc_result __AgentName__::RunImpl(ScAddr const & requestAddr, ScAddr const & resultAddr) - - #define SC_AGENT_REGISTER(__AgentName__) \ SC_OBJECT_INIT_GLOBAL_CALL(__AgentName__) \ __AgentName__::RegisterHandler(); -#define SC_AGENT_UNREGISTER(__AgentName__) __AgentName__::UnregisterHandler(); +#define SC_AGENT_UNREGISTER(__AgentName__) __AgentName__::UnregisterHandler(); diff --git a/sc-memory/sc-memory/python/sc_python_bridge.cpp b/sc-memory/sc-memory/python/sc_python_bridge.cpp index 7f3235a4bf..61329e87e8 100644 --- a/sc-memory/sc-memory/python/sc_python_bridge.cpp +++ b/sc-memory/sc-memory/python/sc_python_bridge.cpp @@ -1,21 +1,20 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_python_bridge.hpp" namespace py { - ScPythonBridge::ScPythonBridge() : m_isInitialized(false) , m_isFinished(false) { } -bool ScPythonBridge::WaitReady(uint32_t timeOutMS/* = 10000*/) +bool ScPythonBridge::WaitReady(uint32_t timeOutMS /* = 10000*/) { return m_initWait.Wait(timeOutMS); } @@ -88,4 +87,4 @@ std::string const & ScPythonBridge::GetInitParams() const return m_initParams; } -} \ No newline at end of file +} // namespace py \ No newline at end of file diff --git a/sc-memory/sc-memory/python/sc_python_bridge.hpp b/sc-memory/sc-memory/python/sc_python_bridge.hpp index efa2a4658c..b9e218a645 100644 --- a/sc-memory/sc-memory/python/sc_python_bridge.hpp +++ b/sc-memory/sc-memory/python/sc_python_bridge.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -14,17 +14,16 @@ namespace py { - class ScPythonBridge { public: using CloseFunc = std::function; ScPythonBridge(); - + /* Waits until bridge would be initialized - * Returns true, when bridge initialized correctly; otherwise - false - */ + * Returns true, when bridge initialized correctly; otherwise - false + */ bool WaitReady(uint32_t timeOutMS = 10000); bool IsInitialized() const; bool IsFinished() const; @@ -56,4 +55,4 @@ class ScPythonBridge using ScPythonBridgePtr = std::shared_ptr; -} // py +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_includes.hpp b/sc-memory/sc-memory/python/sc_python_includes.hpp index 17768f4c33..478e7b427d 100644 --- a/sc-memory/sc-memory/python/sc_python_includes.hpp +++ b/sc-memory/sc-memory/python/sc_python_includes.hpp @@ -1,4 +1,4 @@ #pragma once -#define BOOST_PYTHON_STATIC_LIB +#define BOOST_PYTHON_STATIC_LIB #include \ No newline at end of file diff --git a/sc-memory/sc-memory/python/sc_python_interp.cpp b/sc-memory/sc-memory/python/sc_python_interp.cpp index 2896367f7f..63178e90d9 100644 --- a/sc-memory/sc-memory/python/sc_python_interp.cpp +++ b/sc-memory/sc-memory/python/sc_python_interp.cpp @@ -21,16 +21,15 @@ extern "C" namespace { - std::unordered_set gAddedModulePaths; -template +template void CallPythonFunctionNoGIL(Func & f, Args... args) { f(args...); } -template +template void CallPythonFunction(Func & f, Args... args) { py::WithGIL gil; @@ -39,9 +38,18 @@ void CallPythonFunction(Func & f, Args... args) struct PyObjectWrap { - PyObjectWrap() : m_object(nullptr) {} - explicit PyObjectWrap(PyObject * obj) : m_object(obj) {} - ~PyObjectWrap() { Clear(); } + PyObjectWrap() + : m_object(nullptr) + { + } + explicit PyObjectWrap(PyObject * obj) + : m_object(obj) + { + } + ~PyObjectWrap() + { + Clear(); + } void Clear() { @@ -58,7 +66,7 @@ struct PyObjectWrap m_object = obj; } - PyObject* operator * () const + PyObject * operator*() const { return m_object; } @@ -90,7 +98,7 @@ void PyLoadModulePathFromConfig(py::ScPythonInterpreter::ModulePathSet & outValu void AddModuleSearchPaths(py::ScPythonInterpreter::ModulePathSet const & modulePath) { - PyObject* sysPath = PySys_GetObject("path"); + PyObject * sysPath = PySys_GetObject("path"); for (auto const & p : modulePath) { if (gAddedModulePaths.find(p) == gAddedModulePaths.end()) @@ -125,14 +133,11 @@ class PyScEvent SC_ASSERT(evt != nullptr, ("Should receive valid event pointer")); m_event.reset(evt); - evt->SetDelegate(std::bind(&PyScEvent::OnEvent, this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3)); + evt->SetDelegate( + std::bind(&PyScEvent::OnEvent, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); } public: - ~PyScEvent() { Destroy(); @@ -183,7 +188,6 @@ class PyScEvent EventID m_id; }; - class PyBridgeWrap { using EventsMap = std::unordered_map>; @@ -251,11 +255,11 @@ class PyBridgeWrap { py::WithGIL gil; CallPythonFunctionNoGIL( - m_eventDelegate, - bp::object(params.m_id), - bp::object(params.m_addr), - bp::object(params.m_edgeAddr), - bp::object(params.m_otherAddr)); + m_eventDelegate, + bp::object(params.m_id), + bp::object(params.m_addr), + bp::object(params.m_edgeAddr), + bp::object(params.m_otherAddr)); } } @@ -266,8 +270,7 @@ class PyBridgeWrap if (it == m_events.end()) { - SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, - "Can't find event with ID: " + std::to_string(evtID)); + SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, "Can't find event with ID: " + std::to_string(evtID)); } ClearEvent(it->second); @@ -333,7 +336,9 @@ class PythonLog SC_LOG_PYTHON(str); } - void Flush() {} + void Flush() + { + } }; class PythonLogError @@ -348,53 +353,51 @@ class PythonLogError SC_LOG_PYTHON_ERROR(str); } - void Flush() {} + void Flush() + { + } }; -} // namespace +} // namespace - // small boost python module for bridge utils +// small boost python module for bridge utils BOOST_PYTHON_MODULE(scb) { bp::register_ptr_to_python>(); bp::register_ptr_to_python>(); bp::class_("CppLog", bp::init<>()) - .def("write", bp::make_function(&PythonLog::Write)) - .def("flush", bp::make_function(&PythonLog::Flush)); + .def("write", bp::make_function(&PythonLog::Write)) + .def("flush", bp::make_function(&PythonLog::Flush)); bp::class_("CppLogError", bp::init<>()) - .def("write", bp::make_function(&PythonLogError::Write)) - .def("flush", bp::make_function(&PythonLogError::Flush)); + .def("write", bp::make_function(&PythonLogError::Write)) + .def("flush", bp::make_function(&PythonLogError::Flush)); bp::enum_("ScPythonEventType") - .value("AddInputEdge", ScEvent::Type::AddInputEdge) - .value("AddOutputEdge", ScEvent::Type::AddOutputEdge) - .value("ContentChanged", ScEvent::Type::ContentChanged) - .value("EraseElement", ScEvent::Type::EraseElement) - .value("RemoveInputEdge", ScEvent::Type::RemoveInputEdge) - .value("RemoveOutputEdge", ScEvent::Type::RemoveOutputEdge) - ; + .value("AddInputEdge", ScEvent::Type::AddInputEdge) + .value("AddOutputEdge", ScEvent::Type::AddOutputEdge) + .value("ContentChanged", ScEvent::Type::ContentChanged) + .value("EraseElement", ScEvent::Type::EraseElement) + .value("RemoveInputEdge", ScEvent::Type::RemoveInputEdge) + .value("RemoveOutputEdge", ScEvent::Type::RemoveOutputEdge); bp::class_("ScPythonEvent", bp::no_init) - .def("Destroy", bp::make_function(&PyScEvent::Destroy)) - .def("GetID", bp::make_function(&PyScEvent::GetID)) - ; + .def("Destroy", bp::make_function(&PyScEvent::Destroy)) + .def("GetID", bp::make_function(&PyScEvent::GetID)); bp::class_("ScPythonBridge", bp::no_init) - .def("Ready", bp::make_function(&PyBridgeWrap::Ready)) - .def("Finish", bp::make_function(&PyBridgeWrap::Finish)) - .def("SubscribeEvent", bp::make_function(&PyBridgeWrap::SubscribeEvent)) - .def("DestroyEvent", bp::make_function(&PyBridgeWrap::DestroyEvent)) - .def_readwrite("onClose", &PyBridgeWrap::m_closeDelegate) - .def_readwrite("onEvent", &PyBridgeWrap::m_eventDelegate) - .def("InitParams", bp::make_function(&PyBridgeWrap::GetInitParams)) - ; + .def("Ready", bp::make_function(&PyBridgeWrap::Ready)) + .def("Finish", bp::make_function(&PyBridgeWrap::Finish)) + .def("SubscribeEvent", bp::make_function(&PyBridgeWrap::SubscribeEvent)) + .def("DestroyEvent", bp::make_function(&PyBridgeWrap::DestroyEvent)) + .def_readwrite("onClose", &PyBridgeWrap::m_closeDelegate) + .def_readwrite("onEvent", &PyBridgeWrap::m_eventDelegate) + .def("InitParams", bp::make_function(&PyBridgeWrap::GetInitParams)); } namespace py { - bool ScPythonInterpreter::ms_isInitialized = false; std::wstring ScPythonInterpreter::ms_name; utils::ScLock ScPythonInterpreter::ms_lock; @@ -438,7 +441,10 @@ void ScPythonInterpreter::Shutdown() ms_isInitialized = false; } -void ScPythonInterpreter::RunScript(std::string const & scriptName, ScMemoryContext const & ctx, ScPythonBridgePtr bridge /* = nullptr */) +void ScPythonInterpreter::RunScript( + std::string const & scriptName, + ScMemoryContext const & ctx, + ScPythonBridgePtr bridge /* = nullptr */) { ScPythonSubThread subThreadScope; @@ -451,8 +457,7 @@ void ScPythonInterpreter::RunScript(std::string const & scriptName, ScMemoryCont auto const it = ms_foundModules.find(scriptName); if (it == ms_foundModules.end()) { - SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, - "Can't find " << scriptName << " module"); + SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, "Can't find " << scriptName << " module"); } moduleName = it->first; @@ -463,7 +468,7 @@ void ScPythonInterpreter::RunScript(std::string const & scriptName, ScMemoryCont p /= moduleName; std::string const filePath = p.string(); - //PyEvalLock lock; + // PyEvalLock lock; bp::object mainModule((bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))))); bp::object mainNamespace = mainModule.attr("__dict__"); try @@ -471,13 +476,12 @@ void ScPythonInterpreter::RunScript(std::string const & scriptName, ScMemoryCont bp::dict globalNamespace; globalNamespace["__builtins__"] = mainNamespace["__builtins__"]; std::stringstream initCode; - initCode - << "from scb import *" << std::endl - << "from sc import *" << std::endl - << "import sys" << std::endl - << "sys.path.append('" << p.parent_path().string() << "')" << std::endl - << "sys.stdout = CppLog()" << std::endl - << "sys.stderr = CppLogError()" << std::endl; + initCode << "from scb import *" << std::endl + << "from sc import *" << std::endl + << "import sys" << std::endl + << "sys.path.append('" << p.parent_path().string() << "')" << std::endl + << "sys.stdout = CppLog()" << std::endl + << "sys.stderr = CppLogError()" << std::endl; bp::exec(initCode.str().c_str(), globalNamespace, globalNamespace); std::unique_ptr bridgeWrap; @@ -509,8 +513,7 @@ void ScPythonInterpreter::RunScript(std::string const & scriptName, ScMemoryCont catch (...) { PyErr_Print(); - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "Error during code run " << filePath); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Error during code run " << filePath); } } @@ -544,7 +547,8 @@ void ScPythonInterpreter::CollectModulesInPath(std::string const & modulePath) if (!boost::filesystem::is_directory(*itPath)) { boost::filesystem::path const p = *itPath; - std::string filename = utils::StringUtils::ReplaceAll(boost::filesystem::relativePath(root, p).string(), "\\", "/"); + std::string filename = + utils::StringUtils::ReplaceAll(boost::filesystem::relativePath(root, p).string(), "\\", "/"); std::string ext = utils::StringUtils::GetFileExtension(filename); utils::StringUtils::ToLowerCase(ext); @@ -553,8 +557,8 @@ void ScPythonInterpreter::CollectModulesInPath(std::string const & modulePath) auto const itModule = ms_foundModules.find(filename); if (itModule != ms_foundModules.end()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "Module " << itModule->first << " already exist in " << itModule->second); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidState, "Module " << itModule->first << " already exist in " << itModule->second); } ms_foundModules.insert(std::make_pair(filename, modulePath)); @@ -582,4 +586,4 @@ void ScPythonInterpreter::CollectModulesInPath(std::string const & modulePath) } } -} // namesapce py +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_interp.hpp b/sc-memory/sc-memory/python/sc_python_interp.hpp index b9a72af729..4e4547d7a0 100644 --- a/sc-memory/sc-memory/python/sc_python_interp.hpp +++ b/sc-memory/sc-memory/python/sc_python_interp.hpp @@ -10,7 +10,6 @@ namespace py { - class ScPythonInterpreter { public: @@ -24,7 +23,10 @@ class ScPythonInterpreter * python.modules_path config value. * This function is a thread safe */ - _SC_EXTERN static void RunScript(std::string const & scriptName, ScMemoryContext const & ctx, ScPythonBridgePtr bridge = ScPythonBridgePtr()); + _SC_EXTERN static void RunScript( + std::string const & scriptName, + ScMemoryContext const & ctx, + ScPythonBridgePtr bridge = ScPythonBridgePtr()); _SC_EXTERN static void AddModulesPath(std::string const & modulesPath); @@ -43,4 +45,4 @@ class ScPythonInterpreter static ModulePathSet ms_modulePaths; }; -} // py +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_module.cpp b/sc-memory/sc-memory/python/sc_python_module.cpp index feebad7ad8..59a57bb80f 100644 --- a/sc-memory/sc-memory/python/sc_python_module.cpp +++ b/sc-memory/sc-memory/python/sc_python_module.cpp @@ -13,7 +13,6 @@ extern "C" #include "sc-core/sc_memory_headers.h" } - namespace { namespace bp = boost::python; @@ -26,7 +25,6 @@ void translateException(utils::ScException const & e) namespace impl { - class PyTemplateGenResult { public: @@ -187,7 +185,9 @@ class PyTemplateSearchResult class PyTemplateItemValue { public: - PyTemplateItemValue() {} + PyTemplateItemValue() + { + } PyTemplateItemValue(ScAddr const & addr, std::string const & replName = std::string()) : m_item(new ScTemplateItemValue(addr, replName.c_str())) @@ -236,7 +236,9 @@ class PyLinkContent static uint8_t Float; }; - PyLinkContent() {} + PyLinkContent() + { + } explicit PyLinkContent(ScStream const & stream, uint8_t t) : m_type(t) @@ -244,7 +246,7 @@ class PyLinkContent m_buffer.reset(new MemoryBufferSafe()); m_buffer->Reinit(stream.Size()); size_t readBytes = 0; - stream.Read((sc_char*)m_buffer->Data(), stream.Size(), readBytes); + stream.Read((sc_char *)m_buffer->Data(), stream.Size(), readBytes); } uint8_t GetType() const @@ -254,7 +256,7 @@ class PyLinkContent std::string AsString() const { - char const * data = (char const*)m_buffer->CData(); + char const * data = (char const *)m_buffer->CData(); return std::string(data, data + m_buffer->Size()); } @@ -279,8 +281,7 @@ class PyLinkContent return value; } - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Size of content should be equal to 1, 2 or 4 bytes"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "Size of content should be equal to 1, 2 or 4 bytes"); return 0; } @@ -300,15 +301,16 @@ class PyLinkContent return value; } - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Size of content should be equal to " << sizeof(double) << " or " << sizeof(float) << " bytes"); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidType, + "Size of content should be equal to " << sizeof(double) << " or " << sizeof(float) << " bytes"); return std::numeric_limits::min(); } bp::object AsBinary() const { - PyObject * buff = PyMemoryView_FromMemory((char*)m_buffer->Data(), m_buffer->Size(), PyBUF_READ); + PyObject * buff = PyMemoryView_FromMemory((char *)m_buffer->Data(), m_buffer->Size(), PyBUF_READ); return boost::python::object(boost::python::handle<>(buff)); } @@ -342,8 +344,7 @@ bp::list _context_FindLinksByContent(ScMemoryContext & self, bp::object const & } else { - SC_THROW_EXCEPTION(utils::ExceptionNotImplemented, - "Just string content type now supported"); + SC_THROW_EXCEPTION(utils::ExceptionNotImplemented, "Just string content type now supported"); } return result; @@ -464,61 +465,46 @@ class PyIteratorWrap using PyIterator3 = PyIteratorWrap; using PyIterator5 = PyIteratorWrap; -bp::object _context_iterator3(ScMemoryContext & self, - bp::object & param1, - bp::object & param2, - bp::object & param3) +bp::object _context_iterator3(ScMemoryContext & self, bp::object & param1, bp::object & param2, bp::object & param3) { bp::extract pt2(param2); - if (!pt2.check()) // second parameter should be a type anyway + if (!pt2.check()) // second parameter should be a type anyway return bp::object(); bp::extract pa1(param1); if (pa1.check()) { bp::extract pa3(param3); - if (pa3.check()) // f_a_f - return bp::object( - boost::shared_ptr( - new PyIterator3( - self.Iterator3(static_cast(pa1), - static_cast(pt2), - static_cast(pa3))))); + if (pa3.check()) // f_a_f + return bp::object(boost::shared_ptr(new PyIterator3( + self.Iterator3(static_cast(pa1), static_cast(pt2), static_cast(pa3))))); bp::extract pt3(param3); - if (pt3.check()) // f_a_a - return bp::object( - boost::shared_ptr( - new PyIterator3( - self.Iterator3(static_cast(pa1), - static_cast(pt2), - static_cast(pt3))))); + if (pt3.check()) // f_a_a + return bp::object(boost::shared_ptr(new PyIterator3( + self.Iterator3(static_cast(pa1), static_cast(pt2), static_cast(pt3))))); } bp::extract pt1(param1); if (pt1.check()) { bp::extract pa3(param3); - if (pa3.check()) // a_a_f - return bp::object( - boost::shared_ptr( - new PyIterator3( - self.Iterator3(static_cast(pt1), - static_cast(pt2), - static_cast(pa3))))); + if (pa3.check()) // a_a_f + return bp::object(boost::shared_ptr(new PyIterator3( + self.Iterator3(static_cast(pt1), static_cast(pt2), static_cast(pa3))))); } return bp::object(); } -bp::object _context_iterator5(ScMemoryContext & self, - bp::object & param1, - bp::object & param2, - bp::object & param3, - bp::object & param4, - bp::object & param5) +bp::object _context_iterator5( + ScMemoryContext & self, + bp::object & param1, + bp::object & param2, + bp::object & param3, + bp::object & param4, + bp::object & param5) { - // param2 and param4 are always ScType bp::extract pt2(param2); if (!pt2.check()) @@ -535,26 +521,22 @@ bp::object _context_iterator5(ScMemoryContext & self, if (pa3.check()) { bp::extract pa5(param5); - if (pa5.check()) // f_a_f_a_f - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pa1), - static_cast(pt2), - static_cast(pa3), - static_cast(pt4), - static_cast(pa5))))); + if (pa5.check()) // f_a_f_a_f + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pa1), + static_cast(pt2), + static_cast(pa3), + static_cast(pt4), + static_cast(pa5))))); bp::extract pt5(param5); - if (pt5.check()) // f_a_f_a_a - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pa1), - static_cast(pt2), - static_cast(pa3), - static_cast(pt4), - static_cast(pt5))))); + if (pt5.check()) // f_a_f_a_a + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pa1), + static_cast(pt2), + static_cast(pa3), + static_cast(pt4), + static_cast(pt5))))); } bp::extract pt3(param3); @@ -562,26 +544,22 @@ bp::object _context_iterator5(ScMemoryContext & self, return bp::object(); bp::extract pa5(param5); - if (pa5.check()) // f_a_a_a_f - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pa1), - static_cast(pt2), - static_cast(pt3), - static_cast(pt4), - static_cast(pa5))))); + if (pa5.check()) // f_a_a_a_f + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pa1), + static_cast(pt2), + static_cast(pt3), + static_cast(pt4), + static_cast(pa5))))); bp::extract pt5(param5); - if (pt5.check()) // f_a_a_a_a - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pa1), - static_cast(pt2), - static_cast(pt3), - static_cast(pt4), - static_cast(pt5))))); + if (pt5.check()) // f_a_a_a_a + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pa1), + static_cast(pt2), + static_cast(pt3), + static_cast(pt4), + static_cast(pt5))))); } bp::extract pt1(param1); @@ -592,38 +570,36 @@ bp::object _context_iterator5(ScMemoryContext & self, return bp::object(); bp::extract pa5(param5); - if (pa5.check()) // a_a_f_a_f - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pt1), - static_cast(pt2), - static_cast(pa3), - static_cast(pt4), - static_cast(pa5))))); + if (pa5.check()) // a_a_f_a_f + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pt1), + static_cast(pt2), + static_cast(pa3), + static_cast(pt4), + static_cast(pa5))))); bp::extract pt5(param5); - if (pt5.check()) // a_a_f_a_a - return bp::object( - boost::shared_ptr( - new PyIterator5( - self.Iterator5(static_cast(pt1), - static_cast(pt2), - static_cast(pa3), - static_cast(pt4), - static_cast(pt5))))); + if (pt5.check()) // a_a_f_a_a + return bp::object(boost::shared_ptr(new PyIterator5(self.Iterator5( + static_cast(pt1), + static_cast(pt2), + static_cast(pa3), + static_cast(pt4), + static_cast(pt5))))); } return bp::object(); } -bp::object _context_helperResolveSysIdtf(ScMemoryContext & self, bp::object & idtf, bp::object const & type = bp::object()) +bp::object _context_helperResolveSysIdtf( + ScMemoryContext & self, + bp::object & idtf, + bp::object const & type = bp::object()) { bp::extract se(idtf); if (!se.check()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "First parameter should have an instance of str"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "First parameter should have an instance of str"); } ScType rawType; @@ -632,8 +608,7 @@ bp::object _context_helperResolveSysIdtf(ScMemoryContext & self, bp::object & id bp::extract te(type); if (!te.check()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Second parameter should be None or instance of ScType") + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "Second parameter should be None or instance of ScType") } rawType = static_cast(te); } @@ -648,8 +623,7 @@ bp::object _context_helperFindBySystemIdtf(ScMemoryContext & self, bp::object & bp::extract se(idtf); if (!se.check()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "First parameter should have an instance of str"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "First parameter should have an instance of str"); } std::string const idtfValue = static_cast(se); @@ -675,31 +649,37 @@ ScTemplateItemValue ResolveTemplateParam(bp::object & p) if (te.check()) return ScTemplateItemValue(static_cast(te)); - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Parameter to template should be ScAddr, ScType, string or replacement"); - return{}; + SC_THROW_EXCEPTION( + utils::ExceptionInvalidType, "Parameter to template should be ScAddr, ScType, string or replacement"); + return {}; }; class PyTemplate { public: - PyTemplate() : m_impl(new ScTemplate()) {} + PyTemplate() + : m_impl(new ScTemplate()) + { + } void Triple(bp::object & param1, bp::object & param2, bp::object & param3) { - m_impl->Triple(ResolveTemplateParam(param1), - ResolveTemplateParam(param2), - ResolveTemplateParam(param3)); + m_impl->Triple(ResolveTemplateParam(param1), ResolveTemplateParam(param2), ResolveTemplateParam(param3)); } - void TripleWithRelation(bp::object & param1, bp::object & param2, - bp::object & param3, bp::object & param4, bp::object & param5) + void TripleWithRelation( + bp::object & param1, + bp::object & param2, + bp::object & param3, + bp::object & param4, + bp::object & param5) { - m_impl->TripleWithRelation(ResolveTemplateParam(param1), - ResolveTemplateParam(param2), - ResolveTemplateParam(param3), - ResolveTemplateParam(param4), - ResolveTemplateParam(param5)); + m_impl->TripleWithRelation( + ResolveTemplateParam(param1), + ResolveTemplateParam(param2), + ResolveTemplateParam(param3), + ResolveTemplateParam(param4), + ResolveTemplateParam(param5)); } bool HasReplacement(std::string const & name) @@ -719,7 +699,10 @@ class PyTemplate class PyTemplateGenParams { public: - PyTemplateGenParams() : m_impl(new ScTemplateParams()) {} + PyTemplateGenParams() + : m_impl(new ScTemplateParams()) + { + } void Add(std::string const & paramName, ScAddr const & value) { @@ -788,8 +771,7 @@ bp::object _context_helperBuildTemplate(ScMemoryContext & self, bp::object & dat return bp::object(templ); } - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Second parameter should be ScAddr or string"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "Second parameter should be ScAddr or string"); return bp::object(); } @@ -834,7 +816,7 @@ class ScAgentCommandImpl } }; -} // namespace impl +} // namespace impl BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(ScMemoryContext_CreateLink_overload, ScMemoryContext::CreateLink, 0, 1) @@ -846,208 +828,197 @@ BOOST_PYTHON_MODULE(sc) def("getScConfigValue", bp::make_function(&impl::GetConfigValue)); bp::class_("ScMemoryContext", bp::no_init) - .def("Create", &impl::_context_CreateInstance, bp::return_value_policy()) - .staticmethod("Create") - .def("CreateNode", &ScMemoryContext::CreateNode, bp::return_value_policy()) - .def("CreateEdge", &ScMemoryContext::CreateEdge) - .def("CreateLink", &ScMemoryContext::CreateLink, ScMemoryContext_CreateLink_overload(bp::args("type"), "Create sc-link")) - .def("DeleteElement", &ScMemoryContext::EraseElement) - .def("GetName", &ScMemoryContext::GetName, bp::return_value_policy()) - .def("IsElement", &ScMemoryContext::IsElement) - .def("GetElementType", &ScMemoryContext::GetElementType) - .def("FindLinksByContent", impl::_context_FindLinksByContent) - .def("GetEdgeInfo", impl::_context_getEdgeInfo) - .def("SetLinkContent", impl::_context_setLinkContent) - .def("GetLinkContent", impl::_context_getLinkContent) - .def("Iterator3", impl::_context_iterator3) - .def("Iterator5", impl::_context_iterator5) - .def("HelperResolveSystemIdtf", impl::_context_helperResolveSysIdtf) - .def("HelperSetSystemIdtf", &ScMemoryContext::HelperSetSystemIdtf) - .def("HelperGetSystemIdtf", &ScMemoryContext::HelperGetSystemIdtf) - .def("HelperFindBySystemIdtf", impl::_context_helperFindBySystemIdtf) - .def("HelperCheckEdge", &ScMemoryContext::HelperCheckEdge) - .def("HelperGenTemplate", impl::_context_helperGenTemplate) - .def("HelperSearchTemplate", impl::_context_helperSearchTemplate) - .def("HelperBuildTemplate", impl::_context_helperBuildTemplate) - ; + .def("Create", &impl::_context_CreateInstance, bp::return_value_policy()) + .staticmethod("Create") + .def("CreateNode", &ScMemoryContext::CreateNode, bp::return_value_policy()) + .def("CreateEdge", &ScMemoryContext::CreateEdge) + .def( + "CreateLink", + &ScMemoryContext::CreateLink, + ScMemoryContext_CreateLink_overload(bp::args("type"), "Create sc-link")) + .def("DeleteElement", &ScMemoryContext::EraseElement) + .def("GetName", &ScMemoryContext::GetName, bp::return_value_policy()) + .def("IsElement", &ScMemoryContext::IsElement) + .def("GetElementType", &ScMemoryContext::GetElementType) + .def("FindLinksByContent", impl::_context_FindLinksByContent) + .def("GetEdgeInfo", impl::_context_getEdgeInfo) + .def("SetLinkContent", impl::_context_setLinkContent) + .def("GetLinkContent", impl::_context_getLinkContent) + .def("Iterator3", impl::_context_iterator3) + .def("Iterator5", impl::_context_iterator5) + .def("HelperResolveSystemIdtf", impl::_context_helperResolveSysIdtf) + .def("HelperSetSystemIdtf", &ScMemoryContext::HelperSetSystemIdtf) + .def("HelperGetSystemIdtf", &ScMemoryContext::HelperGetSystemIdtf) + .def("HelperFindBySystemIdtf", impl::_context_helperFindBySystemIdtf) + .def("HelperCheckEdge", &ScMemoryContext::HelperCheckEdge) + .def("HelperGenTemplate", impl::_context_helperGenTemplate) + .def("HelperSearchTemplate", impl::_context_helperSearchTemplate) + .def("HelperBuildTemplate", impl::_context_helperBuildTemplate); bp::class_, boost::noncopyable>("ScIterator3", bp::no_init) - .def("Next", &impl::PyIterator3::Next) - .def("IsValid", &impl::PyIterator3::IsValid) - .def("Get", &impl::PyIterator3::Get) - ; + .def("Next", &impl::PyIterator3::Next) + .def("IsValid", &impl::PyIterator3::IsValid) + .def("Get", &impl::PyIterator3::Get); bp::class_>("ScIterator5", bp::no_init) - .def("Next", &impl::PyIterator5::Next) - .def("IsValid", &impl::PyIterator5::IsValid) - .def("Get", &impl::PyIterator5::Get) - ; + .def("Next", &impl::PyIterator5::Next) + .def("IsValid", &impl::PyIterator5::IsValid) + .def("Get", &impl::PyIterator5::Get); bp::class_("ScLinkContent", bp::no_init) - .def("AsString", &impl::PyLinkContent::AsString) - .def("AsInt", &impl::PyLinkContent::AsInt) - .def("AsFloat", &impl::PyLinkContent::AsDouble) - .def("AsBinary", &impl::PyLinkContent::AsBinary) - .def("GetType", &impl::PyLinkContent::GetType) - .def_readonly("String", &impl::PyLinkContent::Type::String) - .def_readonly("Int", &impl::PyLinkContent::Type::Int) - .def_readonly("Float", &impl::PyLinkContent::Type::Float) - ; + .def("AsString", &impl::PyLinkContent::AsString) + .def("AsInt", &impl::PyLinkContent::AsInt) + .def("AsFloat", &impl::PyLinkContent::AsDouble) + .def("AsBinary", &impl::PyLinkContent::AsBinary) + .def("GetType", &impl::PyLinkContent::GetType) + .def_readonly("String", &impl::PyLinkContent::Type::String) + .def_readonly("Int", &impl::PyLinkContent::Type::Int) + .def_readonly("Float", &impl::PyLinkContent::Type::Float); bp::class_("ScTemplateGenResult", bp::no_init) - .def("Size", &impl::PyTemplateGenResult::Size) - .def("__getitem__", &impl::PyTemplateGenResult::Get) - .def("Aliases", &impl::PyTemplateGenResult::GetReplaceAliases) - ; + .def("Size", &impl::PyTemplateGenResult::Size) + .def("__getitem__", &impl::PyTemplateGenResult::Get) + .def("Aliases", &impl::PyTemplateGenResult::GetReplaceAliases); bp::class_("ScTemplateSearchResultItem", bp::no_init) - .def("Size", &impl::PyTemplateSearchResultItem::Size) - .def("__getitem__", &impl::PyTemplateSearchResultItem::Get) - ; + .def("Size", &impl::PyTemplateSearchResultItem::Size) + .def("__getitem__", &impl::PyTemplateSearchResultItem::Get); bp::class_("ScTemplateSearchResult", bp::no_init) - .def("Size", &impl::PyTemplateSearchResult::Size) - .def("__getitem__", &impl::PyTemplateSearchResult::Get) - .def("Aliases", &impl::PyTemplateSearchResult::GetReplaceAliases) - ; + .def("Size", &impl::PyTemplateSearchResult::Size) + .def("__getitem__", &impl::PyTemplateSearchResult::Get) + .def("Aliases", &impl::PyTemplateSearchResult::GetReplaceAliases); - bp::class_("ScTemplateItemValue", bp::no_init) - ; + bp::class_("ScTemplateItemValue", bp::no_init); bp::class_("ScTemplateParams", bp::init<>()) - .def("Add", &impl::PyTemplateGenParams::Add) - .def("Get", &impl::PyTemplateGenParams::Get) - .def("IsEmpty", &impl::PyTemplateGenParams::IsEmpty) - ; - + .def("Add", &impl::PyTemplateGenParams::Add) + .def("Get", &impl::PyTemplateGenParams::Get) + .def("IsEmpty", &impl::PyTemplateGenParams::IsEmpty); bp::class_("ScTemplate", bp::init<>()) - .def("Triple", &impl::PyTemplate::Triple) - .def("TripleWithRelation", &impl::PyTemplate::TripleWithRelation) - .def("HasReplacement", &impl::PyTemplate::HasReplacement) - ; + .def("Triple", &impl::PyTemplate::Triple) + .def("TripleWithRelation", &impl::PyTemplate::TripleWithRelation) + .def("HasReplacement", &impl::PyTemplate::HasReplacement); bp::class_("ScAddr", bp::init<>()) - .def(bp::init()) - .def("IsValid", &ScAddr::IsValid) - .def("ToInt", &ScAddr::Hash) - .def("__eq__", &ScAddr::operator==) - .def("__ne__", &ScAddr::operator!=) - .def("__rshift__", impl::_scAddrToRShift) - .def("rshift", impl::_scAddrToRShift) - ; + .def(bp::init()) + .def("IsValid", &ScAddr::IsValid) + .def("ToInt", &ScAddr::Hash) + .def("__eq__", &ScAddr::operator==) + .def("__ne__", &ScAddr::operator!=) + .def("__rshift__", impl::_scAddrToRShift) + .def("rshift", impl::_scAddrToRShift); bp::class_("ScType", bp::init<>()) - .def(bp::init()) - .def("__eq__", &ScType::operator==) - .def("__ne__", &ScType::operator!=) - .def("__or__", &ScType::operator|) - .def("__and__", &ScType::operator&) - .def("__rshift__", impl::_scTypeToRShift) - .def("rshift", impl::_scTypeToRShift) - .def("IsLink", &ScType::IsLink) - .def("IsEdge", &ScType::IsEdge) - .def("IsNode", &ScType::IsNode) - .def("IsUnknown", &ScType::IsUnknown) - .def("IsConst", &ScType::IsConst) - .def("IsVar", &ScType::IsVar) - .def("ToInt", &ScType::operator*) - - .def_readonly("Unknown", &ScType::Unknown) - .def_readonly("Const", &ScType::Const) - .def_readonly("Var", &ScType::Var) - .def_readonly("Node", &ScType::Node) - .def_readonly("Link", &ScType::Link) - - .def_readonly("EdgeUCommon", &ScType::EdgeUCommon) - .def_readonly("EdgeDCommon", &ScType::EdgeDCommon) - .def_readonly("EdgeUCommonConst", &ScType::EdgeUCommonConst) - .def_readonly("EdgeDCommonConst", &ScType::EdgeDCommonConst) - .def_readonly("EdgeAccess", &ScType::EdgeAccess) - .def_readonly("EdgeAccessConstPosPerm", &ScType::EdgeAccessConstPosPerm) - .def_readonly("EdgeAccessConstNegPerm", &ScType::EdgeAccessConstNegPerm) - .def_readonly("EdgeAccessConstFuzPerm", &ScType::EdgeAccessConstFuzPerm) - .def_readonly("EdgeAccessConstPosTemp", &ScType::EdgeAccessConstPosTemp) - .def_readonly("EdgeAccessConstNegTemp", &ScType::EdgeAccessConstNegTemp) - .def_readonly("EdgeAccessConstFuzTemp", &ScType::EdgeAccessConstFuzTemp) - .def_readonly("EdgeUCommonVar", &ScType::EdgeUCommonVar) - .def_readonly("EdgeDCommonVar", &ScType::EdgeDCommonVar) - .def_readonly("EdgeAccessVarPosPerm", &ScType::EdgeAccessVarPosPerm) - .def_readonly("EdgeAccessVarNegPerm", &ScType::EdgeAccessVarNegPerm) - .def_readonly("EdgeAccessVarFuzPerm", &ScType::EdgeAccessVarFuzPerm) - .def_readonly("EdgeAccessVarPosTemp", &ScType::EdgeAccessVarPosTemp) - .def_readonly("EdgeAccessVarNegTemp", &ScType::EdgeAccessVarNegTemp) - .def_readonly("EdgeAccessVarFuzTemp", &ScType::EdgeAccessVarFuzTemp) - - .def_readonly("NodeConst", &ScType::NodeConst) - .def_readonly("NodeVar", &ScType::NodeVar) - .def_readonly("LinkConst", &ScType::LinkConst) - .def_readonly("LinkVar", &ScType::LinkVar) - - .def_readonly("NodeConstStruct", &ScType::NodeConstStruct) - .def_readonly("NodeConstTuple", &ScType::NodeConstTuple) - .def_readonly("NodeConstRole", &ScType::NodeConstRole) - .def_readonly("NodeConstNoRole", &ScType::NodeConstNoRole) - .def_readonly("NodeConstClass", &ScType::NodeConstClass) - .def_readonly("NodeConstAbstract", &ScType::NodeConstAbstract) - .def_readonly("NodeConstMaterial", &ScType::NodeConstMaterial) - - .def_readonly("NodeVarStruct", &ScType::NodeVarStruct) - .def_readonly("NodeVarTuple", &ScType::NodeVarTuple) - .def_readonly("NodeVarRole", &ScType::NodeVarRole) - .def_readonly("NodeVarNoRole", &ScType::NodeVarNoRole) - .def_readonly("NodeVarClass", &ScType::NodeVarClass) - .def_readonly("NodeVarAbstract", &ScType::NodeVarAbstract) - .def_readonly("NodeVarMaterial", &ScType::NodeVarMaterial) - ; + .def(bp::init()) + .def("__eq__", &ScType::operator==) + .def("__ne__", &ScType::operator!=) + .def("__or__", &ScType::operator|) + .def("__and__", &ScType::operator&) + .def("__rshift__", impl::_scTypeToRShift) + .def("rshift", impl::_scTypeToRShift) + .def("IsLink", &ScType::IsLink) + .def("IsEdge", &ScType::IsEdge) + .def("IsNode", &ScType::IsNode) + .def("IsUnknown", &ScType::IsUnknown) + .def("IsConst", &ScType::IsConst) + .def("IsVar", &ScType::IsVar) + .def("ToInt", &ScType::operator*) + + .def_readonly("Unknown", &ScType::Unknown) + .def_readonly("Const", &ScType::Const) + .def_readonly("Var", &ScType::Var) + .def_readonly("Node", &ScType::Node) + .def_readonly("Link", &ScType::Link) + + .def_readonly("EdgeUCommon", &ScType::EdgeUCommon) + .def_readonly("EdgeDCommon", &ScType::EdgeDCommon) + .def_readonly("EdgeUCommonConst", &ScType::EdgeUCommonConst) + .def_readonly("EdgeDCommonConst", &ScType::EdgeDCommonConst) + .def_readonly("EdgeAccess", &ScType::EdgeAccess) + .def_readonly("EdgeAccessConstPosPerm", &ScType::EdgeAccessConstPosPerm) + .def_readonly("EdgeAccessConstNegPerm", &ScType::EdgeAccessConstNegPerm) + .def_readonly("EdgeAccessConstFuzPerm", &ScType::EdgeAccessConstFuzPerm) + .def_readonly("EdgeAccessConstPosTemp", &ScType::EdgeAccessConstPosTemp) + .def_readonly("EdgeAccessConstNegTemp", &ScType::EdgeAccessConstNegTemp) + .def_readonly("EdgeAccessConstFuzTemp", &ScType::EdgeAccessConstFuzTemp) + .def_readonly("EdgeUCommonVar", &ScType::EdgeUCommonVar) + .def_readonly("EdgeDCommonVar", &ScType::EdgeDCommonVar) + .def_readonly("EdgeAccessVarPosPerm", &ScType::EdgeAccessVarPosPerm) + .def_readonly("EdgeAccessVarNegPerm", &ScType::EdgeAccessVarNegPerm) + .def_readonly("EdgeAccessVarFuzPerm", &ScType::EdgeAccessVarFuzPerm) + .def_readonly("EdgeAccessVarPosTemp", &ScType::EdgeAccessVarPosTemp) + .def_readonly("EdgeAccessVarNegTemp", &ScType::EdgeAccessVarNegTemp) + .def_readonly("EdgeAccessVarFuzTemp", &ScType::EdgeAccessVarFuzTemp) + + .def_readonly("NodeConst", &ScType::NodeConst) + .def_readonly("NodeVar", &ScType::NodeVar) + .def_readonly("LinkConst", &ScType::LinkConst) + .def_readonly("LinkVar", &ScType::LinkVar) + + .def_readonly("NodeConstStruct", &ScType::NodeConstStruct) + .def_readonly("NodeConstTuple", &ScType::NodeConstTuple) + .def_readonly("NodeConstRole", &ScType::NodeConstRole) + .def_readonly("NodeConstNoRole", &ScType::NodeConstNoRole) + .def_readonly("NodeConstClass", &ScType::NodeConstClass) + .def_readonly("NodeConstAbstract", &ScType::NodeConstAbstract) + .def_readonly("NodeConstMaterial", &ScType::NodeConstMaterial) + + .def_readonly("NodeVarStruct", &ScType::NodeVarStruct) + .def_readonly("NodeVarTuple", &ScType::NodeVarTuple) + .def_readonly("NodeVarRole", &ScType::NodeVarRole) + .def_readonly("NodeVarNoRole", &ScType::NodeVarNoRole) + .def_readonly("NodeVarClass", &ScType::NodeVarClass) + .def_readonly("NodeVarAbstract", &ScType::NodeVarAbstract) + .def_readonly("NodeVarMaterial", &ScType::NodeVarMaterial); bp::enum_("ScResult") - .value("Ok", SC_RESULT_OK) - .value("Error", SC_RESULT_ERROR) - .value("ErrorInvalidParams", SC_RESULT_ERROR_INVALID_PARAMS) - .value("ErrorInvalidType", SC_RESULT_ERROR_INVALID_TYPE) - .value("ErrorIO", SC_RESULT_ERROR_IO) - .value("ErrorInvalidState", SC_RESULT_ERROR_INVALID_STATE) - .value("ErrorNotFound", SC_RESULT_ERROR_NOT_FOUND) - .value("ErrorNoWriteRights", SC_RESULT_ERROR_NO_WRITE_RIGHTS) - .value("ErrorNoReadRights", SC_RESULT_ERROR_NO_READ_RIGHTS) - .value("ErrorNoRights", SC_RESULT_ERROR_NO_RIGHTS) - .value("No", SC_RESULT_NO) - .value("Unknown", SC_RESULT_UNKNOWN) - ; + .value("Ok", SC_RESULT_OK) + .value("Error", SC_RESULT_ERROR) + .value("ErrorInvalidParams", SC_RESULT_ERROR_INVALID_PARAMS) + .value("ErrorInvalidType", SC_RESULT_ERROR_INVALID_TYPE) + .value("ErrorIO", SC_RESULT_ERROR_IO) + .value("ErrorInvalidState", SC_RESULT_ERROR_INVALID_STATE) + .value("ErrorNotFound", SC_RESULT_ERROR_NOT_FOUND) + .value("ErrorNoWriteRights", SC_RESULT_ERROR_NO_WRITE_RIGHTS) + .value("ErrorNoReadRights", SC_RESULT_ERROR_NO_READ_RIGHTS) + .value("ErrorNoRights", SC_RESULT_ERROR_NO_RIGHTS) + .value("No", SC_RESULT_NO) + .value("Unknown", SC_RESULT_UNKNOWN); bp::class_("ScKeynodesImpl", bp::no_init) - .def("GetResultCodeAddr", bp::make_function(&ScKeynodes::GetResultCodeAddr, bp::return_value_policy())) - .staticmethod("GetResultCodeAddr") - .def("GetResultCodeByAddr", bp::make_function(&ScKeynodes::GetResultCodeByAddr, bp::return_value_policy())) - .staticmethod("GetResultCodeByAddr") - .def_readonly("kCommandStateAddr", &ScKeynodes::kCommandStateAddr) - .def_readonly("kCommandInitiatedAddr", &ScKeynodes::kCommandInitiatedAddr) - .def_readonly("kCommandProgressdAddr", &ScKeynodes::kCommandProgressdAddr) - .def_readonly("kCommandFinishedAddr", &ScKeynodes::kCommandFinishedAddr) - ; + .def( + "GetResultCodeAddr", + bp::make_function(&ScKeynodes::GetResultCodeAddr, bp::return_value_policy())) + .staticmethod("GetResultCodeAddr") + .def( + "GetResultCodeByAddr", + bp::make_function(&ScKeynodes::GetResultCodeByAddr, bp::return_value_policy())) + .staticmethod("GetResultCodeByAddr") + .def_readonly("kCommandStateAddr", &ScKeynodes::kCommandStateAddr) + .def_readonly("kCommandInitiatedAddr", &ScKeynodes::kCommandInitiatedAddr) + .def_readonly("kCommandProgressdAddr", &ScKeynodes::kCommandProgressdAddr) + .def_readonly("kCommandFinishedAddr", &ScKeynodes::kCommandFinishedAddr); bp::class_("ScAgentCommandImpl", bp::no_init) - .def("CreateCommand", &impl::ScAgentCommandImpl::CreateCommand) - .staticmethod("CreateCommand") - .def("RunCommand", &impl::ScAgentCommandImpl::RunCommand) - .staticmethod("RunCommand") - .def("RunCommandWait", &impl::ScAgentCommandImpl::RunCommandWait) - .staticmethod("RunCommandWait") - .def("GetCommandResultAddr", &impl::ScAgentCommandImpl::GetCommandResultAddr) - .staticmethod("GetCommandResultAddr") - ; + .def("CreateCommand", &impl::ScAgentCommandImpl::CreateCommand) + .staticmethod("CreateCommand") + .def("RunCommand", &impl::ScAgentCommandImpl::RunCommand) + .staticmethod("RunCommand") + .def("RunCommandWait", &impl::ScAgentCommandImpl::RunCommandWait) + .staticmethod("RunCommandWait") + .def("GetCommandResultAddr", &impl::ScAgentCommandImpl::GetCommandResultAddr) + .staticmethod("GetCommandResultAddr"); } -} // namespace +} // namespace namespace py { - void ScPythonMemoryModule::Initialize() { PyImport_AppendInittab("sc", &PyInit_sc); } -} // namespace py - +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_module.hpp b/sc-memory/sc-memory/python/sc_python_module.hpp index 52a28e44e3..fd5f10a85e 100644 --- a/sc-memory/sc-memory/python/sc_python_module.hpp +++ b/sc-memory/sc-memory/python/sc_python_module.hpp @@ -7,11 +7,10 @@ namespace py { - class ScPythonMemoryModule { public: static void Initialize(); }; -} // py +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_service.cpp b/sc-memory/sc-memory/python/sc_python_service.cpp index f66552efb6..20cd6af00d 100644 --- a/sc-memory/sc-memory/python/sc_python_service.cpp +++ b/sc-memory/sc-memory/python/sc_python_service.cpp @@ -5,7 +5,6 @@ namespace py { - ScPythonService::ScPythonService(std::string const & scriptName) : m_scriptName(scriptName) { @@ -29,16 +28,13 @@ void ScPythonService::Run(std::string const & params) m_bridge->SetInitParams(params); // Run script in a separate thread - m_workThread.reset(new std::thread([&] - { + m_workThread.reset(new std::thread([&] { py::ScPythonInterpreter::RunScript( - m_scriptName, - ScMemoryContext(sc_access_lvl_make_min, m_scriptName.c_str()), - m_bridge); + m_scriptName, ScMemoryContext(sc_access_lvl_make_min, m_scriptName.c_str()), m_bridge); SC_LOG_UNLOAD("Python service " + m_scriptName); })); - + // wait until bridge starts m_bridge->WaitReady(); } @@ -55,5 +51,4 @@ bool ScPythonService::IsRun() const return !m_bridge->IsFinished(); } - -} +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_service.hpp b/sc-memory/sc-memory/python/sc_python_service.hpp index 7ac76e1f07..2e7584b821 100644 --- a/sc-memory/sc-memory/python/sc_python_service.hpp +++ b/sc-memory/sc-memory/python/sc_python_service.hpp @@ -7,27 +7,25 @@ namespace py { - class ScPythonService { - protected: _SC_EXTERN explicit ScPythonService(std::string const & scriptName); _SC_EXTERN ~ScPythonService(); public: /** Run specified service. `params` string will be passed into python module initialization function. - * If you want to implement your own logic on start, then - * override RunImpl function. - */ + * If you want to implement your own logic on start, then + * override RunImpl function. + */ _SC_EXTERN void Run(std::string const & params = ""); /** Stops run of this service. This function doesn't returns until service thread stoped - */ + */ _SC_EXTERN void Stop(); /** Check if it still runs - */ + */ _SC_EXTERN bool IsRun() const; protected: @@ -42,9 +40,9 @@ class ScPythonService } private: - std::string m_scriptName; // name of script to run - ScPythonBridgePtr m_bridge; // special bridge to communicate with python script - std::unique_ptr m_workThread; // thread where script runs + std::string m_scriptName; // name of script to run + ScPythonBridgePtr m_bridge; // special bridge to communicate with python script + std::unique_ptr m_workThread; // thread where script runs }; // Implementation of dummy python service. Used commonly for test issues @@ -57,21 +55,33 @@ class DummyService : public ScPythonService } private: - void RunImpl() override {} - void StopImpl() override {} + void RunImpl() override + { + } + void StopImpl() override + { + } }; - #define PYTHON_DECLARE_SERVICE(__name) \ -class __name##PythonService : public py::ScPythonService \ -{ \ -public:\ - explicit __name##PythonService(std::string const & scriptName) \ - : py::ScPythonService(scriptName) {} \ - virtual ~__name##PythonService() {} \ -private: \ - void RunImpl() final override {} \ - void StopImpl() final override {} \ -}; - -} // namespace py + class __name##PythonService : public py::ScPythonService \ + { \ + public: \ + explicit __name##PythonService(std::string const & scriptName) \ + : py::ScPythonService(scriptName) \ + { \ + } \ + virtual ~__name##PythonService() \ + { \ + } \ +\ + private: \ + void RunImpl() final override \ + { \ + } \ + void StopImpl() final override \ + { \ + } \ + }; + +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_threads.cpp b/sc-memory/sc-memory/python/sc_python_threads.cpp index 1b6691f111..d6420aa75b 100644 --- a/sc-memory/sc-memory/python/sc_python_threads.cpp +++ b/sc-memory/sc-memory/python/sc_python_threads.cpp @@ -2,7 +2,6 @@ namespace py { - ScPythonMainThread::ScPythonMainThread() { Py_Initialize(); @@ -20,7 +19,6 @@ ScPythonMainThread::~ScPythonMainThread() Py_Finalize(); } - // ------------------------------ ScPythonSubThread::ScPythonSubThread() { @@ -42,4 +40,4 @@ ScPythonSubThread::~ScPythonSubThread() PyGILState_Release(m_mainGILState); } -} // namespace py +} // namespace py diff --git a/sc-memory/sc-memory/python/sc_python_threads.hpp b/sc-memory/sc-memory/python/sc_python_threads.hpp index cccf016076..d084b235bf 100644 --- a/sc-memory/sc-memory/python/sc_python_threads.hpp +++ b/sc-memory/sc-memory/python/sc_python_threads.hpp @@ -4,7 +4,6 @@ namespace py { - class ScPythonMainThread { public: @@ -26,20 +25,27 @@ class ScPythonSubThread private: PyGILState_STATE m_mainGILState; - PyThreadState* m_oldThreadState; - PyThreadState* m_newThreadState; - PyThreadState* m_subThreadState; + PyThreadState * m_oldThreadState; + PyThreadState * m_newThreadState; + PyThreadState * m_subThreadState; PyGILState_STATE m_subGILState; }; class WithoutGIL { public: - WithoutGIL() { m_state = PyEval_SaveThread(); } - ~WithoutGIL() { PyEval_RestoreThread(m_state); } + WithoutGIL() + { + m_state = PyEval_SaveThread(); + } + ~WithoutGIL() + { + PyEval_RestoreThread(m_state); + } WithoutGIL(WithoutGIL const &) = delete; WithoutGIL & operator=(WithoutGIL const &) = delete; + private: PyThreadState * m_state; }; @@ -47,8 +53,14 @@ class WithoutGIL class WithGIL { public: - WithGIL() { m_state = PyGILState_Ensure(); } - ~WithGIL() { PyGILState_Release(m_state); } + WithGIL() + { + m_state = PyGILState_Ensure(); + } + ~WithGIL() + { + PyGILState_Release(m_state); + } WithGIL(WithoutGIL const &) = delete; WithGIL & operator=(WithoutGIL const &) = delete; @@ -57,4 +69,4 @@ class WithGIL PyGILState_STATE m_state; }; -} // namespace py \ No newline at end of file +} // namespace py \ No newline at end of file diff --git a/sc-memory/sc-memory/sc_addr.cpp b/sc-memory/sc-memory/sc_addr.cpp index 9f06e22425..5a4e85b3f2 100644 --- a/sc-memory/sc-memory/sc_addr.cpp +++ b/sc-memory/sc-memory/sc_addr.cpp @@ -39,17 +39,17 @@ ScAddr::HashType ScAddr::Hash() const return ((m_realAddr.seg << 16) | m_realAddr.offset); } -bool ScAddr::operator == (ScAddr const & other) const +bool ScAddr::operator==(ScAddr const & other) const { return SC_ADDR_IS_EQUAL(m_realAddr, other.m_realAddr); } -bool ScAddr::operator != (ScAddr const & other) const +bool ScAddr::operator!=(ScAddr const & other) const { return SC_ADDR_IS_NOT_EQUAL(m_realAddr, other.m_realAddr); } -ScRealAddr const & ScAddr::operator * () const +ScRealAddr const & ScAddr::operator*() const { return m_realAddr; } @@ -58,4 +58,3 @@ ScRealAddr const & ScAddr::GetRealAddr() const { return m_realAddr; } - diff --git a/sc-memory/sc-memory/sc_addr.hpp b/sc-memory/sc-memory/sc_addr.hpp index 5e12672f96..f3f3be5a87 100644 --- a/sc-memory/sc-memory/sc_addr.hpp +++ b/sc-memory/sc-memory/sc_addr.hpp @@ -21,8 +21,10 @@ class _SC_EXTERN ScAddr { friend class ScMemoryContext; - template friend class TIterator3; - template friend class TIterator5; + template + friend class TIterator3; + template + friend class TIterator5; public: using HashType = uint64_t; @@ -36,9 +38,9 @@ class _SC_EXTERN ScAddr bool IsValid() const; void Reset(); - bool operator == (ScAddr const & other) const; - bool operator != (ScAddr const & other) const; - ScRealAddr const & operator * () const; + bool operator==(ScAddr const & other) const; + bool operator!=(ScAddr const & other) const; + ScRealAddr const & operator*() const; HashType Hash() const; /// TODO: remove and replace by operator * () @@ -53,7 +55,7 @@ using ScAddrList = std::list; struct RealAddrLessFunc { - bool operator () (ScRealAddr const & a, ScRealAddr const & b) const + bool operator()(ScRealAddr const & a, ScRealAddr const & b) const { if (a.seg < b.seg) return true; @@ -67,7 +69,7 @@ struct RealAddrLessFunc struct ScAddLessFunc { - bool operator () (ScAddr const & a, ScAddr const & b) const + bool operator()(ScAddr const & a, ScAddr const & b) const { return RealAddrLessFunc()(*a, *b); } @@ -77,20 +79,22 @@ struct ScAddLessFunc template struct ScAddrHashFunc { - HashType operator () (ScAddr const & addr); + HashType operator()(ScAddr const & addr); }; -template <> struct ScAddrHashFunc < uint32_t > +template <> +struct ScAddrHashFunc { - uint32_t operator() (ScAddr const & addr) const + uint32_t operator()(ScAddr const & addr) const { return SC_ADDR_LOCAL_TO_INT(*addr); } }; -template <> struct ScAddrHashFunc < uint64_t > +template <> +struct ScAddrHashFunc { - uint64_t operator() (ScAddr const & addr) const + uint64_t operator()(ScAddr const & addr) const { return addr.Hash(); } diff --git a/sc-memory/sc-memory/sc_common_templ.cpp b/sc-memory/sc-memory/sc_common_templ.cpp index 55d5eafa31..aa84552f77 100644 --- a/sc-memory/sc-memory/sc_common_templ.cpp +++ b/sc-memory/sc-memory/sc_common_templ.cpp @@ -2,17 +2,12 @@ namespace sc { - ScAddr ResolveRelationTuple(ScMemoryContext & ctx, ScAddr const & elAddr, ScAddr const & relAddr) { ScTemplate templ; templ.TripleWithRelation( - ScType::NodeVarTuple >> "_tuple", - ScType::EdgeDCommonVar, - elAddr, - ScType::EdgeAccessVarPosPerm, - relAddr); + ScType::NodeVarTuple >> "_tuple", ScType::EdgeDCommonVar, elAddr, ScType::EdgeAccessVarPosPerm, relAddr); ScTemplateSearchResult searchRes; if (ctx.HelperSearchTemplate(templ, searchRes)) @@ -23,11 +18,10 @@ ScAddr ResolveRelationTuple(ScMemoryContext & ctx, ScAddr const & elAddr, ScAddr ScTemplateGenResult genRes; if (!ctx.HelperGenTemplate(templ, genRes)) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "Can't create tuple"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't create tuple"); } return genRes["_tuple"]; } -} // namespace sc \ No newline at end of file +} // namespace sc \ No newline at end of file diff --git a/sc-memory/sc-memory/sc_common_templ.hpp b/sc-memory/sc-memory/sc_common_templ.hpp index 9526e1a0f5..1a8186f6e3 100644 --- a/sc-memory/sc-memory/sc_common_templ.hpp +++ b/sc-memory/sc-memory/sc_common_templ.hpp @@ -6,7 +6,6 @@ namespace sc { - /* Create construction: * elAddr <= relAddr: {};; * If construction exist, then returns exist tuple addr; otherwise create new one. @@ -25,11 +24,7 @@ ScAddr SetRelationValue(ScMemoryContext & ctx, ScAddr const & elAddr, ScAddr con ScTemplate templ; templ.TripleWithRelation( - elAddr, - ScType::EdgeDCommonVar, - ScType::Link >> "_link", - ScType::EdgeAccessVarPosPerm, - relAddr); + elAddr, ScType::EdgeDCommonVar, ScType::Link >> "_link", ScType::EdgeAccessVarPosPerm, relAddr); ScAddr linkAddr; ScTemplateSearchResult res; @@ -44,10 +39,8 @@ ScAddr SetRelationValue(ScMemoryContext & ctx, ScAddr const & elAddr, ScAddr con if (!linkAddr.IsValid()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "Can't create value relation"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't create value relation"); } - } ScLink link(ctx, linkAddr); @@ -56,4 +49,4 @@ ScAddr SetRelationValue(ScMemoryContext & ctx, ScAddr const & elAddr, ScAddr con return linkAddr; } -} // namespace sc \ No newline at end of file +} // namespace sc \ No newline at end of file diff --git a/sc-memory/sc-memory/sc_debug.cpp b/sc-memory/sc-memory/sc_debug.cpp index c6e29b9922..75d0098b28 100644 --- a/sc-memory/sc-memory/sc_debug.cpp +++ b/sc-memory/sc-memory/sc_debug.cpp @@ -1,32 +1,31 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_debug.hpp" namespace utils { +ScException::ScException(std::string const & description, std::string const & msg) + : m_description(description) + , m_msg(msg) +{ +} - ScException::ScException(std::string const & description, std::string const & msg) - : m_description(description) - , m_msg(msg) - { - } - - ScException::~ScException() throw() - { - } +ScException::~ScException() throw() +{ +} - const char * ScException::Description() const throw() - { - return m_description.c_str(); - } +const char * ScException::Description() const throw() +{ + return m_description.c_str(); +} - const char * ScException::Message() const throw() - { - return m_msg.c_str(); - } +const char * ScException::Message() const throw() +{ + return m_msg.c_str(); +} -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/sc_debug.hpp b/sc-memory/sc-memory/sc_debug.hpp index d34f6ce8fd..89225fc02f 100644 --- a/sc-memory/sc-memory/sc_debug.hpp +++ b/sc-memory/sc-memory/sc_debug.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -12,7 +12,6 @@ namespace utils { - /// ----------------------- class ScException : public std::exception @@ -32,160 +31,225 @@ class ScException : public std::exception class ExceptionAssert final : public ScException { public: - ExceptionAssert(std::string const & description, std::string const & msg) : ScException("Assert: " + description, msg) {} + ExceptionAssert(std::string const & description, std::string const & msg) + : ScException("Assert: " + description, msg) + { + } }; class ExceptionCritical final : public ScException { public: - ExceptionCritical(std::string const & description, std::string const & msg) : ScException("Critical: " + description, msg) {} + ExceptionCritical(std::string const & description, std::string const & msg) + : ScException("Critical: " + description, msg) + { + } }; class ExceptionInvalidParams final : public ScException { public: - ExceptionInvalidParams(std::string const & description, std::string const & msg) : ScException("InvalidParams: " + description, msg) {} + ExceptionInvalidParams(std::string const & description, std::string const & msg) + : ScException("InvalidParams: " + description, msg) + { + } }; class ExceptionInvalidState final : public ScException { public: - ExceptionInvalidState(std::string const & description, std::string const & msg) : ScException("InvalidState: " + description, msg) {} + ExceptionInvalidState(std::string const & description, std::string const & msg) + : ScException("InvalidState: " + description, msg) + { + } }; class ExceptionItemNotFound final : public ScException { public: - ExceptionItemNotFound(std::string const & description, std::string const & msg) : ScException("ItemNotFound: " + description, msg) {} + ExceptionItemNotFound(std::string const & description, std::string const & msg) + : ScException("ItemNotFound: " + description, msg) + { + } }; class ExceptionParseError final : public ScException { public: - ExceptionParseError(std::string const & description, std::string const & msg) : ScException("ParseError: " + description, msg) {} + ExceptionParseError(std::string const & description, std::string const & msg) + : ScException("ParseError: " + description, msg) + { + } }; class ExceptionNotImplemented final : public ScException { public: - ExceptionNotImplemented(std::string const & description, std::string const & msg) : ScException("NotImplemented: " + description, msg) {} + ExceptionNotImplemented(std::string const & description, std::string const & msg) + : ScException("NotImplemented: " + description, msg) + { + } }; class ExceptionInvalidType final : public ScException { public: - explicit ExceptionInvalidType(std::string const & description, std::string const & msg) : ScException("InvalidType: " + description, msg) {} + explicit ExceptionInvalidType(std::string const & description, std::string const & msg) + : ScException("InvalidType: " + description, msg) + { + } }; -#define error(__str) { throw ScException(__str); } -#define error_invalid_params(__str) { throw ScExceptionInvalidParams(__str); } +#define error(__str) \ + { \ + throw ScException(__str); \ + } +#define error_invalid_params(__str) \ + { \ + throw ScExceptionInvalidParams(__str); \ + } // Asserts #define THROW_EXCEPTION(_exception_class, _msg, _file, _line) \ -{ \ - std::stringstream _str_message; \ - _str_message << _msg; \ - std::string _msg_raw = _str_message.str(); \ - _str_message << std::endl << "File: " << _file << std::endl << "Line:" << _line << std::endl; \ - throw _exception_class(_str_message.str(), _msg_raw); \ -} + { \ + std::stringstream _str_message; \ + _str_message << _msg; \ + std::string _msg_raw = _str_message.str(); \ + _str_message << std::endl << "File: " << _file << std::endl << "Line:" << _line << std::endl; \ + throw _exception_class(_str_message.str(), _msg_raw); \ + } #define SC_THROW_EXCEPTION(_exception_class, _msg) THROW_EXCEPTION(_exception_class, _msg, __FILE__, __LINE__) #define SC_NOT_IMPLEMENTED(_msg) SC_THROW_EXCEPTION(utils::ExceptionNotImplemented, _msg) #define _ASSERT_IMPL(_exception_class, _expr, _msg, _file, _line) \ -{ \ - if (!(_expr)) \ -{ \ - std::string _message = ::utils::impl::Message("SC_ASSERT("#_expr")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(_exception_class, _message, _file, _line); \ -} \ -} + { \ + if (!(_expr)) \ + { \ + std::string _message = ::utils::impl::Message("SC_ASSERT(" #_expr ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(_exception_class, _message, _file, _line); \ + } \ + } #if SC_DEBUG_MODE -# define SC_ASSERT(_expr, _msg) { _ASSERT_IMPL(::utils::ExceptionAssert, _expr, _msg, __FILE__, __LINE__ ); } +# define SC_ASSERT(_expr, _msg) \ + { \ + _ASSERT_IMPL(::utils::ExceptionAssert, _expr, _msg, __FILE__, __LINE__); \ + } // will be removed use SC_ASSERT instead -# define ASSERT(_expr, _msg) { _ASSERT_IMPL(::utils::ExceptionAssert, _expr, _msg, __FILE__, __LINE__); } +# define ASSERT(_expr, _msg) \ + { \ + _ASSERT_IMPL(::utils::ExceptionAssert, _expr, _msg, __FILE__, __LINE__); \ + } #else -# define SC_ASSERT(_expr, _msg) ((void)0) +# define SC_ASSERT(_expr, _msg) ((void)0) // will be removed use SC_ASSERT instead -# define ASSERT(_expr, _msg) ((void)0) +# define ASSERT(_expr, _msg) ((void)0) #endif -# define SC_CHECK_PARAM(_expr, _msg) { _ASSERT_IMPL(::utils::ExceptionInvalidParams, (_expr).IsValid(), _msg, __FILE__, __LINE__ ); } +#define SC_CHECK_PARAM(_expr, _msg) \ + { \ + _ASSERT_IMPL(::utils::ExceptionInvalidParams, (_expr).IsValid(), _msg, __FILE__, __LINE__); \ + } #define _CHECK_IMPL(_expr, _msg, _name) \ do \ -{ \ - if (_expr) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string(_name) + "("#_expr")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if (_expr) \ + { \ + } \ + else \ + { \ + std::string _message = ::utils::impl::Message(std::string(_name) + "(" #_expr ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK(_expr, _msg) _CHECK_IMPL(_expr, _msg, "CHECK") #define SC_CHECK_NOT(_expr, _msg) _CHECK_IMPL(!_expr, _msg, "CHECK_NOT") #define SC_CHECK_EQUAL(_a, _b, _msg) \ do \ -{ \ - if ((_a) == (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_EQUAL") + "("#_a" == "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if ((_a) == (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = \ + ::utils::impl::Message(std::string("SC_CHECK_EQUAL") + "(" #_a " == " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK_NOT_EQUAL(_a, _b, _msg) \ do \ -{ \ - if ((_a) != (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_NOT_EQUAL") + "("#_a" != "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if ((_a) != (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = ::utils::impl::Message( \ + std::string("SC_CHECK_NOT_EQUAL") + "(" #_a " != " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK_GREAT(_a, _b, _msg) \ do \ -{ \ - if ((_a) > (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_GREAT") + "("#_a" > "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if ((_a) > (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = \ + ::utils::impl::Message(std::string("SC_CHECK_GREAT") + "(" #_a " > " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK_GREAT_EQ(_a, _b, _msg) \ do \ -{ \ - if ((_a) >= (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_GREAT_EQ") + "("#_a" >= "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if ((_a) >= (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = ::utils::impl::Message( \ + std::string("SC_CHECK_GREAT_EQ") + "(" #_a " >= " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK_LESS(_a, _b, _msg) \ do \ -{ \ - if ((_a) < (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_LESS") + "("#_a" < "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime + { \ + if ((_a) < (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = \ + ::utils::impl::Message(std::string("SC_CHECK_LESS") + "(" #_a " < " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime #define SC_CHECK_LESS_EQ(_a, _b, _msg) \ do \ -{ \ - if ((_a) <= (_b)) {} else \ -{ \ - std::string _message = ::utils::impl::Message(std::string("SC_CHECK_LESS_EQ") + "("#_a" <= "#_b")", ::utils::impl::Message _msg); \ - THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ -} \ -} while (false); // stop runtime - - -} // namespace utils + { \ + if ((_a) <= (_b)) \ + { \ + } \ + else \ + { \ + std::string _message = ::utils::impl::Message( \ + std::string("SC_CHECK_LESS_EQ") + "(" #_a " <= " #_b ")", ::utils::impl::Message _msg); \ + THROW_EXCEPTION(::utils::ExceptionAssert, _message, __FILE__, __LINE__); \ + } \ + } while (false); // stop runtime + +} // namespace utils diff --git a/sc-memory/sc-memory/sc_defines.hpp b/sc-memory/sc-memory/sc_defines.hpp index 37ebec3ed4..f090e2840d 100644 --- a/sc-memory/sc-memory/sc_defines.hpp +++ b/sc-memory/sc-memory/sc_defines.hpp @@ -12,38 +12,46 @@ #define SC_COMBINE(v1, v2, v3, v4) SC_COMBINE_INTERNAL(v1, v2, v3, v4) #ifdef __SC_REFLECTION_PARSER__ -#define SC_BODY_INTERNAL(...) __attribute__((annotate(#__VA_ARGS__))) void __null_body() {} -#define SC_CLASS_INTERNAL(...) __attribute__((annotate(#__VA_ARGS__))) void __null_meta() {} - -#define SC_CLASS(...) SC_CLASS_INTERNAL(__VA_ARGS__) -#define SC_GENERATED_BODY(...) SC_BODY_INTERNAL(GenBody()) -#define SC_PROPERTY(...) __attribute__((annotate(#__VA_ARGS__))) +# define SC_BODY_INTERNAL(...) \ + __attribute__((annotate(#__VA_ARGS__))) void __null_body() \ + { \ + } +# define SC_CLASS_INTERNAL(...) \ + __attribute__((annotate(#__VA_ARGS__))) void __null_meta() \ + { \ + } + +# define SC_CLASS(...) SC_CLASS_INTERNAL(__VA_ARGS__) +# define SC_GENERATED_BODY(...) SC_BODY_INTERNAL(GenBody()) +# define SC_PROPERTY(...) __attribute__((annotate(# __VA_ARGS__))) #else -#define SC_GENERATED_BODY_ITEMS(v) SC_COMBINE(ScFileID, _, __LINE__, v) -#define SC_GENERATED_BODY_INIT() \ +# define SC_GENERATED_BODY_ITEMS(v) SC_COMBINE(ScFileID, _, __LINE__, v) +# define SC_GENERATED_BODY_INIT() \ public: \ - static bool InitGlobal() { return _InitStaticInternal(); } \ + static bool InitGlobal() \ + { \ + return _InitStaticInternal(); \ + } \ +\ private: \ - SC_GENERATED_BODY_ITEMS(_init) \ - SC_GENERATED_BODY_ITEMS(_initStatic) \ - SC_GENERATED_BODY_ITEMS(_decl) - + SC_GENERATED_BODY_ITEMS(_init) \ + SC_GENERATED_BODY_ITEMS(_initStatic) \ + SC_GENERATED_BODY_ITEMS(_decl) -#define SC_CLASS(...) -#define SC_GENERATED_BODY(...) SC_GENERATED_BODY_INIT() -#define SC_PROPERTY(...) +# define SC_CLASS(...) +# define SC_GENERATED_BODY(...) SC_GENERATED_BODY_INIT() +# define SC_PROPERTY(...) -#define SC_OBJECT_INIT_GLOBAL_CALL(__class) __class::InitGlobal(); +# define SC_OBJECT_INIT_GLOBAL_CALL(__class) __class::InitGlobal(); // for autocompletion -#define Keynode(__X) -#define ForceCreate(__X) -#define CmdClass -#define Agent +# define Keynode(__X) +# define ForceCreate(__X) +# define CmdClass +# define Agent // utils -#define SC_UNUSED(__X) (void)__X - -#endif // __SC_REFLECTION_PARSER__ +# define SC_UNUSED(__X) (void)__X +#endif // __SC_REFLECTION_PARSER__ diff --git a/sc-memory/sc-memory/sc_event.cpp b/sc-memory/sc-memory/sc_event.cpp index acb6293104..7508ea1610 100644 --- a/sc-memory/sc-memory/sc_event.cpp +++ b/sc-memory/sc-memory/sc_event.cpp @@ -15,7 +15,6 @@ namespace { - sc_event_type ConvertEventType(ScEvent::Type type) { switch (type) @@ -39,17 +38,21 @@ sc_event_type ConvertEventType(ScEvent::Type type) return SC_EVENT_CONTENT_CHANGED; } - SC_THROW_EXCEPTION(utils::ExceptionNotImplemented, - "Unsupported event type " + std::to_string(int(type))); + SC_THROW_EXCEPTION(utils::ExceptionNotImplemented, "Unsupported event type " + std::to_string(int(type))); return SC_EVENT_UNKNOWN; } -} +} // namespace -ScEvent::ScEvent(const ScMemoryContext & ctx, const ScAddr & addr, Type eventType, ScEvent::DelegateFunc func /*= DelegateFunc()*/) +ScEvent::ScEvent( + const ScMemoryContext & ctx, + const ScAddr & addr, + Type eventType, + ScEvent::DelegateFunc func /*= DelegateFunc()*/) { m_delegate = func; - m_event = sc_event_new_ex(*ctx, *addr, ConvertEventType(eventType), (sc_pointer)this, &ScEvent::Handler, &ScEvent::HandlerDelete); + m_event = sc_event_new_ex( + *ctx, *addr, ConvertEventType(eventType), (sc_pointer)this, &ScEvent::Handler, &ScEvent::HandlerDelete); } ScEvent::~ScEvent() @@ -65,12 +68,13 @@ void ScEvent::RemoveDelegate() sc_result ScEvent::Handler(sc_event const * evt, sc_addr edge, sc_addr other_el) { - ScEvent * eventObj = (ScEvent*)sc_event_get_data(evt); + ScEvent * eventObj = (ScEvent *)sc_event_get_data(evt); SC_ASSERT(eventObj != nullptr, ()); if (eventObj->m_delegate) { - return eventObj->m_delegate(ScAddr(sc_event_get_element(evt)), ScAddr(edge), ScAddr(other_el)) ? SC_RESULT_OK : SC_RESULT_ERROR; + return eventObj->m_delegate(ScAddr(sc_event_get_element(evt)), ScAddr(edge), ScAddr(other_el)) ? SC_RESULT_OK + : SC_RESULT_ERROR; } return SC_RESULT_ERROR; @@ -78,7 +82,7 @@ sc_result ScEvent::Handler(sc_event const * evt, sc_addr edge, sc_addr other_el) sc_result ScEvent::HandlerDelete(sc_event const * evt) { - ScEvent * eventObj = (ScEvent*)sc_event_get_data(evt); + ScEvent * eventObj = (ScEvent *)sc_event_get_data(evt); SC_ASSERT(eventObj != nullptr, ()); utils::ScLockScope(eventObj->m_lock); diff --git a/sc-memory/sc-memory/sc_event.hpp b/sc-memory/sc-memory/sc_event.hpp index fd77e3d20c..c7fb67fd35 100644 --- a/sc-memory/sc-memory/sc_event.hpp +++ b/sc-memory/sc-memory/sc_event.hpp @@ -30,7 +30,11 @@ class ScEvent ContentChanged }; - explicit _SC_EXTERN ScEvent(class ScMemoryContext const & ctx, const ScAddr & addr, Type eventType, DelegateFunc func = DelegateFunc()); + explicit _SC_EXTERN ScEvent( + class ScMemoryContext const & ctx, + const ScAddr & addr, + Type eventType, + DelegateFunc func = DelegateFunc()); virtual _SC_EXTERN ~ScEvent(); // Don't allow copying of events @@ -71,6 +75,7 @@ class ScEventAddOutputEdge final : public ScEvent class ScEventAddInputEdge final : public ScEvent { friend class ScMemoryContext; + public: _SC_EXTERN ScEventAddInputEdge(const ScMemoryContext & ctx, const ScAddr & addr, ScEvent::DelegateFunc func) : ScEvent(ctx, addr, ScEvent::Type::AddInputEdge, func) @@ -81,6 +86,7 @@ class ScEventAddInputEdge final : public ScEvent class ScEventRemoveOutputEdge final : public ScEvent { friend class ScMemoryContext; + public: _SC_EXTERN ScEventRemoveOutputEdge(const ScMemoryContext & ctx, const ScAddr & addr, ScEvent::DelegateFunc func) : ScEvent(ctx, addr, ScEvent::Type::RemoveOutputEdge, func) @@ -91,6 +97,7 @@ class ScEventRemoveOutputEdge final : public ScEvent class ScEventRemoveInputEdge final : public ScEvent { friend class ScMemoryContext; + public: _SC_EXTERN ScEventRemoveInputEdge(const ScMemoryContext & ctx, const ScAddr & addr, ScEvent::DelegateFunc func) : ScEvent(ctx, addr, ScEvent::Type::RemoveInputEdge, func) @@ -101,6 +108,7 @@ class ScEventRemoveInputEdge final : public ScEvent class ScEventEraseElement final : public ScEvent { friend class ScMemoryContext; + public: _SC_EXTERN ScEventEraseElement(const ScMemoryContext & ctx, const ScAddr & addr, ScEvent::DelegateFunc func) : ScEvent(ctx, addr, ScEvent::Type::EraseElement, func) @@ -111,6 +119,7 @@ class ScEventEraseElement final : public ScEvent class ScEventContentChanged final : public ScEvent { friend class ScMemoryContext; + public: _SC_EXTERN ScEventContentChanged(const ScMemoryContext & ctx, const ScAddr & addr, ScEvent::DelegateFunc func) : ScEvent(ctx, addr, ScEvent::Type::ContentChanged, func) diff --git a/sc-memory/sc-memory/sc_iterator.cpp b/sc-memory/sc-memory/sc_iterator.cpp index acecbf7e43..f1c83e2665 100644 --- a/sc-memory/sc-memory/sc_iterator.cpp +++ b/sc-memory/sc-memory/sc_iterator.cpp @@ -7,57 +7,78 @@ #include "sc_iterator.hpp" #include "sc_memory.hpp" - -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScAddr const & p1, sc_type const & p2, ScAddr const & p3) + ScAddr const & p1, + sc_type const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_f_a_f_new(*context, *p1, p2, *p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScAddr const & p1, sc_type const & p2, sc_type const & p3) + ScAddr const & p1, + sc_type const & p2, + sc_type const & p3) { m_iterator = sc_iterator3_f_a_a_new(*context, *p1, p2, p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - sc_type const & p1, sc_type const & p2, ScAddr const & p3) + sc_type const & p1, + sc_type const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_a_a_f_new(*context, p1, p2, *p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - sc_type const & p1, ScAddr const & p2, sc_type const & p3) + sc_type const & p1, + ScAddr const & p2, + sc_type const & p3) { m_iterator = sc_iterator3_a_f_a_new(*context, p1, *p2, p3); } -template<> TIterator3::TIterator3( - ScMemoryContext const & context, - ScAddr const & p1, ScAddr const & p2, sc_type const & p3) +template <> +TIterator3::TIterator3( + ScMemoryContext const & context, + ScAddr const & p1, + ScAddr const & p2, + sc_type const & p3) { m_iterator = sc_iterator3_f_f_a_new(*context, *p1, *p2, p3); } -template<> TIterator3::TIterator3( - ScMemoryContext const & context, - sc_type const & p1, ScAddr const & p2, ScAddr const & p3) +template <> +TIterator3::TIterator3( + ScMemoryContext const & context, + sc_type const & p1, + ScAddr const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_a_f_f_new(*context, p1, *p2, *p3); } -template<> TIterator3::TIterator3( - ScMemoryContext const & context, - ScAddr const & p1, ScAddr const & p2, ScAddr const & p3) +template <> +TIterator3::TIterator3( + ScMemoryContext const & context, + ScAddr const & p1, + ScAddr const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_f_f_f_new(*context, *p1, *p2, *p3); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, sc_type const & p2, @@ -68,7 +89,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_a_a_f_new(*context, *p1, p2, p3, p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, sc_type const & p1, sc_type const & p2, @@ -79,7 +101,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_a_a_f_a_f_new(*context, p1, p2, *p3, p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, sc_type const & p2, @@ -90,7 +113,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_f_a_f_new(*context, *p1, p2, *p3, p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, sc_type const & p2, @@ -101,7 +125,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_f_a_a_new(*context, *p1, p2, *p3, p4, p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, sc_type const & p2, @@ -112,7 +137,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_a_a_a_new(*context, *p1, p2, p3, p4, p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, sc_type const & p1, sc_type const & p2, @@ -123,62 +149,81 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_a_a_f_a_a_new(*context, p1, p2, *p3, p4, p5); } - - // ----------- -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScAddr const & p1, ScType const & p2, ScAddr const & p3) + ScAddr const & p1, + ScType const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_f_a_f_new(*context, *p1, *p2, *p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScAddr const & p1, ScType const & p2, ScType const & p3) + ScAddr const & p1, + ScType const & p2, + ScType const & p3) { m_iterator = sc_iterator3_f_a_a_new(*context, *p1, *p2, *p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScType const & p1, ScType const & p2, ScAddr const & p3) + ScType const & p1, + ScType const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_a_a_f_new(*context, *p1, *p2, *p3); } -template<> TIterator3::TIterator3( +template <> +TIterator3::TIterator3( ScMemoryContext const & context, - ScType const & p1, ScAddr const & p2, ScType const & p3) + ScType const & p1, + ScAddr const & p2, + ScType const & p3) { m_iterator = sc_iterator3_a_f_a_new(*context, *p1, *p2, *p3); } -template<> TIterator3::TIterator3( - ScMemoryContext const & context, - ScAddr const & p1, ScAddr const & p2, ScType const & p3) +template <> +TIterator3::TIterator3( + ScMemoryContext const & context, + ScAddr const & p1, + ScAddr const & p2, + ScType const & p3) { m_iterator = sc_iterator3_f_f_a_new(*context, *p1, *p2, *p3); } -template<> TIterator3::TIterator3( - ScMemoryContext const & context, - ScType const & p1, ScAddr const & p2, ScAddr const & p3) +template <> +TIterator3::TIterator3( + ScMemoryContext const & context, + ScType const & p1, + ScAddr const & p2, + ScAddr const & p3) { m_iterator = sc_iterator3_a_f_f_new(*context, *p1, *p2, *p3); } -template<> TIterator5::TIterator5(ScMemoryContext const & context, - ScAddr const & p1, - ScType const & p2, - ScType const & p3, - ScType const & p4, - ScAddr const & p5) +template <> +TIterator5::TIterator5( + ScMemoryContext const & context, + ScAddr const & p1, + ScType const & p2, + ScType const & p3, + ScType const & p4, + ScAddr const & p5) { m_iterator = sc_iterator5_f_a_a_a_f_new(*context, *p1, *p2, *p3, *p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScType const & p1, ScType const & p2, @@ -189,7 +234,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_a_a_f_a_f_new(*context, *p1, *p2, *p3, *p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, ScType const & p2, @@ -200,7 +246,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_f_a_f_new(*context, *p1, *p2, *p3, *p4, *p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, ScType const & p2, @@ -211,7 +258,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_f_a_a_new(*context, *p1, p2, *p3, p4, p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScAddr const & p1, ScType const & p2, @@ -222,7 +270,8 @@ template<> TIterator5::TIterator5( m_iterator = sc_iterator5_f_a_a_a_a_new(*context, *p1, p2, p3, p4, p5); } -template<> TIterator5::TIterator5( +template <> +TIterator5::TIterator5( ScMemoryContext const & context, ScType const & p1, ScType const & p2, @@ -232,4 +281,3 @@ template<> TIterator5::TIterator5( { m_iterator = sc_iterator5_a_a_f_a_a_new(*context, p1, p2, *p3, p4, p5); } - diff --git a/sc-memory/sc-memory/sc_iterator.hpp b/sc-memory/sc-memory/sc_iterator.hpp index 4179810276..f901d2db70 100644 --- a/sc-memory/sc-memory/sc_iterator.hpp +++ b/sc-memory/sc-memory/sc_iterator.hpp @@ -14,15 +14,15 @@ extern "C" #include "sc-core/sc_memory_headers.h" } - class ScMemoryContext; template class TIteratorBase { public: - - virtual ~TIteratorBase() {} + virtual ~TIteratorBase() + { + } inline bool IsValid() const { @@ -34,22 +34,28 @@ class TIteratorBase //! Returns sc-addr of specified element in iterator result _SC_EXTERN virtual ScAddr Get(sc_uint8 idx) const = 0; - + //! Short form of Get - inline ScAddr operator [] (sc_uint8 idx) const { return Get(idx); } + inline ScAddr operator[](sc_uint8 idx) const + { + return Get(idx); + } protected: IterType * m_iterator; }; - template class TIterator3 : public TIteratorBase { friend class ScMemoryContext; protected: - _SC_EXTERN TIterator3(ScMemoryContext const & context, ParamType1 const & p1, ParamType2 const & p2, ParamType3 const & p3); + _SC_EXTERN TIterator3( + ScMemoryContext const & context, + ParamType1 const & p1, + ParamType2 const & p2, + ParamType3 const & p3); public: _SC_EXTERN virtual ~TIterator3() @@ -59,10 +65,9 @@ class TIterator3 : public TIteratorBase TIterator3(TIterator3 const & other) { - } - TIterator3 & operator = (TIterator3 const & other) + TIterator3 & operator=(TIterator3 const & other) { TakeOwnership(other); return *this; @@ -98,7 +103,13 @@ class TIterator5 : public TIteratorBase friend class ScMemoryContext; protected: - _SC_EXTERN TIterator5(ScMemoryContext const & context, ParamType1 const & p1, ParamType2 const & p2, ParamType3 const & p3, ParamType4 const & p4, ParamType5 const & p5); + _SC_EXTERN TIterator5( + ScMemoryContext const & context, + ParamType1 const & p1, + ParamType2 const & p2, + ParamType3 const & p3, + ParamType4 const & p4, + ParamType5 const & p5); public: _SC_EXTERN virtual ~TIterator5() @@ -127,12 +138,10 @@ class TIterator5 : public TIteratorBase SC_ASSERT(IsValid(), ()); return ScAddr(sc_iterator5_value(m_iterator, idx)); } - }; typedef TIteratorBase ScIterator3Type; typedef TIteratorBase ScIterator5Type; -typedef std::shared_ptr< ScIterator3Type > ScIterator3Ptr; -typedef std::shared_ptr< ScIterator5Type > ScIterator5Ptr; - +typedef std::shared_ptr ScIterator3Ptr; +typedef std::shared_ptr ScIterator5Ptr; diff --git a/sc-memory/sc-memory/sc_keynodes.cpp b/sc-memory/sc-memory/sc_keynodes.cpp index bf188d9e04..4ed96b92e9 100644 --- a/sc-memory/sc-memory/sc_keynodes.cpp +++ b/sc-memory/sc-memory/sc_keynodes.cpp @@ -78,7 +78,7 @@ bool ScKeynodes::Init(bool force) } // command states - ScAddr states[] = { kCommandFinishedAddr, kCommandInitiatedAddr, kCommandProgressdAddr }; + ScAddr states[] = {kCommandFinishedAddr, kCommandInitiatedAddr, kCommandProgressdAddr}; for (auto const & a : states) { if (!ctx.CreateEdge(ScType::EdgeAccessConstPosPerm, kCommandStateAddr, a).IsValid()) @@ -88,10 +88,8 @@ bool ScKeynodes::Init(bool force) // binary types { ScSet set(ctx, kBinaryType); - set << kBinaryDouble << kBinaryFloat << kBinaryString - << kBinaryInt8 << kBinaryInt16 << kBinaryInt32 << kBinaryInt64 - << kBinaryUInt8 << kBinaryUInt16 << kBinaryUInt32 << kBinaryUInt64 - << kBinaryCustom; + set << kBinaryDouble << kBinaryFloat << kBinaryString << kBinaryInt8 << kBinaryInt16 << kBinaryInt32 << kBinaryInt64 + << kBinaryUInt8 << kBinaryUInt16 << kBinaryUInt32 << kBinaryUInt64 << kBinaryCustom; } ms_isInitialized = true; @@ -167,13 +165,12 @@ sc_result ScKeynodes::GetResultCodeByAddr(ScAddr const & resultClassAddr) return SC_RESULT_UNKNOWN; } - ScAddr const & ScKeynodes::GetRrelIndex(size_t idx) { if (idx >= kKeynodeRrelListNum) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, - "You should use index in range[0; " + std::to_string(kKeynodeRrelListNum) + "]"); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidParams, "You should use index in range[0; " + std::to_string(kKeynodeRrelListNum) + "]"); } return kKeynodeRrelList[idx]; diff --git a/sc-memory/sc-memory/sc_link.cpp b/sc-memory/sc-memory/sc_link.cpp index 3b0f747943..4359894994 100644 --- a/sc-memory/sc-memory/sc_link.cpp +++ b/sc-memory/sc-memory/sc_link.cpp @@ -113,20 +113,13 @@ std::string ScLink::GetAsString() const return ""; } - bool ScLink::_DetermineTypeEdgeImpl(ScAddr & outEdge, ScAddr & outType) const { // set type ScTemplate templ; - templ.Triple( - ScKeynodes::kBinaryType, - ScType::EdgeAccessVarPosPerm, - ScType::NodeVarClass >> "_type"); + templ.Triple(ScKeynodes::kBinaryType, ScType::EdgeAccessVarPosPerm, ScType::NodeVarClass >> "_type"); - templ.Triple( - "_type", - ScType::EdgeAccessVarPosTemp >> "_edge", - m_addr); + templ.Triple("_type", ScType::EdgeAccessVarPosTemp >> "_edge", m_addr); ScTemplateSearchResult res; if (m_ctx.HelperSearchTemplate(templ, res)) @@ -139,4 +132,3 @@ bool ScLink::_DetermineTypeEdgeImpl(ScAddr & outEdge, ScAddr & outType) const return false; } - diff --git a/sc-memory/sc-memory/sc_link.hpp b/sc-memory/sc-memory/sc_link.hpp index 6551d55f31..12ca38e629 100644 --- a/sc-memory/sc-memory/sc_link.hpp +++ b/sc-memory/sc-memory/sc_link.hpp @@ -39,33 +39,36 @@ class ScLink // Check if this class has reference to sc-link element bool IsValid() const; - template inline ScAddr const & Type2Addr() const; - template inline void Value2Stream(Type const & value, ScStreamPtr & stream) const + template + inline ScAddr const & Type2Addr() const; + template + inline void Value2Stream(Type const & value, ScStreamPtr & stream) const { - stream.reset(new ScStream((sc_char*)(&value), sizeof(value), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK)); + stream.reset(new ScStream((sc_char *)(&value), sizeof(value), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK)); } - template inline bool Stream2Value(ScStreamPtr const & stream, Type & outValue) const + template + inline bool Stream2Value(ScStreamPtr const & stream, Type & outValue) const { if (stream->Size() != sizeof(Type)) return false; size_t readBytes = 0; - stream->Read((sc_char*)(&outValue), sizeof(Type), readBytes); + stream->Read((sc_char *)(&outValue), sizeof(Type), readBytes); if (sizeof(Type) != readBytes) return false; return true; } - template inline - bool IsType() const + template + inline bool IsType() const { return m_ctx.HelperCheckEdge(Type2Addr(), m_addr, ScType::EdgeAccessConstPosTemp); } - template inline - bool Set(Type const & value) + template + inline bool Set(Type const & value) { ScStreamPtr stream; Value2Stream(value, stream); @@ -90,14 +93,12 @@ class ScLink return true; } - template Type Get() const { if (!IsType()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "You've used incorrect type. Use IsType<>() to check it"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "You've used incorrect type. Use IsType<>() to check it"); } ScStreamPtr const stream = m_ctx.GetLinkContent(m_addr); @@ -108,8 +109,7 @@ class ScLink Type result; if (!Stream2Value(stream, result)) { - SC_THROW_EXCEPTION(utils::ExceptionCritical, - "Failed to get the value of " + std::to_string(m_addr.Hash())); + SC_THROW_EXCEPTION(utils::ExceptionCritical, "Failed to get the value of " + std::to_string(m_addr.Hash())); } return result; @@ -120,39 +120,91 @@ class ScLink protected: _SC_EXTERN bool _DetermineTypeEdgeImpl(ScAddr & outEdge, ScAddr & outType) const; + private: ScMemoryContext & m_ctx; ScAddr m_addr; }; -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryString; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryFloat; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryDouble; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryInt8; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryInt16; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryInt32; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryInt64; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryUInt8; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryUInt16; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryUInt32; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryUInt64; } -template <> inline ScAddr const & ScLink::Type2Addr() const { return ScKeynodes::kBinaryCustom; } +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryString; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryFloat; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryDouble; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryInt8; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryInt16; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryInt32; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryInt64; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryUInt8; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryUInt16; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryUInt32; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryUInt64; +} +template <> +inline ScAddr const & ScLink::Type2Addr() const +{ + return ScKeynodes::kBinaryCustom; +} -template <> inline void ScLink::Value2Stream(std::string const & value, ScStreamPtr & stream) const +template <> +inline void ScLink::Value2Stream(std::string const & value, ScStreamPtr & stream) const { - stream.reset(new ScStream((sc_char*)value.c_str(), value.size(), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK)); + stream.reset(new ScStream((sc_char *)value.c_str(), value.size(), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK)); } -template <> inline void ScLink::Value2Stream(ScStreamPtr const & value, ScStreamPtr & stream) const +template <> +inline void ScLink::Value2Stream(ScStreamPtr const & value, ScStreamPtr & stream) const { stream = value; } -template <> inline bool ScLink::Stream2Value(ScStreamPtr const & stream, std::string & outValue) const +template <> +inline bool ScLink::Stream2Value(ScStreamPtr const & stream, std::string & outValue) const { std::vector buff(stream->Size()); size_t readBytes = 0; - stream->Read((sc_char*)buff.data(), buff.size(), readBytes); + stream->Read((sc_char *)buff.data(), buff.size(), readBytes); if (readBytes != buff.size()) return false; @@ -160,7 +212,8 @@ template <> inline bool ScLink::Stream2Value(ScStreamPtr const & st return true; } -template <> inline bool ScLink::Stream2Value(ScStreamPtr const & stream, ScStreamPtr & outValue) const +template <> +inline bool ScLink::Stream2Value(ScStreamPtr const & stream, ScStreamPtr & outValue) const { outValue = stream; return true; diff --git a/sc-memory/sc-memory/sc_memory.cpp b/sc-memory/sc-memory/sc_memory.cpp index 54e635c827..4dc5a9fc40 100644 --- a/sc-memory/sc-memory/sc_memory.cpp +++ b/sc-memory/sc-memory/sc_memory.cpp @@ -31,18 +31,22 @@ extern "C" namespace { - GMutex gContextMutex; struct ContextMutexLock { - ContextMutexLock() { g_mutex_lock(&gContextMutex); } - ~ContextMutexLock() { g_mutex_unlock(&gContextMutex); } + ContextMutexLock() + { + g_mutex_lock(&gContextMutex); + } + ~ContextMutexLock() + { + g_mutex_unlock(&gContextMutex); + } }; bool gIsLogMuted = false; -void _logPrintHandler(gchar const * log_domain, GLogLevelFlags log_level, - gchar const * message, gpointer user_data) +void _logPrintHandler(gchar const * log_domain, GLogLevelFlags log_level, gchar const * message, gpointer user_data) { if (gIsLogMuted) return; @@ -72,7 +76,7 @@ void _logPrintHandler(gchar const * log_domain, GLogLevelFlags log_level, unsigned int gContextGounter; -} // namespace +} // namespace // ------------------ @@ -248,7 +252,7 @@ ScAddr ScMemoryContext::CreateNode(ScType const & type) return ScAddr(sc_memory_node_new(m_context, *type)); } -ScAddr ScMemoryContext::CreateLink(ScType const & type/* = ScType::LinkConst */) +ScAddr ScMemoryContext::CreateLink(ScType const & type /* = ScType::LinkConst */) { SC_ASSERT(type == ScType::LinkConst || type == ScType::LinkVar, ()); SC_ASSERT(IsValid(), ()); @@ -302,7 +306,8 @@ ScAddr ScMemoryContext::GetEdgeTarget(ScAddr const & edgeAddr) const bool ScMemoryContext::GetEdgeInfo(ScAddr const & edgeAddr, ScAddr & outSourceAddr, ScAddr & outTargetAddr) const { SC_ASSERT(IsValid(), ()); - if (sc_memory_get_arc_info(m_context, *edgeAddr, &outSourceAddr.m_realAddr, &outTargetAddr.m_realAddr) != SC_RESULT_OK) + if (sc_memory_get_arc_info(m_context, *edgeAddr, &outSourceAddr.m_realAddr, &outTargetAddr.m_realAddr) != + SC_RESULT_OK) { outSourceAddr.Reset(); outTargetAddr.Reset(); @@ -373,13 +378,16 @@ bool ScMemoryContext::Save() return (sc_memory_save(m_context) == SC_RESULT_OK); } -bool ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScAddr & outAddr, ScType const & type/* = ScType()*/) +bool ScMemoryContext::HelperResolveSystemIdtf( + std::string const & sysIdtf, + ScAddr & outAddr, + ScType const & type /* = ScType()*/) { outAddr = HelperResolveSystemIdtf(sysIdtf, type); return outAddr.IsValid(); } -ScAddr ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScType const & type/* = ScType()*/) +ScAddr ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScType const & type /* = ScType()*/) { SC_ASSERT(IsValid(), ()); ScAddr resultAddr = HelperFindBySystemIdtf(sysIdtf); @@ -387,8 +395,7 @@ ScAddr ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScT { if (!type.IsNode()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, - "You should provide any of ScType::Node... value as a type"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You should provide any of ScType::Node... value as a type"); } resultAddr = CreateNode(type); @@ -401,7 +408,8 @@ ScAddr ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScT bool ScMemoryContext::HelperSetSystemIdtf(std::string const & sysIdtf, ScAddr const & addr) { SC_ASSERT(IsValid(), ()); - return (sc_helper_set_system_identifier(m_context, *addr, sysIdtf.c_str(), (sc_uint32)sysIdtf.size()) == SC_RESULT_OK); + return ( + sc_helper_set_system_identifier(m_context, *addr, sysIdtf.c_str(), (sc_uint32)sysIdtf.size()) == SC_RESULT_OK); } std::string ScMemoryContext::HelperGetSystemIdtf(ScAddr const & addr) @@ -439,18 +447,25 @@ bool ScMemoryContext::HelperCheckEdge(ScAddr const & begin, ScAddr end, ScType c bool ScMemoryContext::HelperFindBySystemIdtf(std::string const & sysIdtf, ScAddr & outAddr) { SC_ASSERT(IsValid(), ()); - return (sc_helper_find_element_by_system_identifier(m_context, sysIdtf.c_str(), (sc_uint32)sysIdtf.size(), &outAddr.m_realAddr) == SC_RESULT_OK); + return ( + sc_helper_find_element_by_system_identifier( + m_context, sysIdtf.c_str(), (sc_uint32)sysIdtf.size(), &outAddr.m_realAddr) == SC_RESULT_OK); } ScAddr ScMemoryContext::HelperFindBySystemIdtf(std::string const & sysIdtf) { ScAddr result; SC_ASSERT(IsValid(), ()); - sc_helper_find_element_by_system_identifier(m_context, sysIdtf.c_str(), (sc_uint32)sysIdtf.size(), &result.m_realAddr); + sc_helper_find_element_by_system_identifier( + m_context, sysIdtf.c_str(), (sc_uint32)sysIdtf.size(), &result.m_realAddr); return result; } -ScTemplate::Result ScMemoryContext::HelperGenTemplate(ScTemplate const & templ, ScTemplateGenResult & result, ScTemplateParams const & params, ScTemplateResultCode * resultCode) +ScTemplate::Result ScMemoryContext::HelperGenTemplate( + ScTemplate const & templ, + ScTemplateGenResult & result, + ScTemplateParams const & params, + ScTemplateResultCode * resultCode) { return templ.Generate(*this, result, params, resultCode); } @@ -460,15 +475,18 @@ ScTemplate::Result ScMemoryContext::HelperSearchTemplate(ScTemplate const & temp return templ.Search(*this, result); } -ScTemplate::Result ScMemoryContext::HelperSearchTemplateInStruct(ScTemplate const & templ, ScAddr const & scStruct, ScTemplateSearchResult & result) +ScTemplate::Result ScMemoryContext::HelperSearchTemplateInStruct( + ScTemplate const & templ, + ScAddr const & scStruct, + ScTemplateSearchResult & result) { return templ.SearchInStruct(*this, scStruct, result); } ScTemplate::Result ScMemoryContext::HelperBuildTemplate( - ScTemplate & templ, - ScAddr const & templAddr, - ScTemplateParams const & params) + ScTemplate & templ, + ScAddr const & templAddr, + ScTemplateParams const & params) { return templ.FromScTemplate(*this, templAddr, params); } diff --git a/sc-memory/sc-memory/sc_memory.hpp b/sc-memory/sc-memory/sc_memory.hpp index 5aed7faa45..b1babd6e2b 100644 --- a/sc-memory/sc-memory/sc_memory.hpp +++ b/sc-memory/sc-memory/sc_memory.hpp @@ -35,10 +35,11 @@ class ScMemory _SC_EXTERN static void LogMute(); _SC_EXTERN static void LogUnmute(); -protected: +protected: static void RegisterContext(ScMemoryContext const * ctx); static void UnregisterContext(ScMemoryContext const * ctx); + private: static bool HasMemoryContext(ScMemoryContext const * ctx); @@ -72,10 +73,16 @@ class ScMemoryContext // Disable object copying ScMemoryContext(ScMemoryContext const & other) = delete; - ScMemoryContext & operator = (ScMemoryContext const & other) = delete; + ScMemoryContext & operator=(ScMemoryContext const & other) = delete; - sc_memory_context const * operator * () const { return m_context; } - sc_memory_context const * GetRealContext() const { return m_context; } + sc_memory_context const * operator*() const + { + return m_context; + } + sc_memory_context const * GetRealContext() const + { + return m_context; + } //! Call this function, when you request to destroy real memory context, before destructor calls for this object _SC_EXTERN void Destroy(); @@ -87,7 +94,10 @@ class ScMemoryContext void EndEventsPending(); // returns copy, because of Python wrapper - std::string const & GetName() const { return m_name; } + std::string const & GetName() const + { + return m_name; + } _SC_EXTERN bool IsValid() const; @@ -108,8 +118,8 @@ class ScMemoryContext _SC_EXTERN ScType GetElementType(ScAddr const & addr) const; /*! Change subtype of sc-element. - * Return true, if there are no any errors; otherwise return false. - */ + * Return true, if there are no any errors; otherwise return false. + */ _SC_EXTERN bool SetElementSubtype(ScAddr const & addr, sc_type subtype); _SC_EXTERN ScAddr GetEdgeSource(ScAddr const & edgeAddr) const; @@ -128,7 +138,8 @@ class ScMemoryContext SC_DEPRECATED(0.6.0, "Use `ScAddrList FindLinksByContent(ScStreamPtr const & stream)` instead.") _SC_EXTERN bool FindLinksByContent(ScStreamPtr const & stream, ScAddrVector & found); _SC_EXTERN ScAddrVector FindLinksByContent(ScStreamPtr const & stream); - template ScAddrVector FindLinksByContent(TContentType const & value) + template + ScAddrVector FindLinksByContent(TContentType const & value) { return FindLinksByContent(ScStreamMakeRead(value)); } @@ -137,33 +148,33 @@ class ScMemoryContext _SC_EXTERN bool Save(); template - std::shared_ptr> Iterator5(ParamType1 const & param1, - ParamType2 const & param2, - ParamType3 const & param3, - ParamType4 const & param4, - ParamType5 const & param5) + std::shared_ptr> Iterator5( + ParamType1 const & param1, + ParamType2 const & param2, + ParamType3 const & param3, + ParamType4 const & param4, + ParamType5 const & param5) { return std::shared_ptr>( - new TIterator5(*this, param1, param2, param3, param4, param5)); + new TIterator5( + *this, param1, param2, param3, param4, param5)); } template - std::shared_ptr> Iterator3(ParamType1 const & param1, - ParamType2 const & param2, - ParamType3 const & param3) + std::shared_ptr> Iterator3( + ParamType1 const & param1, + ParamType2 const & param2, + ParamType3 const & param3) { return std::shared_ptr>( - new TIterator3(*this, param1, param2, param3)); + new TIterator3(*this, param1, param2, param3)); } /* Make iteration by triples, and call fn function for each result. * fn function should have 3 parameters (ScAddr const & source, ScAddr const & edge, ScAddr const & target) */ template - void ForEachIter3(ParamType1 const & param1, - ParamType2 const & param2, - ParamType3 const & param3, - FnT && fn) + void ForEachIter3(ParamType1 const & param1, ParamType2 const & param2, ParamType3 const & param3, FnT && fn) { ScIterator3Ptr it = Iterator3(param1, param2, param3); while (it->Next()) @@ -174,13 +185,20 @@ class ScMemoryContext * fn function should have 5 parameters * (ScAddr const & source, ScAddr const & edge, ScAddr const & target, ScAddr const & attrEdge, ScAddr const & attr) */ - template - void ForEachIter5(ParamType1 const & param1, - ParamType2 const & param2, - ParamType3 const & param3, - ParamType4 const & param4, - ParamType5 const & param5, - FnT && fn) + template < + typename ParamType1, + typename ParamType2, + typename ParamType3, + typename ParamType4, + typename ParamType5, + typename FnT> + void ForEachIter5( + ParamType1 const & param1, + ParamType2 const & param2, + ParamType3 const & param3, + ParamType4 const & param4, + ParamType5 const & param5, + FnT && fn) { ScIterator5Ptr it = Iterator5(param1, param2, param3, param4, param5); while (it->Next()) @@ -192,8 +210,13 @@ class ScMemoryContext * Look at type parameter as ForceCreate flag, that contains type. * Important: Type should be any of ScType::Node... */ - SC_DEPRECATED(0.4.0, "Use should use ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScType const & type)") - _SC_EXTERN bool HelperResolveSystemIdtf(std::string const & sysIdtf, ScAddr & outAddr, ScType const & type = ScType()); + SC_DEPRECATED( + 0.4.0, + "Use should use ScMemoryContext::HelperResolveSystemIdtf(std::string const & sysIdtf, ScType const & type)") + _SC_EXTERN bool HelperResolveSystemIdtf( + std::string const & sysIdtf, + ScAddr & outAddr, + ScType const & type = ScType()); _SC_EXTERN ScAddr HelperResolveSystemIdtf(std::string const & sysIdtf, ScType const & type = ScType()); _SC_EXTERN bool HelperSetSystemIdtf(std::string const & sysIdtf, ScAddr const & addr); @@ -207,10 +230,20 @@ class ScMemoryContext _SC_EXTERN bool HelperFindBySystemIdtf(std::string const & sysIdtf, ScAddr & outAddr); _SC_EXTERN ScAddr HelperFindBySystemIdtf(std::string const & sysIdtf); - _SC_EXTERN ScTemplate::Result HelperGenTemplate(ScTemplate const & templ, ScTemplateGenResult & result, ScTemplateParams const & params = ScTemplateParams::Empty, ScTemplateResultCode * resultCode = nullptr); + _SC_EXTERN ScTemplate::Result HelperGenTemplate( + ScTemplate const & templ, + ScTemplateGenResult & result, + ScTemplateParams const & params = ScTemplateParams::Empty, + ScTemplateResultCode * resultCode = nullptr); _SC_EXTERN ScTemplate::Result HelperSearchTemplate(ScTemplate const & templ, ScTemplateSearchResult & result); - _SC_EXTERN ScTemplate::Result HelperSearchTemplateInStruct(ScTemplate const & templ, ScAddr const & scStruct, ScTemplateSearchResult & result); - _SC_EXTERN ScTemplate::Result HelperBuildTemplate(ScTemplate & templ, ScAddr const & templAddr, const ScTemplateParams & params = ScTemplateParams()); + _SC_EXTERN ScTemplate::Result HelperSearchTemplateInStruct( + ScTemplate const & templ, + ScAddr const & scStruct, + ScTemplateSearchResult & result); + _SC_EXTERN ScTemplate::Result HelperBuildTemplate( + ScTemplate & templ, + ScAddr const & templAddr, + const ScTemplateParams & params = ScTemplateParams()); _SC_EXTERN ScTemplate::Result HelperBuildTemplate(ScTemplate & templ, std::string const & scsText); _SC_EXTERN Stat CalculateStat() const; @@ -237,4 +270,3 @@ class ScMemoryContextEventsPendingGuard private: ScMemoryContext & m_ctx; }; - diff --git a/sc-memory/sc-memory/sc_module.cpp b/sc-memory/sc-memory/sc_module.cpp index 31b7f63a55..071bad1b84 100644 --- a/sc-memory/sc-memory/sc_module.cpp +++ b/sc-memory/sc-memory/sc_module.cpp @@ -5,5 +5,3 @@ */ #include "sc_module.hpp" - - diff --git a/sc-memory/sc-memory/sc_object.cpp b/sc-memory/sc-memory/sc_object.cpp index 39155ecc77..3dda6413e2 100644 --- a/sc-memory/sc-memory/sc_object.cpp +++ b/sc-memory/sc-memory/sc_object.cpp @@ -6,7 +6,6 @@ #include "sc_object.hpp" - ScObject::ScObject() : m_isInitialized(false) , m_initResult(false) @@ -15,15 +14,13 @@ ScObject::ScObject() ScObject::~ScObject() { - } ScObject::ScObject(ScObject const & other) { - } -ScObject & ScObject::operator = (ScObject const & other) +ScObject & ScObject::operator=(ScObject const & other) { return *this; } diff --git a/sc-memory/sc-memory/sc_object.hpp b/sc-memory/sc-memory/sc_object.hpp index 45dced8378..f4e0932f2b 100644 --- a/sc-memory/sc-memory/sc_object.hpp +++ b/sc-memory/sc-memory/sc_object.hpp @@ -15,13 +15,12 @@ */ class _SC_EXTERN ScObject { - protected: explicit ScObject(); virtual ~ScObject(); ScObject(ScObject const & other); - ScObject & operator = (ScObject const & other); + ScObject & operator=(ScObject const & other); public: /// TODO: Need mechanism to call that function automaticaly after object construction @@ -29,8 +28,8 @@ class _SC_EXTERN ScObject private: /** This method override genarates by code generator, and initialize all - * meta data for this object. It calls from ScObject constructors - */ + * meta data for this object. It calls from ScObject constructors + */ virtual bool _InitInternal() = 0; private: diff --git a/sc-memory/sc-memory/sc_platform.hpp b/sc-memory/sc-memory/sc_platform.hpp index 7b4a9cd855..78a50bf2fe 100644 --- a/sc-memory/sc-memory/sc_platform.hpp +++ b/sc-memory/sc-memory/sc_platform.hpp @@ -7,4 +7,3 @@ #pragma once #include "sc-core/sc-store/sc_platform.h" - diff --git a/sc-memory/sc-memory/sc_scs_helper.cpp b/sc-memory/sc-memory/sc_scs_helper.cpp index f968087b3a..98f5e002a5 100644 --- a/sc-memory/sc-memory/sc_scs_helper.cpp +++ b/sc-memory/sc-memory/sc_scs_helper.cpp @@ -16,7 +16,6 @@ namespace impl { - class StructGenerator { friend class ::SCsHelper; @@ -30,17 +29,18 @@ class StructGenerator SC_ASSERT(m_kNrelSCsGlobalIdtf.IsValid(), ()); } - void operator() (scs::Parser const & parser) + void operator()(scs::Parser const & parser) { - // generate aliases - auto const & aliases = parser.GetAliases(); - for (auto const & it : aliases) { - const auto & parsedElement = parser.GetParsedElement(it.second); - if (!parsedElement.GetType().IsEdge()) - { - ResolveElement(parsedElement); - } + // generate aliases + auto const & aliases = parser.GetAliases(); + for (auto const & it : aliases) + { + const auto & parsedElement = parser.GetParsedElement(it.second); + if (!parsedElement.GetType().IsEdge()) + { + ResolveElement(parsedElement); } + } // generate triples auto const & triples = parser.GetParsedTriples(); @@ -56,8 +56,7 @@ class StructGenerator SC_ASSERT(srcAddr.IsValid() && trgAddr.IsValid(), ()); if (!edge.GetType().IsEdge()) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Edge in triple has incorrect type"); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "Edge in triple has incorrect type"); } ScAddr const edgeAddr = m_ctx.CreateEdge(edge.GetType(), srcAddr, trgAddr); @@ -65,10 +64,8 @@ class StructGenerator m_idtfCache.insert(std::make_pair(edge.GetIdtf(), edgeAddr)); } - parser.ForEachParsedElement([this](scs::ParsedElement const & el) - { - if (m_idtfCache.find(el.GetIdtf()) == m_idtfCache.end() && - !el.GetType().IsEdge() && + parser.ForEachParsedElement([this](scs::ParsedElement const & el) { + if (m_idtfCache.find(el.GetIdtf()) == m_idtfCache.end() && !el.GetType().IsEdge() && !scs::TypeResolver::IsKeynodeType(el.GetIdtf())) { ResolveElement(el); @@ -77,7 +74,6 @@ class StructGenerator } private: - void SetSCsGlobalIdtf(std::string const & idtf, ScAddr const & addr) { SC_ASSERT(m_kNrelSCsGlobalIdtf.IsValid(), ()); @@ -88,8 +84,6 @@ class StructGenerator ScLink link(m_ctx, linkAddr); link.Set(idtf); - - ScAddr const edgeAddr = m_ctx.CreateEdge(ScType::EdgeDCommonConst, addr, linkAddr); m_ctx.CreateEdge(ScType::EdgeAccessConstPosPerm, m_kNrelSCsGlobalIdtf, edgeAddr); } @@ -106,19 +100,15 @@ class StructGenerator ScTemplate templ; templ.TripleWithRelation( - ScType::Unknown >> "_el", - ScType::EdgeDCommonVar, - addr, - ScType::EdgeAccessVarPosPerm, - m_kNrelSCsGlobalIdtf); + ScType::Unknown >> "_el", ScType::EdgeDCommonVar, addr, ScType::EdgeAccessVarPosPerm, m_kNrelSCsGlobalIdtf); ScTemplateSearchResult searchResult; if (m_ctx.HelperSearchTemplate(templ, searchResult)) { if (result.IsValid() || searchResult.Size() > 1) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "There are more then 1 element with global identifier: " << idtf); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidState, "There are more then 1 element with global identifier: " << idtf); } result = searchResult[0]["_el"]; @@ -203,7 +193,8 @@ class StructGenerator return result; } - template bool SetLinkContentT(ScAddr const & linkAddr, std::string const & value) + template + bool SetLinkContentT(ScAddr const & linkAddr, std::string const & value) { T number; auto const result = utils::StringUtils::ParseNumber(value, number); @@ -232,7 +223,8 @@ class StructGenerator else { // chekc if it's a number format - std::regex const rNumber("^\\^\"(int8|int16|int32|int64|uint8|uint16|uint32|uint64|float|double)\\s*:\\s*([0-9]+|[0-9]+[.][0-9]+)\"$"); + std::regex const rNumber( + "^\\^\"(int8|int16|int32|int64|uint8|uint16|uint32|uint64|float|double)\\s*:\\s*([0-9]+|[0-9]+[.][0-9]+)\"$"); std::smatch result; if (std::regex_match(el.GetValue(), result, rNumber)) { @@ -264,14 +256,12 @@ class StructGenerator result = SetLinkContentT(linkAddr, value); else { - SC_THROW_EXCEPTION(utils::ExceptionInvalidType, - "Unsupported link binary type: " + type); + SC_THROW_EXCEPTION(utils::ExceptionInvalidType, "Unsupported link binary type: " + type); } if (!result) { - SC_THROW_EXCEPTION(utils::ExceptionInvalidState, - "Can't parse value from: " + el.GetValue()); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't parse value from: " + el.GetValue()); } } else @@ -290,7 +280,7 @@ class StructGenerator ScAddr m_kNrelSCsGlobalIdtf; }; -} // namespace impl +} // namespace impl SCsHelper::SCsHelper(ScMemoryContext & ctx, SCsFileInterfacePtr const & fileInterface) : m_ctx(ctx) diff --git a/sc-memory/sc-memory/sc_stream.cpp b/sc-memory/sc-memory/sc_stream.cpp index fb21cdb0fe..fc20c9fb95 100644 --- a/sc-memory/sc-memory/sc_stream.cpp +++ b/sc-memory/sc-memory/sc_stream.cpp @@ -6,7 +6,6 @@ #include "sc_stream.hpp" - ScStream::ScStream() : m_stream(0) { @@ -108,7 +107,7 @@ bool ScStream::HasFlag(sc_uint8 flag) // --------------- ScStreamMemory::ScStreamMemory(MemoryBufferPtr const & buff) - : ScStream (static_cast(buff->Data()), sc_uint(buff->Size()), SC_STREAM_FLAG_READ) + : ScStream(static_cast(buff->Data()), sc_uint(buff->Size()), SC_STREAM_FLAG_READ) , m_buffer(buff) { } @@ -129,10 +128,9 @@ bool ScStreamConverter::StreamToString(ScStreamPtr const & stream, std::string & if (stream->Read(data, bytesCount, readBytes) && (readBytes == bytesCount)) outString.assign(data, data + bytesCount); - delete []data; + delete[] data; return true; - } ScStreamPtr ScStreamConverter::StreamFromString(std::string const & str) diff --git a/sc-memory/sc-memory/sc_stream.hpp b/sc-memory/sc-memory/sc_stream.hpp index 1f452a4baa..307d155922 100644 --- a/sc-memory/sc-memory/sc_stream.hpp +++ b/sc-memory/sc-memory/sc_stream.hpp @@ -20,7 +20,7 @@ class ScStream friend class ScMemoryContext; ScStream(ScStream const & other) = delete; - ScStream & operator = (ScStream const & other) = delete; + ScStream & operator=(ScStream const & other) = delete; public: _SC_EXTERN explicit ScStream(); @@ -53,7 +53,7 @@ class ScStream bool ReadType(Type & value) { size_t readBytes = 0; - return Read((sc_char*)&value, sizeof(Type), readBytes) && (readBytes == sizeof(Type)); + return Read((sc_char *)&value, sizeof(Type), readBytes) && (readBytes == sizeof(Type)); } protected: @@ -72,11 +72,9 @@ class ScStreamMemory : public ScStream MemoryBufferPtr m_buffer; }; - class ScStreamConverter { - public: - +public: static _SC_EXTERN bool StreamToString(ScStreamPtr const & stream, std::string & outString); static _SC_EXTERN ScStreamPtr StreamFromString(std::string const & str); }; @@ -84,19 +82,53 @@ class ScStreamConverter template inline ScStreamPtr ScStreamMakeReadT(T const & value) { - static_assert (std::is_arithmetic::value, "Just simple arithmetic types are supported"); - return std::make_shared((sc_char*)&value, sizeof(T), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK | SC_STREAM_FLAG_TELL); + static_assert(std::is_arithmetic::value, "Just simple arithmetic types are supported"); + return std::make_shared( + (sc_char *)&value, sizeof(T), SC_STREAM_FLAG_READ | SC_STREAM_FLAG_SEEK | SC_STREAM_FLAG_TELL); } // TODO: implement with enable_if -inline ScStreamPtr ScStreamMakeRead(std::string const & value) { return ScStreamConverter::StreamFromString(value); } -inline ScStreamPtr ScStreamMakeRead(uint8_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(uint16_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(uint32_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(uint64_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(int8_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(int16_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(int32_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(int64_t const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(float const & value) { return ScStreamMakeReadT(value); } -inline ScStreamPtr ScStreamMakeRead(double const & value) { return ScStreamMakeReadT(value); } +inline ScStreamPtr ScStreamMakeRead(std::string const & value) +{ + return ScStreamConverter::StreamFromString(value); +} +inline ScStreamPtr ScStreamMakeRead(uint8_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(uint16_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(uint32_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(uint64_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(int8_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(int16_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(int32_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(int64_t const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(float const & value) +{ + return ScStreamMakeReadT(value); +} +inline ScStreamPtr ScStreamMakeRead(double const & value) +{ + return ScStreamMakeReadT(value); +} diff --git a/sc-memory/sc-memory/sc_struct.cpp b/sc-memory/sc-memory/sc_struct.cpp index 68381c31ae..25499a95e0 100644 --- a/sc-memory/sc-memory/sc_struct.cpp +++ b/sc-memory/sc-memory/sc_struct.cpp @@ -59,13 +59,13 @@ bool ScSet::HasElement(ScAddr const & elAddr) const return m_context.HelperCheckEdge(m_addr, elAddr, ScType::EdgeAccessConstPosPerm); } -ScSet & ScSet::operator << (ScAddr const & elAddr) +ScSet & ScSet::operator<<(ScAddr const & elAddr) { Append(elAddr); return *this; } -ScSet & ScSet::operator << (ScTemplateGenResult const & res) +ScSet & ScSet::operator<<(ScTemplateGenResult const & res) { size_t const res_num = res.Size(); for (size_t i = 0; i < res_num; ++i) @@ -74,13 +74,13 @@ ScSet & ScSet::operator << (ScTemplateGenResult const & res) return *this; } -ScSet & ScSet::operator >> (ScAddr const & elAddr) +ScSet & ScSet::operator>>(ScAddr const & elAddr) { Remove(elAddr); return *this; } -ScAddr const & ScSet::operator * () const +ScAddr const & ScSet::operator*() const { return m_addr; } diff --git a/sc-memory/sc-memory/sc_struct.hpp b/sc-memory/sc-memory/sc_struct.hpp index 2b8e943312..15748bf316 100644 --- a/sc-memory/sc-memory/sc_struct.hpp +++ b/sc-memory/sc-memory/sc_struct.hpp @@ -14,7 +14,8 @@ class ScSet public: _SC_EXTERN ScSet(class ScMemoryContext & ctx, ScAddr const & setAddr); - /* Append element into sc-set. If element already exist, then doesn't append it and return false; otherwise returns true. */ + /* Append element into sc-set. If element already exist, then doesn't append it and return false; otherwise returns + * true. */ _SC_EXTERN bool Append(ScAddr const & elAddr); _SC_EXTERN bool Append(ScAddr const & elAddr, ScAddr const & attrAddr); @@ -22,16 +23,16 @@ class ScSet _SC_EXTERN bool Remove(ScAddr const & elAddr); /* Operator equal to append */ - _SC_EXTERN ScSet & operator << (ScAddr const & elAddr); - _SC_EXTERN ScSet & operator << (class ScTemplateGenResult const & res); + _SC_EXTERN ScSet & operator<<(ScAddr const & elAddr); + _SC_EXTERN ScSet & operator<<(class ScTemplateGenResult const & res); /* Operator equal to remove */ - _SC_EXTERN ScSet & operator >> (ScAddr const & elAddr); + _SC_EXTERN ScSet & operator>>(ScAddr const & elAddr); /* Check if specified element exist in set */ _SC_EXTERN bool HasElement(ScAddr const & elAddr) const; - _SC_EXTERN ScAddr const & operator * () const; + _SC_EXTERN ScAddr const & operator*() const; /* Check if set has no elements */ _SC_EXTERN bool IsEmpty() const; @@ -49,5 +50,5 @@ class ScStruct : public ScSet : ScSet(ctx, structAddr) { // TODO: check type of struct element - } + } }; diff --git a/sc-memory/sc-memory/sc_template.cpp b/sc-memory/sc-memory/sc_template.cpp index c822dd1279..c471434dd0 100644 --- a/sc-memory/sc-memory/sc_template.cpp +++ b/sc-memory/sc-memory/sc_template.cpp @@ -9,22 +9,22 @@ #include -ScTemplateItemValue operator >> (ScAddr const & value, char const * replName) +ScTemplateItemValue operator>>(ScAddr const & value, char const * replName) { return ScTemplateItemValue(value, replName); } -ScTemplateItemValue operator >> (ScAddr const & value, std::string const & replName) +ScTemplateItemValue operator>>(ScAddr const & value, std::string const & replName) { return ScTemplateItemValue(value, replName.c_str()); } -ScTemplateItemValue operator >> (ScType const & value, char const * replName) +ScTemplateItemValue operator>>(ScType const & value, char const * replName) { return ScTemplateItemValue(value, replName); } -ScTemplateItemValue operator >> (ScType const & value, std::string const & replName) +ScTemplateItemValue operator>>(ScType const & value, std::string const & replName) { return ScTemplateItemValue(value, replName.c_str()); } @@ -39,13 +39,20 @@ ScTemplate::ScTemplate(bool forceOrder /* = false */) m_constructions.reserve(16); } -ScTemplate & ScTemplate::operator() (ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3) +ScTemplate & ScTemplate::operator()( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3) { return Triple(param1, param2, param3); } -ScTemplate & ScTemplate::operator() (ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3, - ScTemplateItemValue const & param4, ScTemplateItemValue const & param5) +ScTemplate & ScTemplate::operator()( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3, + ScTemplateItemValue const & param4, + ScTemplateItemValue const & param5) { return TripleWithRelation(param1, param2, param3, param4, param5); } @@ -74,9 +81,10 @@ bool ScTemplate::HasReplacement(std::string const & repl) const return (m_replacements.find(repl) != m_replacements.end()); } -ScTemplate & ScTemplate::Triple(ScTemplateItemValue const & param1, - ScTemplateItemValue const & param2, - ScTemplateItemValue const & param3) +ScTemplate & ScTemplate::Triple( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3) { size_t const replPos = m_constructions.size() * 3; m_constructions.emplace_back(ScTemplateConstr3(param1, param2, param3, m_constructions.size())); @@ -97,8 +105,7 @@ ScTemplate & ScTemplate::Triple(ScTemplateItemValue const & param1, SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You should to use variable types in template"); } - if ((value.m_itemType == ScTemplateItemValue::Type::Addr) && - !value.m_addrValue.IsValid()) + if ((value.m_itemType == ScTemplateItemValue::Type::Addr) && !value.m_addrValue.IsValid()) { SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You can't use empty ScAddr"); } @@ -112,8 +119,8 @@ ScTemplate & ScTemplate::Triple(ScTemplateItemValue const & param1, } /* Store type there, if replacement for any type. - * That allows to use it before original type will processed - */ + * That allows to use it before original type will processed + */ size_t const constrIdx = replPos / 3; SC_ASSERT(constrIdx < m_constructions.size(), ()); ScTemplateItemValue const & valueType = m_constructions[constrIdx].m_values[i]; @@ -128,9 +135,12 @@ ScTemplate & ScTemplate::Triple(ScTemplateItemValue const & param1, return *this; } -ScTemplate & ScTemplate::TripleWithRelation(ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, - ScTemplateItemValue const & param3, ScTemplateItemValue const & param4, - ScTemplateItemValue const & param5) +ScTemplate & ScTemplate::TripleWithRelation( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3, + ScTemplateItemValue const & param4, + ScTemplateItemValue const & param5) { size_t const replPos = m_constructions.size() * 3; diff --git a/sc-memory/sc-memory/sc_template.hpp b/sc-memory/sc-memory/sc_template.hpp index 6832c20b64..c6433f24b1 100644 --- a/sc-memory/sc-memory/sc_template.hpp +++ b/sc-memory/sc-memory/sc_template.hpp @@ -10,7 +10,6 @@ #include "sc_type.hpp" #include "sc_utils.hpp" - #define SC_REPL(x) (char const *)(x) struct ScTemplateItemValue @@ -123,13 +122,15 @@ struct ScTemplateItemValue class ScTemplateConstr3 { friend class ScTemplate; + public: using ItemsArray = std::array; - ScTemplateConstr3(ScTemplateItemValue const & param1, - ScTemplateItemValue const & param2, - ScTemplateItemValue const & param3, - size_t idx) + ScTemplateConstr3( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3, + size_t idx) : m_index(idx) { m_values[0] = param1; @@ -183,10 +184,10 @@ class ScTemplateConstr3 size_t m_index; }; -_SC_EXTERN ScTemplateItemValue operator >> (ScAddr const & value, char const * replName); -_SC_EXTERN ScTemplateItemValue operator >> (ScAddr const & value, std::string const & replName); -_SC_EXTERN ScTemplateItemValue operator >> (ScType const & value, char const * replName); -_SC_EXTERN ScTemplateItemValue operator >> (ScType const & value, std::string const & replName); +_SC_EXTERN ScTemplateItemValue operator>>(ScAddr const & value, char const * replName); +_SC_EXTERN ScTemplateItemValue operator>>(ScAddr const & value, std::string const & replName); +_SC_EXTERN ScTemplateItemValue operator>>(ScType const & value, char const * replName); +_SC_EXTERN ScTemplateItemValue operator>>(ScType const & value, std::string const & replName); class ScTemplateGenResult; class ScTemplateSearchResult; @@ -206,7 +207,7 @@ class ScTemplateParams friend class ScTemplateGenerator; public: - ScTemplateParams & operator = (ScTemplateParams const & other) = delete; + ScTemplateParams & operator=(ScTemplateParams const & other) = delete; explicit ScTemplateParams() { @@ -264,7 +265,6 @@ class ScTemplate final friend class ScTemplateBuilderFromScs; public: - class Result { public: @@ -289,10 +289,9 @@ class ScTemplate final std::string m_msg; }; - public: ScTemplate(ScTemplate const & other) = delete; - ScTemplate & operator = (ScTemplate const & other) = delete; + ScTemplate & operator=(ScTemplate const & other) = delete; using ReplacementsMap = std::map; using TemplateConstr3Vector = std::vector; @@ -303,10 +302,17 @@ class ScTemplate final */ _SC_EXTERN explicit ScTemplate(bool forceOrder = false); - _SC_EXTERN ScTemplate & operator() (ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3); + _SC_EXTERN ScTemplate & operator()( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3); - _SC_EXTERN ScTemplate & operator() (ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3, - ScTemplateItemValue const & param4, ScTemplateItemValue const & param5); + _SC_EXTERN ScTemplate & operator()( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3, + ScTemplateItemValue const & param4, + ScTemplateItemValue const & param5); _SC_EXTERN void Clear(); _SC_EXTERN bool IsEmpty() const; @@ -316,33 +322,47 @@ class ScTemplate final _SC_EXTERN bool HasReplacement(std::string const & repl) const; /** Add construction: - * param2 - * param1 ----------> param3 - */ - _SC_EXTERN ScTemplate & Triple(ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3); + * param2 + * param1 ----------> param3 + */ + _SC_EXTERN ScTemplate & Triple( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3); /** Adds template: - * param2 - * param1 ---------> param3 - * ^ - * | - * | param4 - * | - * param5 - * Equal to two calls of triple, so this template add 6 items to result (NOT 5), to minimize - * possible abuse, use result name mapping, and get result by names - */ - _SC_EXTERN ScTemplate & TripleWithRelation(ScTemplateItemValue const & param1, ScTemplateItemValue const & param2, ScTemplateItemValue const & param3, - ScTemplateItemValue const & param4, ScTemplateItemValue const & param5); + * param2 + * param1 ---------> param3 + * ^ + * | + * | param4 + * | + * param5 + * Equal to two calls of triple, so this template add 6 items to result (NOT 5), to minimize + * possible abuse, use result name mapping, and get result by names + */ + _SC_EXTERN ScTemplate & TripleWithRelation( + ScTemplateItemValue const & param1, + ScTemplateItemValue const & param2, + ScTemplateItemValue const & param3, + ScTemplateItemValue const & param4, + ScTemplateItemValue const & param5); protected: // Begin: calls by memory context - Result Generate(ScMemoryContext & ctx, ScTemplateGenResult & result, ScTemplateParams const & params, ScTemplateResultCode * errorCode = nullptr) const; + Result Generate( + ScMemoryContext & ctx, + ScTemplateGenResult & result, + ScTemplateParams const & params, + ScTemplateResultCode * errorCode = nullptr) const; Result Search(ScMemoryContext & ctx, ScTemplateSearchResult & result) const; Result SearchInStruct(ScMemoryContext & ctx, ScAddr const & scStruct, ScTemplateSearchResult & result) const; // Builds template based on template in sc-memory - Result FromScTemplate(ScMemoryContext & ctx, ScAddr const & scTemplateAddr, const ScTemplateParams & params = ScTemplateParams()); + Result FromScTemplate( + ScMemoryContext & ctx, + ScAddr const & scTemplateAddr, + const ScTemplateParams & params = ScTemplateParams()); Result FromScs(ScMemoryContext & ctx, std::string const & scsText); // End: calls by memory context @@ -371,20 +391,19 @@ class ScTemplate final */ mutable bool m_isSearchCacheValid : 1; mutable ProcessOrder m_searchCachedOrder; - }; - - class ScTemplateGenResult { friend class ScTemplateGenerator; friend class ScSet; public: - ScTemplateGenResult() { } + ScTemplateGenResult() + { + } - ScAddr const & operator [] (std::string const & name) const + ScAddr const & operator[](std::string const & name) const { auto const it = m_replacements.find(name); if (it != m_replacements.end()) @@ -414,7 +433,7 @@ class ScTemplateGenResult return m_result.size(); } - ScAddr const & operator[] (size_t index) + ScAddr const & operator[](size_t index) { SC_ASSERT(index < Size(), ()); return m_result[index]; @@ -443,7 +462,7 @@ class ScTemplateSearchResultItem { } - inline ScAddr const & operator[] (std::string const & name) const + inline ScAddr const & operator[](std::string const & name) const { auto const it = m_replacements->find(name); SC_ASSERT(it != m_replacements->end(), ()); @@ -451,13 +470,13 @@ class ScTemplateSearchResultItem return (*m_results)[it->second]; } - inline ScAddr const & operator[] (size_t index) const + inline ScAddr const & operator[](size_t index) const { SC_ASSERT(index < Size(), ()); return (*m_results)[index]; } - inline bool Has(std::string const& name) const + inline bool Has(std::string const & name) const { return (m_replacements->find(name) != m_replacements->end()); } @@ -468,7 +487,6 @@ class ScTemplateSearchResultItem return m_results->size(); } - protected: ScAddrVector const * m_results; ScTemplate::ReplacementsMap const * m_replacements; @@ -479,7 +497,10 @@ class ScTemplateSearchResult friend class ScTemplateSearch; public: - inline size_t Size() const { return m_results.size(); } + inline size_t Size() const + { + return m_results.size(); + } inline bool IsEmpty() const { @@ -498,7 +519,7 @@ class ScTemplateSearchResult return false; } - inline ScTemplateSearchResultItem operator [] (size_t idx) const + inline ScTemplateSearchResultItem operator[](size_t idx) const { SC_ASSERT(idx < m_results.size(), ()); return ScTemplateSearchResultItem(&(m_results[idx]), &m_replacements); diff --git a/sc-memory/sc-memory/sc_template_build.cpp b/sc-memory/sc-memory/sc_template_build.cpp index ea42688ff3..8a178f8581 100644 --- a/sc-memory/sc-memory/sc_template_build.cpp +++ b/sc-memory/sc-memory/sc_template_build.cpp @@ -13,7 +13,6 @@ namespace { - class ObjectInfo { public: @@ -85,7 +84,7 @@ class ObjectInfo ScAddr::HashType m_trgHash; }; -} +} // namespace class ScTemplateBuilder { @@ -95,17 +94,14 @@ class ScTemplateBuilder using ScAddrHashVector = std::vector; protected: - ScTemplateBuilder( - ScAddr const & inScTemplateAddr, - ScMemoryContext & inCtx, - ScTemplateParams const & params) + ScTemplateBuilder(ScAddr const & inScTemplateAddr, ScMemoryContext & inCtx, ScTemplateParams const & params) : m_templateAddr(inScTemplateAddr) , m_context(inCtx) , m_params(params) { } - ScTemplate::Result operator() (ScTemplate * inTemplate) + ScTemplate::Result operator()(ScTemplate * inTemplate) { // mark template to don't force order of triples inTemplate->m_isForceOrder = false; @@ -115,10 +111,7 @@ class ScTemplateBuilder independentEdges.reserve(512); size_t index = 0; - ScIterator3Ptr iter = m_context.Iterator3( - m_templateAddr, - *ScType::EdgeAccessConstPosPerm, - *ScType()); + ScIterator3Ptr iter = m_context.Iterator3(m_templateAddr, *ScType::EdgeAccessConstPosPerm, *ScType()); // define edges set and independent edges set while (iter->Next()) @@ -127,7 +120,7 @@ class ScTemplateBuilder ObjectInfo obj = CollectObjectInfo(objAddr, "..obj_" + std::to_string(index++)); if (obj.IsUnknown()) - return ScTemplate::Result(false, "Can't determine type of ScElement"); // template corrupted + return ScTemplate::Result(false, "Can't determine type of ScElement"); // template corrupted ScAddr objSrc, objTrg; if (obj.IsEdge() && m_context.GetEdgeInfo(objAddr, objSrc, objTrg)) @@ -135,8 +128,7 @@ class ScTemplateBuilder obj.SetSourceHash(objSrc.Hash()); obj.SetTargetHash(objTrg.Hash()); - ScType const srcType = m_context.GetElementType(objSrc), - trgType = m_context.GetElementType(objTrg); + ScType const srcType = m_context.GetElementType(objSrc), trgType = m_context.GetElementType(objTrg); if (!srcType.IsEdge() && !trgType.IsEdge()) { auto const & it = std::find(independentEdges.begin(), independentEdges.end(), obj.GetHash()); @@ -173,17 +165,13 @@ class ScTemplateBuilder ObjectInfo const src = ReplaceWithParam(&m_elements.at(edge.GetSourceHash())); ObjectInfo const trg = ReplaceWithParam(&m_elements.at(edge.GetTargetHash())); - auto const & param = [&inTemplate](ObjectInfo const & obj) -> ScTemplateItemValue - { + auto const & param = [&inTemplate](ObjectInfo const & obj) -> ScTemplateItemValue { return obj.GetType().IsConst() - ? obj.GetAddr() >> obj.GetIdtf() - : (inTemplate->HasReplacement(obj.GetIdtf()) ? obj.GetIdtf() : obj.GetType() >> obj.GetIdtf()); + ? obj.GetAddr() >> obj.GetIdtf() + : (inTemplate->HasReplacement(obj.GetIdtf()) ? obj.GetIdtf() : obj.GetType() >> obj.GetIdtf()); }; - inTemplate->Triple( - param(src), - edge.GetType() >> edge.GetIdtf(), - param(trg)); + inTemplate->Triple(param(src), edge.GetType() >> edge.GetIdtf(), param(trg)); } return ScTemplate::Result(true); @@ -227,7 +215,8 @@ class ScTemplateBuilder } auto const & equalDependentEdges = powerDependentEdges.at(power); - auto const & equalDependentEdgesIt = std::find(equalDependentEdges.begin(), equalDependentEdges.end(), hPair.first); + auto const & equalDependentEdgesIt = + std::find(equalDependentEdges.begin(), equalDependentEdges.end(), hPair.first); if (equalDependentEdgesIt == equalDependentEdges.end()) powerDependentEdges.at(power).emplace_back(hPair.first); } @@ -253,8 +242,11 @@ class ScTemplateBuilder } // count edge dependence power from other edge - inline size_t DefineEdgeDependencePower(ScAddr::HashType const & edge, ScAddr::HashType const & otherEdge, - size_t & max, size_t power) const + inline size_t DefineEdgeDependencePower( + ScAddr::HashType const & edge, + ScAddr::HashType const & otherEdge, + size_t & max, + size_t power) const { auto const range = m_edgeDependenceMap.equal_range(edge); for (auto it = range.first; it != range.second; ++it) @@ -268,7 +260,10 @@ class ScTemplateBuilder } }; -ScTemplate::Result ScTemplate::FromScTemplate(ScMemoryContext & ctx, ScAddr const & scTemplateAddr, const ScTemplateParams & params) +ScTemplate::Result ScTemplate::FromScTemplate( + ScMemoryContext & ctx, + ScAddr const & scTemplateAddr, + const ScTemplateParams & params) { ScTemplateBuilder builder(scTemplateAddr, ctx, params); return builder(this); diff --git a/sc-memory/sc-memory/sc_template_gen.cpp b/sc-memory/sc-memory/sc_template_gen.cpp index 9a90d4d0fd..cb08d2e196 100644 --- a/sc-memory/sc-memory/sc_template_gen.cpp +++ b/sc-memory/sc-memory/sc_template_gen.cpp @@ -14,10 +14,11 @@ const ScTemplateParams ScTemplateParams::Empty; class ScTemplateGenerator { public: - ScTemplateGenerator(ScTemplate::ReplacementsMap const & replacements, - ScTemplate::TemplateConstr3Vector const & constructions, - ScTemplateParams const & params, - ScMemoryContext & context) + ScTemplateGenerator( + ScTemplate::ReplacementsMap const & replacements, + ScTemplate::TemplateConstr3Vector const & constructions, + ScTemplateParams const & params, + ScMemoryContext & context) : m_replacements(replacements) , m_constructions(constructions) , m_params(params) @@ -28,12 +29,13 @@ class ScTemplateGenerator { auto values = constr.GetValues(); if (values[1].IsFixed()) - SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You can't use fixed value for edge in triple for template generation"); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidParams, "You can't use fixed value for edge in triple for template generation"); - auto checkEdge = [](ScTemplateItemValue const & value) - { + auto checkEdge = [](ScTemplateItemValue const & value) { if (value.IsAssign() && (!value.IsType() || value.m_typeValue.IsEdge())) - SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "You can't use edges as a source/target element in triple for generation"); + SC_THROW_EXCEPTION( + utils::ExceptionInvalidParams, "You can't use edges as a source/target element in triple for generation"); }; checkEdge(values[0]); @@ -41,10 +43,10 @@ class ScTemplateGenerator } } - ScTemplateResultCode operator() (ScTemplateGenResult & result) + ScTemplateResultCode operator()(ScTemplateGenResult & result) { if (!checkParams()) - return ScTemplateResultCode::InvalidParams; /// TODO: Provide error + return ScTemplateResultCode::InvalidParams; /// TODO: Provide error ScMemoryContextEventsPendingGuard guard(m_context); @@ -184,8 +186,11 @@ class ScTemplateGenerator ScAddrVector m_createdElements; }; - -ScTemplate::Result ScTemplate::Generate(ScMemoryContext & ctx, ScTemplateGenResult & result, ScTemplateParams const & params, ScTemplateResultCode * errorCode) const +ScTemplate::Result ScTemplate::Generate( + ScMemoryContext & ctx, + ScTemplateGenResult & result, + ScTemplateParams const & params, + ScTemplateResultCode * errorCode) const { ScTemplateGenerator gen(m_replacements, m_constructions, params, ctx); ScTemplateResultCode resultCode = gen(result); @@ -195,4 +200,3 @@ ScTemplate::Result ScTemplate::Generate(ScMemoryContext & ctx, ScTemplateGenResu return ScTemplate::Result(resultCode == ScTemplateResultCode::Success); } - diff --git a/sc-memory/sc-memory/sc_template_scs.cpp b/sc-memory/sc-memory/sc_template_scs.cpp index 59a2358e39..29b8d98edf 100644 --- a/sc-memory/sc-memory/sc_template_scs.cpp +++ b/sc-memory/sc-memory/sc_template_scs.cpp @@ -22,7 +22,7 @@ class ScTemplateBuilderFromScs { } - ScTemplate::Result operator () (ScTemplate * templ) + ScTemplate::Result operator()(ScTemplate * templ) { // mark template to don't force order of triples templ->m_isForceOrder = false; @@ -41,8 +41,8 @@ class ScTemplateBuilderFromScs ScTemplate::Result result(true); - auto const MakeTemplItem = [&passed, &keynodes, &result](scs::ParsedElement const & el, ScTemplateItemValue & outValue) -> bool - { + auto const MakeTemplItem = [&passed, &keynodes, &result]( + scs::ParsedElement const & el, ScTemplateItemValue & outValue) -> bool { std::string const & idtf = el.GetIdtf(); bool const isUnnamed = scs::TypeResolver::IsUnnamed(idtf); bool const isPassed = (passed.find(idtf) != passed.end()); @@ -84,9 +84,7 @@ class ScTemplateBuilderFromScs ScTemplateItemValue srcItem, edgeItem, trgItem; - if (!MakeTemplItem(src, srcItem) || - !MakeTemplItem(edge, edgeItem) || - !MakeTemplItem(trg, trgItem)) + if (!MakeTemplItem(src, srcItem) || !MakeTemplItem(edge, edgeItem) || !MakeTemplItem(trg, trgItem)) { break; } diff --git a/sc-memory/sc-memory/sc_template_search.cpp b/sc-memory/sc-memory/sc_template_search.cpp index 80bb794521..2a73b4cca7 100644 --- a/sc-memory/sc-memory/sc_template_search.cpp +++ b/sc-memory/sc-memory/sc_template_search.cpp @@ -15,9 +15,7 @@ class ScTemplateSearch { public: - ScTemplateSearch(ScTemplate const & templ, - ScMemoryContext & context, - ScAddr const & scStruct) + ScTemplateSearch(ScTemplate const & templ, ScMemoryContext & context, ScAddr const & scStruct) : m_template(templ) , m_context(context) , m_struct(scStruct) @@ -44,22 +42,21 @@ class ScTemplateSearch static const size_t kScoreOther = 1; /** First of all we need to calculate scores for all triples - * (more scores - should be search first). - * Also need to store all replacements that need to be resolved - */ + * (more scores - should be search first). + * Also need to store all replacements that need to be resolved + */ std::vector tripleScores(m_template.m_constructions.size()); std::unordered_map> replDependMap; for (size_t i = 0; i < m_template.m_constructions.size(); ++i) { ScTemplateConstr3 const & triple = m_template.m_constructions[i]; - auto const CalculateScore = [](ScTemplateConstr3 const & constr) - { + auto const CalculateScore = [](ScTemplateConstr3 const & constr) { uint8_t score = 0; auto const & values = constr.GetValues(); if (values[1].IsAddr() && values[0].IsAssign() && values[2].IsAssign()) score += kScoreEdge; else if (values[0].IsAddr() && values[1].IsAssign() && values[2].IsAddr()) - score += kScoreOther * 2; // should be a sum of (f_a_a and a_a_f) + score += kScoreOther * 2; // should be a sum of (f_a_a and a_a_f) else if (values[0].IsAddr() || values[2].IsAddr()) score += kScoreOther; @@ -67,8 +64,7 @@ class ScTemplateSearch }; tripleScores[i] = CalculateScore(triple); // doesn't add edges into depend map - auto const TryAppendRepl = [&](ScTemplateItemValue const & value, size_t idx) - { + auto const TryAppendRepl = [&](ScTemplateItemValue const & value, size_t idx) { SC_ASSERT(idx < 3, ()); if (!value.IsAddr() && !value.m_replacementName.empty()) replDependMap[value.m_replacementName].push_back((i << 2) + idx); @@ -81,8 +77,7 @@ class ScTemplateSearch } // sort by scores - std::sort(preCache.begin(), preCache.end(), [&](size_t a, size_t b) - { + std::sort(preCache.begin(), preCache.end(), [&](size_t a, size_t b) { return (tripleScores[a] > tripleScores[b]); }); @@ -206,8 +201,7 @@ class ScTemplateSearch ScAddr const addr1 = ResolveAddr(value1); ScAddr const addr2 = ResolveAddr(value2); - auto const PrepareType = [](ScType const & type) - { + auto const PrepareType = [](ScType const & type) { if (type.HasConstancyFlag()) return type.UpConstType(); @@ -218,22 +212,22 @@ class ScTemplateSearch { if (!addr1.IsValid()) { - if (addr2.IsValid()) // F_A_F + if (addr2.IsValid()) // F_A_F { return m_context.Iterator3(addr0, PrepareType(value1.m_typeValue), addr2); } - else // F_A_A + else // F_A_A { return m_context.Iterator3(addr0, PrepareType(value1.m_typeValue), PrepareType(value2.m_typeValue)); } } else { - if (addr2.IsValid()) // F_F_F + if (addr2.IsValid()) // F_F_F { return m_context.Iterator3(addr0, addr1, addr2); } - else // F_F_A + else // F_F_A { return m_context.Iterator3(addr0, addr1, PrepareType(value2.m_typeValue)); } @@ -241,22 +235,22 @@ class ScTemplateSearch } else if (addr2.IsValid()) { - if (addr1.IsValid()) // A_F_F + if (addr1.IsValid()) // A_F_F { return m_context.Iterator3(PrepareType(value0.m_typeValue), addr1, addr2); } - else // A_A_F + else // A_A_F { return m_context.Iterator3(PrepareType(value0.m_typeValue), PrepareType(value1.m_typeValue), addr2); } } - else if (addr1.IsValid() && !addr2.IsValid()) // A_F_A + else if (addr1.IsValid() && !addr2.IsValid()) // A_F_A { return m_context.Iterator3(PrepareType(value0.m_typeValue), addr1, PrepareType(value2.m_typeValue)); } //// unknown iterator type - //SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Unknown iterator type"); + // SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Unknown iterator type"); return ScIterator3Ptr(); } @@ -339,10 +333,7 @@ class ScTemplateSearch it = iterators.top(); } - auto const applyResult = [&](ScAddr const & res1, - ScAddr const & res2, - ScAddr const & res3) - { + auto const applyResult = [&](ScAddr const & res1, ScAddr const & res2, ScAddr const & res3) { edges[orderIndex] = res2; // do not make cycle for optimization issues (remove comparsion expresion) @@ -379,16 +370,14 @@ class ScTemplateSearch // check if search in structure if (m_struct.IsValid()) { - if (!CheckInStruct(addr1) || - !CheckInStruct(addr2) || - !CheckInStruct(addr3)) + if (!CheckInStruct(addr1) || !CheckInStruct(addr2) || !CheckInStruct(addr3)) { continue; } } auto const res = m_usedEdges.insert(addr2); - if (!res.second) // don't iterate the same edge twicely + if (!res.second) // don't iterate the same edge twicely continue; applyResult(addr1, addr2, addr3); @@ -398,20 +387,20 @@ class ScTemplateSearch break; } - if (isFinished) // finish iterator + if (isFinished) // finish iterator { iterators.pop(); newIteration = false; } } - else // special checks and search + else // special checks and search { SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Invalid state during template search"); } } while (!iterators.empty()); } - ScTemplate::Result operator () (ScTemplateSearchResult & result) + ScTemplate::Result operator()(ScTemplateSearchResult & result) { // if (!m_template.m_hasRequired) // SC_THROW_EXCEPTION(utils::ExceptionInvalidParams, "Templates just with optional triples doesn't supported."); @@ -454,7 +443,10 @@ ScTemplate::Result ScTemplate::Search(ScMemoryContext & ctx, ScTemplateSearchRes return search(result); } -ScTemplate::Result ScTemplate::SearchInStruct(ScMemoryContext & ctx, ScAddr const & scStruct, ScTemplateSearchResult & result) const +ScTemplate::Result ScTemplate::SearchInStruct( + ScMemoryContext & ctx, + ScAddr const & scStruct, + ScTemplateSearchResult & result) const { ScTemplateSearch search(*this, ctx, scStruct); return search(result); diff --git a/sc-memory/sc-memory/sc_timer.cpp b/sc-memory/sc-memory/sc_timer.cpp index fa8ed46bf1..3b3dc78168 100644 --- a/sc-memory/sc-memory/sc_timer.cpp +++ b/sc-memory/sc-memory/sc_timer.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_timer.hpp" @@ -22,4 +22,3 @@ bool ScTimer::IsTimeOut() const { return ((m_timeOutSec > 0) && (Seconds() > m_timeOutSec)); } - diff --git a/sc-memory/sc-memory/sc_timer.hpp b/sc-memory/sc-memory/sc_timer.hpp index 90818f2385..bdb30fd7ed 100644 --- a/sc-memory/sc-memory/sc_timer.hpp +++ b/sc-memory/sc-memory/sc_timer.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once diff --git a/sc-memory/sc-memory/sc_type.cpp b/sc-memory/sc-memory/sc_type.cpp index f36938d28a..4e11749364 100644 --- a/sc-memory/sc-memory/sc_type.cpp +++ b/sc-memory/sc-memory/sc_type.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_type.hpp" @@ -20,7 +20,6 @@ ScType const ScType::EdgeAccessConstPosTemp(sc_type_const | sc_type_arc_access | ScType const ScType::EdgeAccessConstNegTemp(sc_type_const | sc_type_arc_access | sc_type_arc_temp | sc_type_arc_neg); ScType const ScType::EdgeAccessConstFuzTemp(sc_type_const | sc_type_arc_access | sc_type_arc_temp | sc_type_arc_fuz); - ScType const ScType::EdgeUCommonVar(sc_type_edge_common | sc_type_var); ScType const ScType::EdgeDCommonVar(sc_type_arc_common | sc_type_var); ScType const ScType::EdgeAccessVarPosPerm(sc_type_var | sc_type_arc_access | sc_type_arc_perm | sc_type_arc_pos); diff --git a/sc-memory/sc-memory/sc_type.hpp b/sc-memory/sc-memory/sc_type.hpp index 2cb4944f30..3e667399b8 100644 --- a/sc-memory/sc-memory/sc_type.hpp +++ b/sc-memory/sc-memory/sc_type.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -29,7 +29,7 @@ extern "C" #include "sc_defines.hpp" #if SC_IS_PLATFORM_WIN32 -#define NOMINMAX +# define NOMINMAX #endif using StringVector = std::vector; @@ -42,7 +42,8 @@ class _SC_EXTERN ScType public: using RealType = sc_type; - explicit ScType() : m_realType(0) + explicit ScType() + : m_realType(0) { } @@ -51,58 +52,106 @@ class _SC_EXTERN ScType { } - inline bool IsEdge() const { return (m_realType & sc_type_arc_mask) != 0; } - inline bool IsNode() const { return (m_realType & sc_type_node) != 0; } - inline bool IsLink() const { return (m_realType & sc_type_link) != 0; } - inline bool IsConst() const { return (m_realType & sc_type_const) != 0; } - inline bool IsVar() const { return (m_realType & sc_type_var) != 0; } + inline bool IsEdge() const + { + return (m_realType & sc_type_arc_mask) != 0; + } + inline bool IsNode() const + { + return (m_realType & sc_type_node) != 0; + } + inline bool IsLink() const + { + return (m_realType & sc_type_link) != 0; + } + inline bool IsConst() const + { + return (m_realType & sc_type_const) != 0; + } + inline bool IsVar() const + { + return (m_realType & sc_type_var) != 0; + } SC_DEPRECATED(0.4.0, "Use !IsUnknown() instead") - inline bool IsValid() const { return !IsUnknown(); } + inline bool IsValid() const + { + return !IsUnknown(); + } - inline bool IsUnknown() const { return (m_realType == 0); } + inline bool IsUnknown() const + { + return (m_realType == 0); + } - inline bool HasConstancyFlag() const { return (m_realType & sc_type_constancy_mask) != 0; } + inline bool HasConstancyFlag() const + { + return (m_realType & sc_type_constancy_mask) != 0; + } // Returns copy of this type, but with variable raplaced to const - inline ScType AsConst() const { return ScType((m_realType & ~sc_type_var) | sc_type_const); } + inline ScType AsConst() const + { + return ScType((m_realType & ~sc_type_var) | sc_type_const); + } // Returns copy of this type, but replace constancy type upward (metavar -> var -> const) inline ScType UpConstType() const { /// TODO: metavar - //if (isVar()) - return ScType((m_realType & ~sc_type_var) | sc_type_const); // copied from asConst for maximum perfomance + // if (isVar()) + return ScType((m_realType & ~sc_type_var) | sc_type_const); // copied from asConst for maximum perfomance } - inline sc_type operator * () const { return m_realType; } + inline sc_type operator*() const + { + return m_realType; + } - ScType & operator() (RealType bits) + ScType & operator()(RealType bits) { m_realType |= bits; return *this; } - inline bool operator == (ScType const & other) { return (m_realType == other.m_realType); } - inline bool operator != (ScType const & other) { return (m_realType != other.m_realType); } - inline RealType BitAnd(RealType const & inMask) const { return (m_realType & inMask); } + inline bool operator==(ScType const & other) + { + return (m_realType == other.m_realType); + } + inline bool operator!=(ScType const & other) + { + return (m_realType != other.m_realType); + } + inline RealType BitAnd(RealType const & inMask) const + { + return (m_realType & inMask); + } - inline ScType operator | (ScType const & other) { return ScType(m_realType | other.m_realType); } - inline ScType operator & (ScType const & other) { return ScType(m_realType & other.m_realType); } + inline ScType operator|(ScType const & other) + { + return ScType(m_realType | other.m_realType); + } + inline ScType operator&(ScType const & other) + { + return ScType(m_realType & other.m_realType); + } - inline ScType & operator |= (ScType const & other) + inline ScType & operator|=(ScType const & other) { m_realType |= other.m_realType; return *this; } - inline ScType & operator &= (ScType const & other) + inline ScType & operator&=(ScType const & other) { m_realType &= other.m_realType; return *this; } - operator RealType () const { return m_realType; } + operator RealType() const + { + return m_realType; + } /* Check if specified type can be extended by another one to be a valid type/ * For example this function returns false, if you try to extend node by @@ -124,8 +173,7 @@ class _SC_EXTERN ScType if (selfConstType != 0 && selfConstType != extConstType) return false; - auto const CheckMask = [&extType](RealType const & mask) - { + auto const CheckMask = [&extType](RealType const & mask) { return !(extType.m_realType != (extType.m_realType & mask)); }; @@ -175,19 +223,19 @@ class _SC_EXTERN ScType public: static ScType const EdgeUCommon; static ScType const EdgeDCommon; - + static ScType const EdgeUCommonConst; static ScType const EdgeDCommonConst; - + static ScType const EdgeAccess; - + static ScType const EdgeAccessConstPosPerm; static ScType const EdgeAccessConstNegPerm; static ScType const EdgeAccessConstFuzPerm; static ScType const EdgeAccessConstPosTemp; static ScType const EdgeAccessConstNegTemp; static ScType const EdgeAccessConstFuzTemp; - + static ScType const EdgeUCommonVar; static ScType const EdgeDCommonVar; static ScType const EdgeAccessVarPosPerm; @@ -196,14 +244,14 @@ class _SC_EXTERN ScType static ScType const EdgeAccessVarPosTemp; static ScType const EdgeAccessVarNegTemp; static ScType const EdgeAccessVarFuzTemp; - + static ScType const Const; static ScType const Var; - + static ScType const Node; static ScType const Link; static ScType const Unknown; - + static ScType const NodeConst; static ScType const NodeVar; @@ -217,7 +265,7 @@ class _SC_EXTERN ScType static ScType const NodeClass; static ScType const NodeAbstract; static ScType const NodeMaterial; - + static ScType const NodeConstStruct; static ScType const NodeConstTuple; static ScType const NodeConstRole; @@ -225,7 +273,7 @@ class _SC_EXTERN ScType static ScType const NodeConstClass; static ScType const NodeConstAbstract; static ScType const NodeConstMaterial; - + static ScType const NodeVarStruct; static ScType const NodeVarTuple; static ScType const NodeVarRole; diff --git a/sc-memory/sc-memory/sc_utils.cpp b/sc-memory/sc-memory/sc_utils.cpp index 0460883041..cf95597410 100644 --- a/sc-memory/sc-memory/sc_utils.cpp +++ b/sc-memory/sc-memory/sc_utils.cpp @@ -13,24 +13,15 @@ namespace utils { - void StringUtils::ToLowerCase(std::string & str) { - std::transform( - str.begin(), - str.end(), - str.begin(), - tolower); + std::transform(str.begin(), str.end(), str.begin(), tolower); } //----------------------------------------------------------------------- void StringUtils::ToUpperCase(std::string & str) { - std::transform( - str.begin(), - str.end(), - str.begin(), - toupper); + std::transform(str.begin(), str.end(), str.begin(), toupper); } bool StringUtils::StartsWith(std::string const & str, std::string const & pattern, bool lowerCase) @@ -92,7 +83,6 @@ void StringUtils::SplitFilename(std::string const & qualifiedName, std::string & outBasename = path.substr(i + 1, path.size() - i - 1); outPath = path.substr(0, i + 1); } - } void StringUtils::SplitString(std::string const & str, char delim, std::vector & outList) @@ -106,51 +96,52 @@ void StringUtils::SplitString(std::string const & str, char delim, std::vector 1023) { - //if source path is to long ensure we don't do a buffer overrun by allocating some - //new memory + // if source path is to long ensure we don't do a buffer overrun by allocating some + // new memory isDestAllocated = true; bufferDst = new char[pathLen + 1]; } - //The outer loop loops over directories + // The outer loop loops over directories while (indexSrc < pathLen) { if ((bufferSrc[indexSrc] == '\\') || (bufferSrc[indexSrc] == '/')) { - //check if we have a directory delimiter if so skip it (we should already - //have written such a delimiter by this point + // check if we have a directory delimiter if so skip it (we should already + // have written such a delimiter by this point ++indexSrc; continue; } else { - //check if there is a directory to skip of type ".\" - if ((bufferSrc[indexSrc] == '.') && - ((bufferSrc[indexSrc + 1] == '\\') || (bufferSrc[indexSrc + 1] == '/'))) + // check if there is a directory to skip of type ".\" + if ((bufferSrc[indexSrc] == '.') && ((bufferSrc[indexSrc + 1] == '\\') || (bufferSrc[indexSrc + 1] == '/'))) { indexSrc += 2; continue; } - //check if there is a directory to skip of type "..\" - else if ((bufferSrc[indexSrc] == '.') && (bufferSrc[indexSrc + 1] == '.') && - ((bufferSrc[indexSrc + 2] == '\\') || (bufferSrc[indexSrc + 2] == '/'))) + // check if there is a directory to skip of type "..\" + else if ( + (bufferSrc[indexSrc] == '.') && (bufferSrc[indexSrc + 1] == '.') && + ((bufferSrc[indexSrc + 2] == '\\') || (bufferSrc[indexSrc + 2] == '/'))) { if (indexDst > metaPathArea) { - //skip a directory backward in the destination path - do { + // skip a directory backward in the destination path + do + { --indexDst; } while ((indexDst > metaPathArea) && (bufferDst[indexDst - 1] != '/')); indexSrc += 3; @@ -158,23 +149,26 @@ std::string StringUtils::NormalizeFilePath(std::string const & init, bool makeLo } else { - //we are about to write "..\" to the destination buffer - //ensure we will not remove this in future "skip directories" + // we are about to write "..\" to the destination buffer + // ensure we will not remove this in future "skip directories" metaPathArea += 3; } } } - //transfer the current directory name from the source to the destination + // transfer the current directory name from the source to the destination while (indexSrc < pathLen) { char curChar = bufferSrc[indexSrc]; - if (makeLowerCase) curChar = tolower(curChar); - if ((curChar == '\\') || (curChar == '/')) curChar = '/'; + if (makeLowerCase) + curChar = tolower(curChar); + if ((curChar == '\\') || (curChar == '/')) + curChar = '/'; bufferDst[indexDst] = curChar; ++indexDst; ++indexSrc; - if (curChar == '/') break; + if (curChar == '/') + break; } } bufferDst[indexDst] = 0; @@ -188,8 +182,10 @@ std::string StringUtils::NormalizeFilePath(std::string const & init, bool makeLo return normalized; } - -std::string StringUtils::ReplaceAll(std::string const & source, std::string const & replaceWhat, std::string const & replaceWithWhat) +std::string StringUtils::ReplaceAll( + std::string const & source, + std::string const & replaceWhat, + std::string const & replaceWithWhat) { std::string result = source; std::string::size_type pos = 0; @@ -245,4 +241,4 @@ int Random::Int() return std::rand(); } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/sc_utils.hpp b/sc-memory/sc-memory/sc_utils.hpp index 0b427ec7ce..127fd5268c 100644 --- a/sc-memory/sc-memory/sc_utils.hpp +++ b/sc-memory/sc-memory/sc_utils.hpp @@ -16,21 +16,19 @@ #include #include - // Got it there: https://github.com/mapsme/omim/blob/136f12af3adde05623008f71d07bb996fe5801a5/base/macros.hpp #define ARRAY_SIZE(X) sizeof(::my::impl::ArraySize(X)) -#define SC_DISALLOW_COPY(className) \ - className(className const &) = delete; \ +#define SC_DISALLOW_COPY(className) \ + className(className const &) = delete; \ className & operator=(className const &) = delete - -#define SC_DISALLOW_MOVE(className) \ - className(className &&) = delete; \ +#define SC_DISALLOW_MOVE(className) \ + className(className &&) = delete; \ className & operator=(className &&) = delete -#define SC_DISALLOW_COPY_AND_MOVE(className) \ - SC_DISALLOW_COPY(className); \ +#define SC_DISALLOW_COPY_AND_MOVE(className) \ + SC_DISALLOW_COPY(className); \ SC_DISALLOW_MOVE(className) // ---------------- Reference counter ----------- @@ -59,8 +57,7 @@ class RefCount uint32_t m_refCount; }; - -#define SHARED_PTR_TYPE(__type) using __type##Ptr = std::shared_ptr< __type >; +#define SHARED_PTR_TYPE(__type) using __type##Ptr = std::shared_ptr<__type>; class MemoryBuffer { @@ -71,11 +68,23 @@ class MemoryBuffer { } - inline bool IsValid() const { return m_data != nullptr; } + inline bool IsValid() const + { + return m_data != nullptr; + } - void * Data() { return static_cast(m_data); } - void const * CData() const { return static_cast(m_data); } - size_t Size() const { return m_size; } + void * Data() + { + return static_cast(m_data); + } + void const * CData() const + { + return static_cast(m_data); + } + size_t Size() const + { + return m_size; + } size_t Read(void * buff, size_t size) const { @@ -98,7 +107,8 @@ class MemoryBuffer class MemoryBufferSafe : public MemoryBuffer { public: - MemoryBufferSafe() : MemoryBuffer() + MemoryBufferSafe() + : MemoryBuffer() { } @@ -138,27 +148,65 @@ class MemoryBufferSafe : public MemoryBuffer SHARED_PTR_TYPE(MemoryBuffer) SHARED_PTR_TYPE(MemoryBufferSafe) - namespace utils { - namespace impl { -template inline T toNumber(std::string const & value); - -template <> inline int8_t toNumber(std::string const & value) { return int8_t(std::stol(value)); } -template <> inline int16_t toNumber(std::string const & value) { return int16_t(std::stol(value)); } -template <> inline int32_t toNumber(std::string const & value) { return int32_t(std::stol(value)); } -template <> inline int64_t toNumber(std::string const & value) { return int64_t(std::stoll(value)); } -template <> inline uint8_t toNumber(std::string const & value) { return uint8_t(std::stoul(value)); } -template <> inline uint16_t toNumber(std::string const & value) { return uint16_t(std::stoul(value)); } -template <> inline uint32_t toNumber(std::string const & value) { return uint32_t(std::stoul(value)); } -template <> inline uint64_t toNumber(std::string const & value) { return uint64_t(std::stoull(value)); } -template <> inline float toNumber(std::string const & value) { return std::stof(value); } -template <> inline double toNumber(std::string const & value) { return std::stod(value); } +template +inline T toNumber(std::string const & value); -} // namespace impl +template <> +inline int8_t toNumber(std::string const & value) +{ + return int8_t(std::stol(value)); +} +template <> +inline int16_t toNumber(std::string const & value) +{ + return int16_t(std::stol(value)); +} +template <> +inline int32_t toNumber(std::string const & value) +{ + return int32_t(std::stol(value)); +} +template <> +inline int64_t toNumber(std::string const & value) +{ + return int64_t(std::stoll(value)); +} +template <> +inline uint8_t toNumber(std::string const & value) +{ + return uint8_t(std::stoul(value)); +} +template <> +inline uint16_t toNumber(std::string const & value) +{ + return uint16_t(std::stoul(value)); +} +template <> +inline uint32_t toNumber(std::string const & value) +{ + return uint32_t(std::stoul(value)); +} +template <> +inline uint64_t toNumber(std::string const & value) +{ + return uint64_t(std::stoull(value)); +} +template <> +inline float toNumber(std::string const & value) +{ + return std::stof(value); +} +template <> +inline double toNumber(std::string const & value) +{ + return std::stod(value); +} +} // namespace impl class StringUtils { @@ -169,7 +217,10 @@ class StringUtils _SC_EXTERN static bool StartsWith(std::string const & str, std::string const & pattern, bool lowerCase = true); _SC_EXTERN static bool EndsWith(std::string const & str, std::string const & pattern, bool lowerCase = true); - _SC_EXTERN static void SplitFilename(std::string const & qualifiedName, std::string & outBasename, std::string & outPath); + _SC_EXTERN static void SplitFilename( + std::string const & qualifiedName, + std::string & outBasename, + std::string & outPath); _SC_EXTERN static void SplitString(std::string const & str, char delim, std::vector & outList); _SC_EXTERN static void TrimLeft(std::string & str); @@ -179,8 +230,12 @@ class StringUtils _SC_EXTERN static std::string GetFileExtension(std::string const & filename); _SC_EXTERN static std::string NormalizeFilePath(std::string const & init, bool makeLowerCase); - _SC_EXTERN static std::string ReplaceAll(std::string const & source, std::string const & replaceWhat, std::string const & replaceWithWhat); - template static bool ParseNumber(std::string const & value, T & outValue) + _SC_EXTERN static std::string ReplaceAll( + std::string const & source, + std::string const & replaceWhat, + std::string const & replaceWithWhat); + template + static bool ParseNumber(std::string const & value, T & outValue) { try { @@ -201,4 +256,4 @@ class Random _SC_EXTERN static int Int(); }; -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/sc_wait.cpp b/sc-memory/sc-memory/sc_wait.cpp index ca4d994746..a6441ed8c3 100644 --- a/sc-memory/sc-memory/sc_wait.cpp +++ b/sc-memory/sc-memory/sc_wait.cpp @@ -7,7 +7,6 @@ #include "sc_wait.hpp" #include "kpm/sc_agent.hpp" - ScWaitActionFinished::ScWaitActionFinished(ScMemoryContext const & ctx, ScAddr const & actionAddr) : ScWaitEvent(ctx, actionAddr) { diff --git a/sc-memory/sc-memory/sc_wait.hpp b/sc-memory/sc-memory/sc_wait.hpp index 35cf5dc17f..67cb5ad947 100644 --- a/sc-memory/sc-memory/sc_wait.hpp +++ b/sc-memory/sc-memory/sc_wait.hpp @@ -51,7 +51,9 @@ class ScWait public: using DelegateFunc = std::function; - virtual ~ScWait() {} + virtual ~ScWait() + { + } void Resolve() { @@ -79,23 +81,28 @@ class ScWait }; /* Class implements event wait logic. -* Should be alive, while Memory context is alive. -*/ + * Should be alive, while Memory context is alive. + */ template class ScWaitEvent : public ScWait { public: ScWaitEvent(const ScMemoryContext & ctx, const ScAddr & addr) - : m_event(ctx, addr, - std::bind(&ScWaitEvent::OnEvent, - this, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3)) + : m_event( + ctx, + addr, + std::bind( + &ScWaitEvent::OnEvent, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)) { } - virtual ~ScWaitEvent() {} + virtual ~ScWaitEvent() + { + } protected: bool OnEvent(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) @@ -108,18 +115,19 @@ class ScWaitEvent : public ScWait return false; } - virtual bool OnEventImpl(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) { return true; } + virtual bool OnEventImpl(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) + { + return true; + } private: EventClassT m_event; }; - -template -class ScWaitCondition final : public ScWaitEvent +template +class ScWaitCondition final : public ScWaitEvent { public: - using DelegateCheckFunc = std::function; ScWaitCondition(const ScMemoryContext & ctx, const ScAddr & addr, DelegateCheckFunc func) @@ -150,4 +158,5 @@ class ScWaitActionFinished final : public ScWaitEvent }; #define SC_WAIT_CHECK(_func) std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) -#define SC_WAIT_CHECK_MEMBER(_class, _func) std::bind(_class, _func, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) +#define SC_WAIT_CHECK_MEMBER(_class, _func) \ + std::bind(_class, _func, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3) diff --git a/sc-memory/sc-memory/scs/scs_parser.cpp b/sc-memory/sc-memory/scs/scs_parser.cpp index 9f92c1e406..2a5ff32d05 100644 --- a/sc-memory/sc-memory/scs/scs_parser.cpp +++ b/sc-memory/sc-memory/scs/scs_parser.cpp @@ -16,13 +16,16 @@ #if SC_DEBUG_MODE /// TODO: @deniskoronchik: make as cmake parameter -# define SCS_DEBUG_TOKEN 1 +# define SCS_DEBUG_TOKEN 1 #endif #if SCS_DEBUG_TOKEN -# define DEBUG_TOKEN(__msg) { std::cout << __msg << std::endl; } +# define DEBUG_TOKEN(__msg) \ + { \ + std::cout << __msg << std::endl; \ + } #else -# define DEBUG_TOKEN(__msg) +# define DEBUG_TOKEN(__msg) #endif #include "scsLexer.h" @@ -53,57 +56,76 @@ std::string UnescapeContent(std::string const & content) { auto const nextSymbol = result[pos + 1]; if (nextSymbol == '\\' || nextSymbol == '[' || nextSymbol == ']') - result.replace(pos, 2, { nextSymbol }); + result.replace(pos, 2, {nextSymbol}); } ++pos; } - return result; } class ErrorListener : public antlr4::ANTLRErrorListener { protected: - void syntaxError(antlr4::Recognizer *, antlr4::Token *, size_t line, - size_t charPositionInLine, std::string const & msg, std::exception_ptr) override + void syntaxError( + antlr4::Recognizer *, + antlr4::Token *, + size_t line, + size_t charPositionInLine, + std::string const & msg, + std::exception_ptr) override { - SC_THROW_EXCEPTION(utils::ExceptionParseError, "Parse error at line " << line << "," << charPositionInLine << ": " << msg); + SC_THROW_EXCEPTION( + utils::ExceptionParseError, "Parse error at line " << line << "," << charPositionInLine << ": " << msg); } - void reportAmbiguity(antlr4::Parser *, antlr4::dfa::DFA const &, size_t, size_t, bool, - antlrcpp::BitSet const &, antlr4::atn::ATNConfigSet *) override + void reportAmbiguity( + antlr4::Parser *, + antlr4::dfa::DFA const &, + size_t, + size_t, + bool, + antlrcpp::BitSet const &, + antlr4::atn::ATNConfigSet *) override { SC_THROW_EXCEPTION(utils::ExceptionParseError, "reportAmbiguity"); } - - void reportAttemptingFullContext(antlr4::Parser *, antlr4::dfa::DFA const &, size_t, size_t, - antlrcpp::BitSet const &, antlr4::atn::ATNConfigSet *) override + void reportAttemptingFullContext( + antlr4::Parser *, + antlr4::dfa::DFA const &, + size_t, + size_t, + antlrcpp::BitSet const &, + antlr4::atn::ATNConfigSet *) override { SC_THROW_EXCEPTION(utils::ExceptionParseError, "reportAttemptingFullContext"); } - - void reportContextSensitivity(antlr4::Parser *, antlr4::dfa::DFA const &, size_t, size_t, - size_t, antlr4::atn::ATNConfigSet *) override + void reportContextSensitivity( + antlr4::Parser *, + antlr4::dfa::DFA const &, + size_t, + size_t, + size_t, + antlr4::atn::ATNConfigSet *) override { SC_THROW_EXCEPTION(utils::ExceptionParseError, "reportContextSensitivity"); } - }; -} +} // namespace namespace scs { -ParsedElement::ParsedElement(std::string const & idtf, - ScType const & type, - bool isReversed, - std::string const & value /* = "" */, - bool isURL /* = false */) +ParsedElement::ParsedElement( + std::string const & idtf, + ScType const & type, + bool isReversed, + std::string const & value /* = "" */, + bool isURL /* = false */) : m_idtf(idtf) , m_type(type) , m_visibility(Visibility::System) @@ -202,7 +224,7 @@ ElementHandle::ElementHandle(ElementID id, bool isLocal) { } -ElementID ElementHandle::operator * () const +ElementID ElementHandle::operator*() const { SC_ASSERT(IsValid(), ()); return m_id; @@ -218,24 +240,24 @@ bool ElementHandle::IsValid() const return m_id != INVALID_ID; } -bool ElementHandle::operator == (ElementHandle const & other) const +bool ElementHandle::operator==(ElementHandle const & other) const { return (m_id == other.m_id) && (m_isLocal == other.m_isLocal); } -bool ElementHandle::operator != (ElementHandle const & other) const +bool ElementHandle::operator!=(ElementHandle const & other) const { return !(*this == other); } -ElementHandle & ElementHandle::operator = (ElementHandle const & other) +ElementHandle & ElementHandle::operator=(ElementHandle const & other) { m_id = other.m_id; m_isLocal = other.m_isLocal; return *this; } -bool ElementHandle::operator < (ElementHandle const & other) const +bool ElementHandle::operator<(ElementHandle const & other) const { if (m_id == other.m_id) return m_isLocal < other.m_isLocal; @@ -243,7 +265,6 @@ bool ElementHandle::operator < (ElementHandle const & other) const return m_id < other.m_id; } - // --------------------------------------- Parser::Parser() @@ -294,8 +315,9 @@ ParsedElement & Parser::GetParsedElementRef(ElementHandle const & elID) if (*elID >= container.size()) { - SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, - std::string("ElementId{") + std::to_string(*elID) + ", " + std::to_string(elID.IsLocal()) + "}"); + SC_THROW_EXCEPTION( + utils::ExceptionItemNotFound, + std::string("ElementId{") + std::to_string(*elID) + ", " + std::to_string(elID.IsLocal()) + "}"); } return container[*elID]; @@ -307,8 +329,9 @@ ParsedElement const & Parser::GetParsedElement(ElementHandle const & elID) const if (*elID >= container.size()) { - SC_THROW_EXCEPTION(utils::ExceptionItemNotFound, - std::string("ElementId{") + std::to_string(*elID) + ", " + std::to_string(elID.IsLocal()) + "}"); + SC_THROW_EXCEPTION( + utils::ExceptionItemNotFound, + std::string("ElementId{") + std::to_string(*elID) + ", " + std::to_string(elID.IsLocal()) + "}"); } return container[*elID]; @@ -349,11 +372,12 @@ std::string Parser::GenerateContourIdtf() return std::string("..contour_") + std::to_string(m_idtfCounter++); } -ElementHandle Parser::AppendElement(std::string idtf, - ScType const & type, - bool isConnectorReversed, - std::string const & value /* = "" */, - bool isURL /* = false */) +ElementHandle Parser::AppendElement( + std::string idtf, + ScType const & type, + bool isConnectorReversed, + std::string const & value /* = "" */, + bool isURL /* = false */) { SC_CHECK_GREAT(idtf.size(), 0, ()); if (TypeResolver::IsUnnamed(idtf)) @@ -417,8 +441,7 @@ void Parser::ProcessTriple(ElementHandle const & source, ElementHandle const & e ParsedElement const & edgeEl = GetParsedElement(edge); SC_ASSERT(edgeEl.GetType().IsEdge(), ("edge has invalid type")); - auto addEdge = [this, &edgeEl](ElementHandle const & src, ElementHandle const & e, ElementHandle const & trg) - { + auto addEdge = [this, &edgeEl](ElementHandle const & src, ElementHandle const & e, ElementHandle const & trg) { ParsedElement const & srcEl = GetParsedElement(src); std::string const & idtf = srcEl.GetIdtf(); if (edgeEl.GetType() == ScType::EdgeAccessConstPosPerm && scs::TypeResolver::IsKeynodeType(idtf)) @@ -432,8 +455,7 @@ void Parser::ProcessTriple(ElementHandle const & source, ElementHandle const & e } else { - SC_THROW_EXCEPTION(utils::ExceptionParseError, - "Can't merge types for element " + targetEl.GetIdtf()); + SC_THROW_EXCEPTION(utils::ExceptionParseError, "Can't merge types for element " + targetEl.GetIdtf()); } if (!m_contourTriplesStack.empty()) @@ -465,7 +487,7 @@ ElementHandle Parser::ProcessConnector(std::string const & connector) ScType const type = TypeResolver::GetConnectorType(connector); SC_ASSERT(type.IsEdge(), ()); - return AppendElement(GenerateEdgeIdtf(), type, TypeResolver::IsConnectorReversed(connector)); + return AppendElement(GenerateEdgeIdtf(), type, TypeResolver::IsConnectorReversed(connector)); } ElementHandle Parser::ProcessContent(std::string const & content, bool isVar) @@ -542,47 +564,47 @@ void Parser::ProcessContourEnd(ElementHandle const & contourHandle) } } - ElementHandle Parser::ProcessContourEndWithJoin(ElementHandle const & source) - { - SC_ASSERT(!m_contourElementsStack.empty(), ()); - SC_ASSERT(!m_contourTriplesStack.empty(), ()); - - size_t const last = m_parsedElements.size(); - size_t const lastLocal = m_parsedElementsLocal.size(); - size_t const lastTriple = m_parsedTriples.size(); +ElementHandle Parser::ProcessContourEndWithJoin(ElementHandle const & source) +{ + SC_ASSERT(!m_contourElementsStack.empty(), ()); + SC_ASSERT(!m_contourTriplesStack.empty(), ()); - auto const ind = m_contourElementsStack.top(); - m_contourElementsStack.pop(); + size_t const last = m_parsedElements.size(); + size_t const lastLocal = m_parsedElementsLocal.size(); + size_t const lastTriple = m_parsedTriples.size(); - std::set newElements; + auto const ind = m_contourElementsStack.top(); + m_contourElementsStack.pop(); - // append all new elements into contour - for (size_t i = ind.first; i < last; ++i) - newElements.insert(ElementHandle(ElementID(i), false)); + std::set newElements; - //for (size_t i = ind.second; i < lastLocal; ++i) - // newElements.insert(ElementHandle(ElementID(i), true)); + // append all new elements into contour + for (size_t i = ind.first; i < last; ++i) + newElements.insert(ElementHandle(ElementID(i), false)); - size_t const tripleFirst = m_contourTriplesStack.top(); - m_contourTriplesStack.pop(); + // for (size_t i = ind.second; i < lastLocal; ++i) + // newElements.insert(ElementHandle(ElementID(i), true)); - for (size_t i = tripleFirst; i < lastTriple; ++i) - { - auto const & t = m_parsedTriples[i]; - newElements.insert(t.m_source); - newElements.insert(t.m_edge); - newElements.insert(t.m_target); - } + size_t const tripleFirst = m_contourTriplesStack.top(); + m_contourTriplesStack.pop(); - for (auto const & el : newElements) - { - ElementHandle const edge = ProcessConnector("->"); - ProcessTriple(source, edge, el); - } + for (size_t i = tripleFirst; i < lastTriple; ++i) + { + auto const & t = m_parsedTriples[i]; + newElements.insert(t.m_source); + newElements.insert(t.m_edge); + newElements.insert(t.m_target); + } - ParsedElement & srcEl = GetParsedElementRef(source); - srcEl.m_type = ScType::NodeConstStruct; - return source; - } + for (auto const & el : newElements) + { + ElementHandle const edge = ProcessConnector("->"); + ProcessTriple(source, edge, el); + } + ParsedElement & srcEl = GetParsedElementRef(source); + srcEl.m_type = ScType::NodeConstStruct; + return source; } + +} // namespace scs diff --git a/sc-memory/sc-memory/scs/scs_parser.hpp b/sc-memory/sc-memory/scs/scs_parser.hpp index 401485957a..099200be2b 100644 --- a/sc-memory/sc-memory/scs/scs_parser.hpp +++ b/sc-memory/sc-memory/scs/scs_parser.hpp @@ -20,9 +20,9 @@ typedef uint32_t ElementID; enum class Visibility : uint8_t { - Local, // just in one file - Global, // in whole knowledge base, but without system idtf - System // system idtf + Local, // just in one file + Global, // in whole knowledge base, but without system idtf + System // system idtf }; class ParsedElement @@ -30,11 +30,12 @@ class ParsedElement friend class Parser; public: - explicit ParsedElement(std::string const & idtf, - ScType const & type = ScType(), - bool isReversed = false, - std::string const & value = "", - bool isURL = false); + explicit ParsedElement( + std::string const & idtf, + ScType const & type = ScType(), + bool isReversed = false, + std::string const & value = "", + bool isURL = false); _SC_EXTERN std::string const & GetIdtf() const; _SC_EXTERN ScType const & GetType() const; @@ -52,10 +53,10 @@ class ParsedElement protected: std::string m_idtf; ScType m_type; - Visibility m_visibility; // cached value, to prevent each time check - bool m_isReversed : 1; // flag used just for an edges - std::string m_value; // string representation of content/link value - bool m_isURL : 1; // flag used to determine if ScLink value is an URL + Visibility m_visibility; // cached value, to prevent each time check + bool m_isReversed : 1; // flag used just for an edges + std::string m_value; // string representation of content/link value + bool m_isURL : 1; // flag used to determine if ScLink value is an URL }; class ElementHandle @@ -66,13 +67,13 @@ class ElementHandle _SC_EXTERN ElementHandle(ElementID id, bool isLocal); _SC_EXTERN ElementHandle(ElementHandle const & other) = default; - _SC_EXTERN ElementID operator * () const; + _SC_EXTERN ElementID operator*() const; _SC_EXTERN bool IsLocal() const; _SC_EXTERN bool IsValid() const; - _SC_EXTERN bool operator == (ElementHandle const & other) const; - _SC_EXTERN bool operator != (ElementHandle const & other) const; - _SC_EXTERN ElementHandle & operator = (ElementHandle const & other); - _SC_EXTERN bool operator < (ElementHandle const & other) const; + _SC_EXTERN bool operator==(ElementHandle const & other) const; + _SC_EXTERN bool operator!=(ElementHandle const & other) const; + _SC_EXTERN ElementHandle & operator=(ElementHandle const & other); + _SC_EXTERN bool operator<(ElementHandle const & other) const; private: static const ElementID INVALID_ID = std::numeric_limits::max(); @@ -81,16 +82,13 @@ class ElementHandle bool m_isLocal; }; - struct ParsedTriple { ElementHandle const m_source; ElementHandle const m_edge; ElementHandle const m_target; - ParsedTriple(ElementHandle const & s, - ElementHandle const & e, - ElementHandle const & t) + ParsedTriple(ElementHandle const & s, ElementHandle const & e, ElementHandle const & t) : m_source(s) , m_edge(e) , m_target(t) @@ -98,7 +96,6 @@ struct ParsedTriple } }; - class Parser { friend class scsParser; @@ -130,7 +127,6 @@ class Parser } protected: - ParsedElement & GetParsedElementRef(ElementHandle const & elID); ElementHandle ResolveAlias(std::string const & name); @@ -150,11 +146,12 @@ class Parser void ProcessAssign(std::string const & alias, ElementHandle const & value); private: - ElementHandle AppendElement(std::string idtf, - ScType const & type = ScType(), - bool isConnectorReversed = false, - std::string const & value = "", - bool isURL = false); + ElementHandle AppendElement( + std::string idtf, + ScType const & type = ScType(), + bool isConnectorReversed = false, + std::string const & value = "", + bool isURL = false); std::string GenerateNodeIdtf(); std::string GenerateEdgeIdtf(); @@ -162,9 +159,8 @@ class Parser std::string GenerateContourIdtf(); private: - ParsedElementVector m_parsedElements; - ParsedElementVector m_parsedElementsLocal; // just elements that has a local visibility + ParsedElementVector m_parsedElementsLocal; // just elements that has a local visibility std::stack> m_contourElementsStack; std::stack m_contourTriplesStack; @@ -177,4 +173,4 @@ class Parser uint32_t m_idtfCounter; }; -} +} // namespace scs diff --git a/sc-memory/sc-memory/scs/scs_types.cpp b/sc-memory/sc-memory/scs/scs_types.cpp index 19ed8d66e4..585446c321 100644 --- a/sc-memory/sc-memory/scs/scs_types.cpp +++ b/sc-memory/sc-memory/scs/scs_types.cpp @@ -10,82 +10,69 @@ namespace scs { -TypeResolver::MapType TypeResolver::ms_connectorToType = -{ - {">", ScType::EdgeDCommon}, - {"<", ScType::EdgeDCommon}, - {"<>", ScType::EdgeUCommon}, - {"..>", ScType::EdgeAccess}, - {"<..", ScType::EdgeAccess}, - {"<=>", ScType::EdgeUCommonConst}, - {"_<=>", ScType::EdgeUCommonVar}, - {"=>", ScType::EdgeDCommonConst}, - {"<=", ScType::EdgeDCommonConst}, - {"_=>", ScType::EdgeDCommonVar}, - {"_<=", ScType::EdgeDCommonVar}, - {"->", ScType::EdgeAccessConstPosPerm}, - {"<-", ScType::EdgeAccessConstPosPerm}, - {"_->", ScType::EdgeAccessVarPosPerm}, - {"_<-", ScType::EdgeAccessVarPosPerm}, - {"-|>", ScType::EdgeAccessConstNegPerm}, - {"<|-", ScType::EdgeAccessConstNegPerm}, - {"_-|>", ScType::EdgeAccessVarNegPerm}, - {"_<|-", ScType::EdgeAccessVarNegPerm}, - {"-/>", ScType::EdgeAccessConstFuzPerm}, - {"", ScType::EdgeAccessVarFuzPerm}, - {"_", ScType::EdgeAccessConstPosTemp}, - {"<~", ScType::EdgeAccessConstPosTemp}, - {"_~>", ScType::EdgeAccessVarPosTemp}, - {"_<~", ScType::EdgeAccessVarPosTemp}, - {"~|>", ScType::EdgeAccessConstNegTemp}, - {"<|~", ScType::EdgeAccessConstNegTemp}, - {"_~|>", ScType::EdgeAccessVarNegTemp}, - {"_<|~", ScType::EdgeAccessVarNegTemp}, - {"~/>", ScType::EdgeAccessConstFuzTemp}, - {"", ScType::EdgeAccessVarFuzTemp}, - {"_", ScType::EdgeDCommon}, + {"<", ScType::EdgeDCommon}, + {"<>", ScType::EdgeUCommon}, + {"..>", ScType::EdgeAccess}, + {"<..", ScType::EdgeAccess}, + {"<=>", ScType::EdgeUCommonConst}, + {"_<=>", ScType::EdgeUCommonVar}, + {"=>", ScType::EdgeDCommonConst}, + {"<=", ScType::EdgeDCommonConst}, + {"_=>", ScType::EdgeDCommonVar}, + {"_<=", ScType::EdgeDCommonVar}, + {"->", ScType::EdgeAccessConstPosPerm}, + {"<-", ScType::EdgeAccessConstPosPerm}, + {"_->", ScType::EdgeAccessVarPosPerm}, + {"_<-", ScType::EdgeAccessVarPosPerm}, + {"-|>", ScType::EdgeAccessConstNegPerm}, + {"<|-", ScType::EdgeAccessConstNegPerm}, + {"_-|>", ScType::EdgeAccessVarNegPerm}, + {"_<|-", ScType::EdgeAccessVarNegPerm}, + {"-/>", ScType::EdgeAccessConstFuzPerm}, + {"", ScType::EdgeAccessVarFuzPerm}, + {"_", ScType::EdgeAccessConstPosTemp}, + {"<~", ScType::EdgeAccessConstPosTemp}, + {"_~>", ScType::EdgeAccessVarPosTemp}, + {"_<~", ScType::EdgeAccessVarPosTemp}, + {"~|>", ScType::EdgeAccessConstNegTemp}, + {"<|~", ScType::EdgeAccessConstNegTemp}, + {"_~|>", ScType::EdgeAccessVarNegTemp}, + {"_<|~", ScType::EdgeAccessVarNegTemp}, + {"~/>", ScType::EdgeAccessConstFuzTemp}, + {"", ScType::EdgeAccessVarFuzTemp}, + {"_ #include @@ -33,4 +32,4 @@ class TypeResolver final static MapType ms_connectorToType; static IsType ms_reversedConnectors; }; -} +} // namespace scs diff --git a/sc-memory/sc-memory/utils/sc_base64.cpp b/sc-memory/sc-memory/utils/sc_base64.cpp index 51173a488c..52d7d3fe8a 100644 --- a/sc-memory/sc-memory/utils/sc_base64.cpp +++ b/sc-memory/sc-memory/utils/sc_base64.cpp @@ -28,27 +28,23 @@ #include "sc_base64.hpp" #include - namespace { static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } -} // namespace +} // namespace namespace ScBase64 { - - -std::string Encode(unsigned char const* bytes_to_encode, unsigned int in_len) +std::string Encode(unsigned char const * bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; @@ -87,11 +83,9 @@ std::string Encode(unsigned char const* bytes_to_encode, unsigned int in_len) while ((i++ < 3)) ret += '='; - } return ret; - } std::string Decode(std::string const & encoded_string) @@ -105,7 +99,8 @@ std::string Decode(std::string const & encoded_string) while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; + char_array_4[i++] = encoded_string[in_]; + in_++; if (i == 4) { for (i = 0; i < 4; i++) @@ -133,10 +128,11 @@ std::string Decode(std::string const & encoded_string) char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + for (j = 0; (j < i - 1); j++) + ret += char_array_3[j]; } return ret; } -} // namespace ScBase64 \ No newline at end of file +} // namespace ScBase64 \ No newline at end of file diff --git a/sc-memory/sc-memory/utils/sc_base64.hpp b/sc-memory/sc-memory/utils/sc_base64.hpp index 356c3e9218..89a7a07a8b 100644 --- a/sc-memory/sc-memory/utils/sc_base64.hpp +++ b/sc-memory/sc-memory/utils/sc_base64.hpp @@ -32,8 +32,7 @@ namespace ScBase64 { +_SC_EXTERN std::string Encode(unsigned char const *, unsigned int len); +_SC_EXTERN std::string Decode(std::string const & s); -_SC_EXTERN std::string Encode(unsigned char const*, unsigned int len); -_SC_EXTERN std::string Decode(std::string const& s); - -} +} // namespace ScBase64 diff --git a/sc-memory/sc-memory/utils/sc_boost.hpp b/sc-memory/sc-memory/utils/sc_boost.hpp index b53c0a5d7b..c4a667f1ee 100644 --- a/sc-memory/sc-memory/utils/sc_boost.hpp +++ b/sc-memory/sc-memory/utils/sc_boost.hpp @@ -6,37 +6,36 @@ namespace boost { namespace filesystem { - static boost::filesystem::path relativePath(boost::filesystem::path parent, boost::filesystem::path to) { - // Start at the root path and while they are the same then do nothing then when they first - // diverge take the remainder of the two path and replace the entire parent path with ".." - // segments. - boost::filesystem::path::const_iterator fromIter = parent.begin(); - boost::filesystem::path::const_iterator toIter = to.begin(); - - // Loop through both - while (fromIter != parent.end() && toIter != to.end() && (*toIter) == (*fromIter)) - { - ++toIter; - ++fromIter; - } - - boost::filesystem::path finalPath; - while (fromIter != parent.end()) - { - finalPath /= ".."; - ++fromIter; - } - - while (toIter != to.end()) - { - finalPath /= *toIter; - ++toIter; - } - - return finalPath; + // Start at the root path and while they are the same then do nothing then when they first + // diverge take the remainder of the two path and replace the entire parent path with ".." + // segments. + boost::filesystem::path::const_iterator fromIter = parent.begin(); + boost::filesystem::path::const_iterator toIter = to.begin(); + + // Loop through both + while (fromIter != parent.end() && toIter != to.end() && (*toIter) == (*fromIter)) + { + ++toIter; + ++fromIter; + } + + boost::filesystem::path finalPath; + while (fromIter != parent.end()) + { + finalPath /= ".."; + ++fromIter; + } + + while (toIter != to.end()) + { + finalPath /= *toIter; + ++toIter; + } + + return finalPath; } -} // filesystem -} // namespace boost \ No newline at end of file +} // namespace filesystem +} // namespace boost \ No newline at end of file diff --git a/sc-memory/sc-memory/utils/sc_cache.hpp b/sc-memory/sc-memory/utils/sc_cache.hpp index 1d91fdd0ae..b04e3e1adb 100644 --- a/sc-memory/sc-memory/utils/sc_cache.hpp +++ b/sc-memory/sc-memory/utils/sc_cache.hpp @@ -8,9 +8,9 @@ namespace utils { - // Simple cache that stores list of values. -template class Cache +template +class Cache { SC_DISALLOW_COPY(Cache); @@ -27,9 +27,10 @@ template class Cache void Init(uint32_t logCacheSize) { SC_ASSERT(logCacheSize > 0 && logCacheSize < 32, (logCacheSize)); - static_assert((std::is_same::value || - std::is_same::value || - std::is_same::value), ""); + static_assert( + (std::is_same::value || std::is_same::value || + std::is_same::value), + ""); m_cache.reset(new Data[uint64_t(1) << logCacheSize]); m_hashMask = uint32_t(1 << logCacheSize) - 1; @@ -63,17 +64,20 @@ template class Cache inline void ResetValue(uint32_t i, uint32_t & value) { - for (value = 0; Index(value) == i; ++value); + for (value = 0; Index(value) == i; ++value) + ; } inline void ResetValue(uint32_t i, uint64_t & value) { - for (value = 0; Index(value) == i; ++value); + for (value = 0; Index(value) == i; ++value) + ; } inline void ResetValue(uint32_t i, std::string & value) { - for (value = ""; Index(value) == i; value += " "); + for (value = ""; Index(value) == i; value += " ") + ; } template @@ -122,7 +126,11 @@ template class Cache // TODO: Consider using separate arrays for keys and values, to save on padding. struct Data { - Data() : m_Key(), m_Value() {} + Data() + : m_Key() + , m_Value() + { + } KeyT m_Key; ValueT m_Value; }; @@ -131,5 +139,4 @@ template class Cache uint32_t m_hashMask; }; - -} // namespace utils \ No newline at end of file +} // namespace utils \ No newline at end of file diff --git a/sc-memory/sc-memory/utils/sc_console.cpp b/sc-memory/sc-memory/utils/sc_console.cpp index 94e6655f7b..a3bd5a856e 100644 --- a/sc-memory/sc-memory/utils/sc_console.cpp +++ b/sc-memory/sc-memory/utils/sc_console.cpp @@ -1,29 +1,28 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_console.hpp" /// Common C++ headers #include #include -#include // for getch() - +#include // for getch() #if SC_IS_PLATFORM_WIN32 -# include // for WinAPI and Sleep() -# define _NO_OLDNAMES // for MinGW compatibility -# include // for getch() and kbhit() -# define getch _getch -# define kbhit _kbhit +# include // for WinAPI and Sleep() +# define _NO_OLDNAMES // for MinGW compatibility +# include // for getch() and kbhit() +# define getch _getch +# define kbhit _kbhit #else -# include // for getch() and kbhit() -# include // for getch(), kbhit() and (u)sleep() -# include // for getkey() -# include // for kbhit() -# include // for kbhit() +# include // for getch() and kbhit() +# include // for getch(), kbhit() and (u)sleep() +# include // for getkey() +# include // for kbhit() +# include // for kbhit() /// Function: getch /// Get character without waiting for Return to be pressed. @@ -53,22 +52,25 @@ int kbhit(void) tcgetattr(STDIN_FILENO, &oldt); newt = oldt; newt.c_lflag &= ~(ICANON | ECHO); - newt.c_iflag = 0; // input mode - newt.c_oflag = 0; // output mode - newt.c_cc[VMIN] = 1; // minimum time to wait - newt.c_cc[VTIME] = 1; // minimum characters to wait for + newt.c_iflag = 0; // input mode + newt.c_oflag = 0; // output mode + newt.c_cc[VMIN] = 1; // minimum time to wait + newt.c_cc[VTIME] = 1; // minimum characters to wait for tcsetattr(STDIN_FILENO, TCSANOW, &newt); - ioctl(0, FIONREAD, &cnt); // Read count + ioctl(0, FIONREAD, &cnt); // Read count struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100; - select(STDIN_FILENO + 1, NULL, NULL, NULL, &tv); // A small time delay + select(STDIN_FILENO + 1, NULL, NULL, NULL, &tv); // A small time delay tcsetattr(STDIN_FILENO, TCSANOW, &oldt); - return cnt; // Return number of characters + return cnt; // Return number of characters } -#endif // SC_PLATFORM_WIN32 +#endif // SC_PLATFORM_WIN32 -#define SC_CONSOLE_PRINT(st) { std::cout << st; } +#define SC_CONSOLE_PRINT(st) \ + { \ + std::cout << st; \ + } namespace impl { @@ -115,7 +117,7 @@ const std::string ANSI_EMPTY = ""; ScConsole::KeyCode GetKey(void) { #if !SC_IS_PLATFORM_WIN32 - int cnt = kbhit(); // for ANSI escapes processing + int cnt = kbhit(); // for ANSI escapes processing #endif int k = getch(); switch (k) @@ -125,17 +127,28 @@ ScConsole::KeyCode GetKey(void) int kk; switch (kk = getch()) { - case 71: return ScConsole::KeyCode::NumPad7; - case 72: return ScConsole::KeyCode::NumPad8; - case 73: return ScConsole::KeyCode::NumPad9; - case 75: return ScConsole::KeyCode::NumPad4; - case 77: return ScConsole::KeyCode::NumPad6; - case 79: return ScConsole::KeyCode::NumPad1; - case 80: return ScConsole::KeyCode::NumPad2; - case 81: return ScConsole::KeyCode::NumPad3; - case 82: return ScConsole::KeyCode::NumPad0; - case 83: return ScConsole::KeyCode::NumDel; - default: return static_cast(kk - 59 + static_cast(ScConsole::KeyCode::F1)); // Function keys + case 71: + return ScConsole::KeyCode::NumPad7; + case 72: + return ScConsole::KeyCode::NumPad8; + case 73: + return ScConsole::KeyCode::NumPad9; + case 75: + return ScConsole::KeyCode::NumPad4; + case 77: + return ScConsole::KeyCode::NumPad6; + case 79: + return ScConsole::KeyCode::NumPad1; + case 80: + return ScConsole::KeyCode::NumPad2; + case 81: + return ScConsole::KeyCode::NumPad3; + case 82: + return ScConsole::KeyCode::NumPad0; + case 83: + return ScConsole::KeyCode::NumDel; + default: + return static_cast(kk - 59 + static_cast(ScConsole::KeyCode::F1)); // Function keys } } case 224: @@ -143,24 +156,37 @@ ScConsole::KeyCode GetKey(void) int kk; switch (kk = getch()) { - case 71: return ScConsole::KeyCode::Home; - case 72: return ScConsole::KeyCode::Up; - case 73: return ScConsole::KeyCode::PageUp; - case 75: return ScConsole::KeyCode::Left; - case 77: return ScConsole::KeyCode::Right; - case 79: return ScConsole::KeyCode::End; - case 80: return ScConsole::KeyCode::Down; - case 81: return ScConsole::KeyCode::PageDown; - case 82: return ScConsole::KeyCode::Insert; - case 83: return ScConsole::KeyCode::Delete; - default: return static_cast(kk - 123 + static_cast(ScConsole::KeyCode::F1)); // Function keys + case 71: + return ScConsole::KeyCode::Home; + case 72: + return ScConsole::KeyCode::Up; + case 73: + return ScConsole::KeyCode::PageUp; + case 75: + return ScConsole::KeyCode::Left; + case 77: + return ScConsole::KeyCode::Right; + case 79: + return ScConsole::KeyCode::End; + case 80: + return ScConsole::KeyCode::Down; + case 81: + return ScConsole::KeyCode::PageDown; + case 82: + return ScConsole::KeyCode::Insert; + case 83: + return ScConsole::KeyCode::Delete; + default: + return static_cast(kk - 123 + static_cast(ScConsole::KeyCode::F1)); // Function keys } } - case 13: return ScConsole::KeyCode::Enter; + case 13: + return ScConsole::KeyCode::Enter; #if SC_IS_PLATFORM_WIN32 - case 27: return ScConsole::KeyCode::Escape; -#else // _WIN32 - case 155: // single-character CSI + case 27: + return ScConsole::KeyCode::Escape; +#else // _WIN32 + case 155: // single-character CSI case 27: { // Process ANSI escape sequences @@ -168,10 +194,14 @@ ScConsole::KeyCode GetKey(void) { switch (k = getch()) { - case 'A': return ScConsole::KeyCode::Up; - case 'B': return ScConsole::KeyCode::Down; - case 'C': return ScConsole::KeyCode::Right; - case 'D': return ScConsole::KeyCode::Left; + case 'A': + return ScConsole::KeyCode::Up; + case 'B': + return ScConsole::KeyCode::Down; + case 'C': + return ScConsole::KeyCode::Right; + case 'D': + return ScConsole::KeyCode::Left; } } else @@ -179,39 +209,58 @@ ScConsole::KeyCode GetKey(void) return ScConsole::KeyCode::Escape; } } -#endif // _WIN32 - default: return static_cast(k); +#endif // _WIN32 + default: + return static_cast(k); } } int nb_getch(void) { - if (kbhit()) return getch(); - else return 0; + if (kbhit()) + return getch(); + else + return 0; } std::string const & GetANSIColor(ScConsole::Color const c) { - switch (c) { - case ScConsole::Color::Reset: return ANSI_ATTRIBUTE_RESET; - case ScConsole::Color::Black: return ANSI_BLACK; - case ScConsole::Color::Blue: return ANSI_BLUE; // non-ANSI - case ScConsole::Color::Green: return ANSI_GREEN; - case ScConsole::Color::Cyan: return ANSI_CYAN; // non-ANSI - case ScConsole::Color::Red: return ANSI_RED; // non-ANSI - case ScConsole::Color::Magneta: return ANSI_MAGENTA; - case ScConsole::Color::Brown: return ANSI_BROWN; - case ScConsole::Color::Grey: return ANSI_GREY; - case ScConsole::Color::DarkGrey: return ANSI_DARKGREY; - case ScConsole::Color::LightBlue: return ANSI_LIGHTBLUE; // non-ANSI - case ScConsole::Color::LightGreen: return ANSI_LIGHTGREEN; - case ScConsole::Color::LightCyan: return ANSI_LIGHTCYAN; // non-ANSI; - case ScConsole::Color::LightRed: return ANSI_LIGHTRED; // non-ANSI; - case ScConsole::Color::LightMagneta: return ANSI_LIGHTMAGENTA; - case ScConsole::Color::Yellow: return ANSI_YELLOW; // non-ANSI - case ScConsole::Color::White: return ANSI_WHITE; + case ScConsole::Color::Reset: + return ANSI_ATTRIBUTE_RESET; + case ScConsole::Color::Black: + return ANSI_BLACK; + case ScConsole::Color::Blue: + return ANSI_BLUE; // non-ANSI + case ScConsole::Color::Green: + return ANSI_GREEN; + case ScConsole::Color::Cyan: + return ANSI_CYAN; // non-ANSI + case ScConsole::Color::Red: + return ANSI_RED; // non-ANSI + case ScConsole::Color::Magneta: + return ANSI_MAGENTA; + case ScConsole::Color::Brown: + return ANSI_BROWN; + case ScConsole::Color::Grey: + return ANSI_GREY; + case ScConsole::Color::DarkGrey: + return ANSI_DARKGREY; + case ScConsole::Color::LightBlue: + return ANSI_LIGHTBLUE; // non-ANSI + case ScConsole::Color::LightGreen: + return ANSI_LIGHTGREEN; + case ScConsole::Color::LightCyan: + return ANSI_LIGHTCYAN; // non-ANSI; + case ScConsole::Color::LightRed: + return ANSI_LIGHTRED; // non-ANSI; + case ScConsole::Color::LightMagneta: + return ANSI_LIGHTMAGENTA; + case ScConsole::Color::Yellow: + return ANSI_YELLOW; // non-ANSI + case ScConsole::Color::White: + return ANSI_WHITE; } return ANSI_EMPTY; } @@ -220,16 +269,26 @@ std::string const & GetANSIBackgroundColor(ScConsole::Color const c) { switch (c) { - case ScConsole::Color::Reset: return ANSI_ATTRIBUTE_RESET; - case ScConsole::Color::Black: return ANSI_BACKGROUND_BLACK; - case ScConsole::Color::Blue: return ANSI_BACKGROUND_BLUE; - case ScConsole::Color::Green: return ANSI_BACKGROUND_GREEN; - case ScConsole::Color::Cyan: return ANSI_BACKGROUND_CYAN; - case ScConsole::Color::Red: return ANSI_BACKGROUND_RED; - case ScConsole::Color::Magneta: return ANSI_BACKGROUND_MAGENTA; - case ScConsole::Color::Brown: return ANSI_BACKGROUND_YELLOW; - case ScConsole::Color::Grey: return ANSI_BACKGROUND_WHITE; - default: break; + case ScConsole::Color::Reset: + return ANSI_ATTRIBUTE_RESET; + case ScConsole::Color::Black: + return ANSI_BACKGROUND_BLACK; + case ScConsole::Color::Blue: + return ANSI_BACKGROUND_BLUE; + case ScConsole::Color::Green: + return ANSI_BACKGROUND_GREEN; + case ScConsole::Color::Cyan: + return ANSI_BACKGROUND_CYAN; + case ScConsole::Color::Red: + return ANSI_BACKGROUND_RED; + case ScConsole::Color::Magneta: + return ANSI_BACKGROUND_MAGENTA; + case ScConsole::Color::Brown: + return ANSI_BACKGROUND_YELLOW; + case ScConsole::Color::Grey: + return ANSI_BACKGROUND_WHITE; + default: + break; } return ANSI_EMPTY; } @@ -239,7 +298,7 @@ void SetCursorVisibility(bool isVisible) #if SC_IS_PLATFORM_WIN32 && !defined(SC_CONSOLE_USE_ANSI) HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO structCursorInfo; - GetConsoleCursorInfo(hConsoleOutput, &structCursorInfo); // Get current cursor size + GetConsoleCursorInfo(hConsoleOutput, &structCursorInfo); // Get current cursor size structCursorInfo.bVisible = (isVisible ? TRUE : FALSE); SetConsoleCursorInfo(hConsoleOutput, &structCursorInfo); #else @@ -247,7 +306,7 @@ void SetCursorVisibility(bool isVisible) #endif } -} // namespace +} // namespace impl #if SC_IS_PLATFORM_WIN32 WORD ColorToWin(ScConsole::Color c) @@ -289,7 +348,6 @@ WORD ColorToWin(ScConsole::Color c) } #endif - void ScConsole::SetColor(Color c) { #if SC_IS_PLATFORM_WIN32 && !defined(SC_CONSOLE_USE_ANSI) @@ -298,7 +356,8 @@ void ScConsole::SetColor(Color c) GetConsoleScreenBufferInfo(hConsole, &csbi); - SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFFF0) | ColorToWin(c)); // Foreground colors take up the least significant byte + SetConsoleTextAttribute( + hConsole, (csbi.wAttributes & 0xFFF0) | ColorToWin(c)); // Foreground colors take up the least significant byte #else SC_CONSOLE_PRINT(impl::GetANSIColor(c)); #endif @@ -312,7 +371,9 @@ void ScConsole::SetBackgroundColor(Color c) GetConsoleScreenBufferInfo(hConsole, &csbi); - SetConsoleTextAttribute(hConsole, (csbi.wAttributes & 0xFF0F) | (((WORD)c) << 4)); // Background colors take up the second-least significant byte + SetConsoleTextAttribute( + hConsole, + (csbi.wAttributes & 0xFF0F) | (((WORD)c) << 4)); // Background colors take up the second-least significant byte #else SC_CONSOLE_PRINT(impl::GetANSIBackgroundColor(c)); #endif @@ -321,10 +382,11 @@ void ScConsole::SetBackgroundColor(Color c) ScConsole::Color ScConsole::GetDefaultColor() { #if SC_IS_PLATFORM_WIN32 && !defined(SC_CONSOLE_USE_ANSI) - static char initialized = 0; // bool + static char initialized = 0; // bool static WORD attributes; - if (!initialized) { + if (!initialized) + { CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); attributes = csbi.wAttributes; @@ -351,7 +413,7 @@ void ScConsole::SetCursorPos(int x, int y) COORD coord; // TODO: clamping/assert for x/y <= 0? coord.X = (SHORT)(x - 1); - coord.Y = (SHORT)(y - 1); // Windows uses 0-based coordinates + coord.Y = (SHORT)(y - 1); // Windows uses 0-based coordinates SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); #else SC_CONSOLE_PRINT("\033[" << y << ";" << x << "H"); @@ -363,7 +425,7 @@ void ScConsole::Clear() #if SC_IS_PLATFORM_WIN32 && !defined(SC_CONSOLE_USE_ANSI) // Based on https://msdn.microsoft.com/en-us/library/windows/desktop/ms682022%28v=vs.85%29.aspx const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - const COORD coordScreen = { 0, 0 }; + const COORD coordScreen = {0, 0}; DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi; @@ -416,25 +478,25 @@ int ScConsole::GetRowsNum() CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { - return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; // Window height + return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; // Window height } else { return -1; } #else -# ifdef TIOCGSIZE +# ifdef TIOCGSIZE struct ttysize ts; ioctl(STDIN_FILENO, TIOCGSIZE, &ts); return ts.ts_lines; -# elif defined(TIOCGWINSZ) +# elif defined(TIOCGWINSZ) struct winsize ts; ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); return ts.ws_row; -# else // TIOCGSIZE +# else // TIOCGSIZE return -1; -# endif // TIOCGSIZE -#endif // WIN32 +# endif // TIOCGSIZE +#endif // WIN32 } int ScConsole::GetColsNum() @@ -443,25 +505,25 @@ int ScConsole::GetColsNum() CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { - return csbi.srWindow.Right - csbi.srWindow.Left + 1; // Window width + return csbi.srWindow.Right - csbi.srWindow.Left + 1; // Window width } else { return -1; } #else -# ifdef TIOCGSIZE +# ifdef TIOCGSIZE struct ttysize ts; ioctl(STDIN_FILENO, TIOCGSIZE, &ts); return ts.ts_cols; -# elif defined(TIOCGWINSZ) +# elif defined(TIOCGWINSZ) struct winsize ts; ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); return ts.ws_col; -# else // TIOCGSIZE +# else // TIOCGSIZE return -1; -# endif // TIOCGSIZE -#endif // _WIN32 +# endif // TIOCGSIZE +#endif // _WIN32 } void ScConsole::WaitAnyKey(std::string const & message) diff --git a/sc-memory/sc-memory/utils/sc_console.hpp b/sc-memory/sc-memory/utils/sc_console.hpp index 91680a2ce4..34f14328e3 100644 --- a/sc-memory/sc-memory/utils/sc_console.hpp +++ b/sc-memory/sc-memory/utils/sc_console.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -38,7 +38,6 @@ class ScConsole final White }; - class Output final { public: @@ -57,59 +56,60 @@ class ScConsole final std::cout << std::flush; } - template Output & operator << (T v) + template + Output & operator<<(T v) { std::cout << v; return *this; } + private: bool m_isNewLine = false; }; public: - enum class KeyCode : uint8_t { - Escape = 0, - Enter = 1, - Space = 32, - - Insert = 2, - Home = 3, - PageUp = 4, - Delete = 5, - End = 6, - PageDown = 7, - - Up = 14, - Down = 15, - Left = 16, - Right = 17, - - F1 = 18, - F2 = 19, - F3 = 20, - F4 = 21, - F5 = 22, - F6 = 23, - F7 = 24, - F8 = 25, - F9 = 26, - F10 = 27, - F11 = 28, - F12 = 29, - - NumDel = 30, - NumPad0 = 31, - NumPad1 = 127, - NumPad2 = 128, - NumPad3 = 129, - NumPad4 = 130, - NumPad5 = 131, - NumPad6 = 132, - NumPad7 = 133, - NumPad8 = 134, - NumPad9 = 135 + Escape = 0, + Enter = 1, + Space = 32, + + Insert = 2, + Home = 3, + PageUp = 4, + Delete = 5, + End = 6, + PageDown = 7, + + Up = 14, + Down = 15, + Left = 16, + Right = 17, + + F1 = 18, + F2 = 19, + F3 = 20, + F4 = 21, + F5 = 22, + F6 = 23, + F7 = 24, + F8 = 25, + F9 = 26, + F10 = 27, + F11 = 28, + F12 = 29, + + NumDel = 30, + NumPad0 = 31, + NumPad1 = 127, + NumPad2 = 128, + NumPad3 = 129, + NumPad4 = 130, + NumPad5 = 131, + NumPad6 = 132, + NumPad7 = 133, + NumPad8 = 134, + NumPad9 = 135 }; _SC_EXTERN static void SetColor(Color c); @@ -142,20 +142,26 @@ class ScConsole final struct CursorHideGuard final { - CursorHideGuard() { ScConsole::HideCursor(); } - ~CursorHideGuard() { ScConsole::ShowCursor(); } + CursorHideGuard() + { + ScConsole::HideCursor(); + } + ~CursorHideGuard() + { + ScConsole::ShowCursor(); + } }; }; namespace impl { - std::string const & GetANSIColor(ScConsole::Color const c); +std::string const & GetANSIColor(ScConsole::Color const c); } - -template <> inline ScConsole::Output & ScConsole::Output::operator << (ScConsole::Color v) +template <> +inline ScConsole::Output & ScConsole::Output::operator<<(ScConsole::Color v) { ScConsole::SetColor(v); - //std::cout << impl::GetANSIColor(v); + // std::cout << impl::GetANSIColor(v); return *this; } diff --git a/sc-memory/sc-memory/utils/sc_keynode_cache.cpp b/sc-memory/sc-memory/utils/sc_keynode_cache.cpp index 5d20a48168..7b3244064e 100644 --- a/sc-memory/sc-memory/utils/sc_keynode_cache.cpp +++ b/sc-memory/sc-memory/utils/sc_keynode_cache.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_keynode_cache.hpp" @@ -10,7 +10,6 @@ namespace utils { - ScKeynodeCache::ScKeynodeCache(ScMemoryContext & ctx) : m_ctx(ctx) { @@ -18,7 +17,6 @@ ScKeynodeCache::ScKeynodeCache(ScMemoryContext & ctx) ScAddr const & ScKeynodeCache::GetKeynode(std::string const & idtf) { - auto const it = m_cache.find(idtf); if (it == m_cache.end()) { @@ -37,4 +35,4 @@ ScAddr const & ScKeynodeCache::GetKeynode(std::string const & idtf) return it->second; } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_keynode_cache.hpp b/sc-memory/sc-memory/utils/sc_keynode_cache.hpp index b5d0e90872..6022fdf080 100644 --- a/sc-memory/sc-memory/utils/sc_keynode_cache.hpp +++ b/sc-memory/sc-memory/utils/sc_keynode_cache.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -16,13 +16,12 @@ class ScMemoryContext; namespace utils { - // Simple lock without mutex class ScKeynodeCache { public: _SC_EXTERN explicit ScKeynodeCache(ScMemoryContext & ctx); - + _SC_EXTERN ScAddr const & GetKeynode(std::string const & idtf); private: @@ -31,4 +30,4 @@ class ScKeynodeCache std::unordered_map m_cache; }; -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_lock.cpp b/sc-memory/sc-memory/utils/sc_lock.cpp index c6b0925c42..af852581bd 100644 --- a/sc-memory/sc-memory/utils/sc_lock.cpp +++ b/sc-memory/sc-memory/utils/sc_lock.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_lock.hpp" @@ -15,7 +15,6 @@ extern "C" namespace utils { - ScLock::ScLock() : m_locked(0) { @@ -40,4 +39,4 @@ bool ScLock::IsLocked() const return g_atomic_int_get(&m_locked) == 1; } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_lock.hpp b/sc-memory/sc-memory/utils/sc_lock.hpp index 4d30140477..72b098ec14 100644 --- a/sc-memory/sc-memory/utils/sc_lock.hpp +++ b/sc-memory/sc-memory/utils/sc_lock.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -10,7 +10,6 @@ namespace utils { - // Simple lock without mutex class ScLock { @@ -33,11 +32,18 @@ class ScLock struct ScLockScope { - ScLockScope(ScLock & lock) : m_lock(lock) { m_lock.Lock(); } - ~ScLockScope() { m_lock.Unlock(); } + ScLockScope(ScLock & lock) + : m_lock(lock) + { + m_lock.Lock(); + } + ~ScLockScope() + { + m_lock.Unlock(); + } private: ScLock & m_lock; }; -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_log.cpp b/sc-memory/sc-memory/utils/sc_log.cpp index df1124d32d..1f36526bc8 100644 --- a/sc-memory/sc-memory/utils/sc_log.cpp +++ b/sc-memory/sc-memory/utils/sc_log.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_log.hpp" #include "../sc_debug.hpp" @@ -14,18 +14,13 @@ namespace { - // should be synced with ScLog::Type -const std::string kTypeToStr[] = { - "Debug", "Info", "Warning", "Error", "Python", "PythonError", "Off" -}; +const std::string kTypeToStr[] = {"Debug", "Info", "Warning", "Error", "Python", "PythonError", "Off"}; // should be synced with ScLog::OutputType -const std::string kOutputTypeToStr[] = { - "Console", "File" -}; +const std::string kOutputTypeToStr[] = {"Console", "File"}; -} // namespace +} // namespace namespace utils { @@ -91,7 +86,7 @@ void ScLog::Shutdown() void ScLog::Message(ScLog::Type type, std::string const & msg, ScConsole::Color color /*= ScConsole::Color::White*/) { if (m_isMuted && type != Type::Error) - return; // do nothing on mute + return; // do nothing on mute utils::ScLockScope lock(gLock); if (m_mode <= type) @@ -101,17 +96,16 @@ void ScLog::Message(ScLog::Type type, std::string const & msg, ScConsole::Color std::tm tm = *std::localtime(&t); std::stringstream ss; - ss << "[" << std::setw(2) << std::setfill('0') << tm.tm_hour - << ":" << std::setw(2) << std::setfill('0') << tm.tm_min - << ":" << std::setw(2) << std::setfill('0') << tm.tm_sec << "][" - << kTypeToStr[int(type)] << "]: "; + ss << "[" << std::setw(2) << std::setfill('0') << tm.tm_hour << ":" << std::setw(2) << std::setfill('0') + << tm.tm_min << ":" << std::setw(2) << std::setfill('0') << tm.tm_sec << "][" << kTypeToStr[int(type)] << "]: "; if (m_output_mode == OutputType::Console) { ScConsole::SetColor(ScConsole::Color::White); std::cout << ss.str(); ScConsole::SetColor(color); - std::cout << msg << std::endl;; + std::cout << msg << std::endl; + ; ScConsole::ResetColor(); } else @@ -136,8 +130,8 @@ void ScLog::SetFileName(const std::string & file_name) Initialize(file_name); } -template -int ScLog::FindEnumElement(const std::string (& elements)[N], const std::string & externalValue) +template +int ScLog::FindEnumElement(const std::string (&elements)[N], const std::string & externalValue) { size_t size = N; int index = -1; @@ -153,4 +147,4 @@ int ScLog::FindEnumElement(const std::string (& elements)[N], const std::string return index; } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_log.hpp b/sc-memory/sc-memory/utils/sc_log.hpp index 88a5c0cd8a..9182a5ea17 100644 --- a/sc-memory/sc-memory/utils/sc_log.hpp +++ b/sc-memory/sc-memory/utils/sc_log.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once #include "sc_console.hpp" @@ -14,7 +14,6 @@ namespace utils { - class ScLog final { protected: @@ -23,7 +22,6 @@ class ScLog final _SC_EXTERN ~ScLog(); public: - // should be synced with kTypeToStr in cpp enum class Type : uint8_t { @@ -42,8 +40,6 @@ class ScLog final File }; - - _SC_EXTERN void Shutdown(); _SC_EXTERN void SetFileName(std::string const & file_name); @@ -67,29 +63,63 @@ class ScLog final bool Initialize(std::string const & file_name); - template - static int FindEnumElement(const std::string ( & elements)[N], const std::string & externalValue); + template + static int FindEnumElement(const std::string (&elements)[N], const std::string & externalValue); }; - #define SC_LOG_COLOR(__type, __msg, __color) \ -{ std::stringstream ss; ss << __msg; ::utils::ScLog::GetInstance()->Message(__type, ss.str(), __color); } + { \ + std::stringstream ss; \ + ss << __msg; \ + ::utils::ScLog::GetInstance()->Message(__type, ss.str(), __color); \ + } #define SC_LOG(__type, __msg) SC_LOG_COLOR(__type, __msg, ScConsole::Color::White) - -#define SC_LOG_DEBUG(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::Debug, __msg, ScConsole::Color::LightBlue) } -#define SC_LOG_INFO(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::Info, __msg, ScConsole::Color::Grey) } -#define SC_LOG_WARNING(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::Warning, __msg, ScConsole::Color::Yellow) } -#define SC_LOG_ERROR(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::Error, __msg, ScConsole::Color::Red) } -#define SC_LOG_PYTHON(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::Python, __msg, ScConsole::Color::DarkGrey) } -#define SC_LOG_PYTHON_ERROR(__msg) { SC_LOG_COLOR(::utils::ScLog::Type::PythonError, __msg, ScConsole::Color::LightRed) } -#define SC_LOG_INFO_COLOR(__msg, __color) { SC_LOG_COLOR(::utils::ScLog::Type::Info, __msg, __color) } - -#define SC_LOG_INIT(__msg) { SC_LOG_INFO("[init] " << __msg) } -#define SC_LOG_SHUTDOWN(__msg) { SC_LOG_INFO("[shutdown] " << __msg) } -#define SC_LOG_LOAD(__msg) { SC_LOG_INFO("[load] " << __msg) } -#define SC_LOG_UNLOAD(__msg) { SC_LOG_INFO("[unload] " << __msg) } - - -} // namesapce utils +#define SC_LOG_DEBUG(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Debug, __msg, ScConsole::Color::LightBlue) \ + } +#define SC_LOG_INFO(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Info, __msg, ScConsole::Color::Grey) \ + } +#define SC_LOG_WARNING(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Warning, __msg, ScConsole::Color::Yellow) \ + } +#define SC_LOG_ERROR(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Error, __msg, ScConsole::Color::Red) \ + } +#define SC_LOG_PYTHON(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Python, __msg, ScConsole::Color::DarkGrey) \ + } +#define SC_LOG_PYTHON_ERROR(__msg) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::PythonError, __msg, ScConsole::Color::LightRed) \ + } +#define SC_LOG_INFO_COLOR(__msg, __color) \ + { \ + SC_LOG_COLOR(::utils::ScLog::Type::Info, __msg, __color) \ + } + +#define SC_LOG_INIT(__msg) \ + { \ + SC_LOG_INFO("[init] " << __msg) \ + } +#define SC_LOG_SHUTDOWN(__msg) \ + { \ + SC_LOG_INFO("[shutdown] " << __msg) \ + } +#define SC_LOG_LOAD(__msg) \ + { \ + SC_LOG_INFO("[load] " << __msg) \ + } +#define SC_LOG_UNLOAD(__msg) \ + { \ + SC_LOG_INFO("[unload] " << __msg) \ + } + +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_message.hpp b/sc-memory/sc-memory/utils/sc_message.hpp index a73c766885..6e3aa52c05 100644 --- a/sc-memory/sc-memory/utils/sc_message.hpp +++ b/sc-memory/sc-memory/utils/sc_message.hpp @@ -13,26 +13,33 @@ #include #include -template inline std::string DebugPrint(T const & t); +template +inline std::string DebugPrint(T const & t); _SC_EXTERN std::string DebugPrint(std::string const & t); inline std::string DebugPrint(char const * t); inline std::string DebugPrint(char t); -template inline std::string DebugPrint(std::pair const & p); -template inline std::string DebugPrint(std::list const & v); -template inline std::string DebugPrint(std::vector const & v); -template > inline std::string DebugPrint(std::set const & v); -template > inline std::string DebugPrint(std::multiset const & v); -template > inline std::string DebugPrint(std::map const & v); -template inline std::string DebugPrint(std::initializer_list const & v); +template +inline std::string DebugPrint(std::pair const & p); +template +inline std::string DebugPrint(std::list const & v); +template +inline std::string DebugPrint(std::vector const & v); +template > +inline std::string DebugPrint(std::set const & v); +template > +inline std::string DebugPrint(std::multiset const & v); +template > +inline std::string DebugPrint(std::map const & v); +template +inline std::string DebugPrint(std::initializer_list const & v); template , class Pred = std::equal_to> inline std::string DebugPrint(std::unordered_set const & v); template , class Pred = std::equal_to> inline std::string DebugPrint(std::unordered_map const & v); - inline std::string DebugPrint(char const * t) { if (t) @@ -60,7 +67,8 @@ inline std::string DebugPrint(unsigned char t) return DebugPrint(static_cast(t)); } -template inline std::string DebugPrint(std::pair const & p) +template +inline std::string DebugPrint(std::pair const & p) { std::ostringstream out; out << "(" << DebugPrint(p.first) << ", " << DebugPrint(p.second) << ")"; @@ -71,8 +79,8 @@ namespace utils { namespace impl { - -template inline std::string DebugPrintSequence(IterT beg, IterT end) +template +inline std::string DebugPrintSequence(IterT beg, IterT end) { std::ostringstream out; out << "[" << std::distance(beg, end) << ":"; @@ -82,45 +90,53 @@ template inline std::string DebugPrintSequence(IterT beg, IterT return out.str(); } -} // namespace impl -} // namespace utils +} // namespace impl +} // namespace utils -template inline std::string DebugPrint(T (&arr) [N]) +template +inline std::string DebugPrint(T (&arr)[N]) { return ::utils::impl::DebugPrintSequence(arr, arr + N); } -template inline std::string DebugPrint(std::array const & v) +template +inline std::string DebugPrint(std::array const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::vector const & v) +template +inline std::string DebugPrint(std::vector const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::list const & v) +template +inline std::string DebugPrint(std::list const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::set const & v) +template +inline std::string DebugPrint(std::set const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::multiset const & v) +template +inline std::string DebugPrint(std::multiset const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::map const & v) +template +inline std::string DebugPrint(std::map const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(std::initializer_list const & v) +template +inline std::string DebugPrint(std::initializer_list const & v) { return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } @@ -137,7 +153,8 @@ inline std::string DebugPrint(std::unordered_map const & v) return ::utils::impl::DebugPrintSequence(v.begin(), v.end()); } -template inline std::string DebugPrint(T const & t) +template +inline std::string DebugPrint(T const & t) { std::ostringstream out; out << t; @@ -152,13 +169,15 @@ inline std::string Message() { return std::string(); } -template std::string Message(T const & t) +template +std::string Message(T const & t) { return DebugPrint(t); } -template std::string Message(T const & t, ARGS const & ... others) +template +std::string Message(T const & t, ARGS const &... others) { return DebugPrint(t) + " " + Message(others...); } -} -} +} // namespace impl +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_progress.cpp b/sc-memory/sc-memory/utils/sc_progress.cpp index 470b5bd015..2d8233d09e 100644 --- a/sc-memory/sc-memory/utils/sc_progress.cpp +++ b/sc-memory/sc-memory/utils/sc_progress.cpp @@ -9,27 +9,27 @@ namespace utils { // --------------- ScProgress::ScProgress(std::string const & title, size_t stepsNum, size_t width) - : m_title(title), - m_width(width), - m_stepsNum(stepsNum), - m_passedSteps(0), - m_isComplete(false), - m_isFirst(false), - m_prevPercent(0) + : m_title(title) + , m_width(width) + , m_stepsNum(stepsNum) + , m_passedSteps(0) + , m_isComplete(false) + , m_isFirst(false) + , m_prevPercent(0) { std::cout << m_title << "..." << std::endl; } void ScProgress::PrintStatus(size_t passedStep) { - m_passedSteps = passedStep + 1; // to correctly work with for (0; N); + m_passedSteps = passedStep + 1; // to correctly work with for (0; N); // calculate status - float progress = (float) (m_passedSteps + 1) / (float) m_stepsNum; + float progress = (float)(m_passedSteps + 1) / (float)m_stepsNum; m_isComplete = (progress >= 1.f); progress = std::min(std::max(0.f, progress), 1.f); - size_t const filledNum = (size_t) ((float) m_width * progress); - size_t const percentInt = (size_t) ((float) 100 * progress); + size_t const filledNum = (size_t)((float)m_width * progress); + size_t const percentInt = (size_t)((float)100 * progress); if (m_isFirst || (m_prevPercent != percentInt)) { @@ -46,4 +46,4 @@ void ScProgress::PrintStatus(size_t passedStep) std::cout << std::endl; } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_progress.hpp b/sc-memory/sc-memory/utils/sc_progress.hpp index be42ef31c1..33f78bb77d 100644 --- a/sc-memory/sc-memory/utils/sc_progress.hpp +++ b/sc-memory/sc-memory/utils/sc_progress.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #pragma once @@ -12,7 +12,6 @@ namespace utils { - class ScProgress final { public: @@ -30,4 +29,4 @@ class ScProgress final size_t m_prevPercent; }; -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_signal_handler.cpp b/sc-memory/sc-memory/utils/sc_signal_handler.cpp index 363b769473..e3c9e4619b 100644 --- a/sc-memory/sc-memory/utils/sc_signal_handler.cpp +++ b/sc-memory/sc-memory/utils/sc_signal_handler.cpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "sc_signal_handler.hpp" @@ -10,37 +10,37 @@ #include "../sc_debug.hpp" #if SC_IS_PLATFORM_WIN32 -#include +# include #elif SC_IS_PLATFORM_LINUX || SC_IS_PLATFORM_MAC -#include +# include #else -#error "Not supported platform" +# error "Not supported platform" #endif namespace handlers { #if SC_IS_PLATFORM_WIN32 -BOOL CtrlHandler( DWORD fdwCtrlType ) +BOOL CtrlHandler(DWORD fdwCtrlType) { - switch( fdwCtrlType ) + switch (fdwCtrlType) { - // Handle the CTRL-C signal. - case CTRL_C_EVENT: - // CTRL-CLOSE: confirm that the user wants to exit. - case CTRL_CLOSE_EVENT: - case CTRL_BREAK_EVENT: - { - if (utils::ScSignalHandler::m_onTerminate) - utils::ScSignalHandler::m_onTerminate(); - return( TRUE ); - } + // Handle the CTRL-C signal. + case CTRL_C_EVENT: + // CTRL-CLOSE: confirm that the user wants to exit. + case CTRL_CLOSE_EVENT: + case CTRL_BREAK_EVENT: + { + if (utils::ScSignalHandler::m_onTerminate) + utils::ScSignalHandler::m_onTerminate(); + return (TRUE); + } - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - return FALSE; + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + return FALSE; - default: - return FALSE; + default: + return FALSE; } } #elif SC_IS_PLATFORM_LINUX || SC_IS_PLATFORM_MAC @@ -50,20 +50,19 @@ void sc_signal_handler(int s) utils::ScSignalHandler::m_onTerminate(); } #else -#error "Not supported platform" +# error "Not supported platform" #endif -} // namespace handlers +} // namespace handlers namespace utils { - ScSignalHandler::HandlerDelegate ScSignalHandler::m_onTerminate; void ScSignalHandler::Initialize() { SC_LOG_INIT("Signal handler"); #if SC_IS_PLATFORM_WIN32 - if( SetConsoleCtrlHandler( (PHANDLER_ROUTINE) handlers::CtrlHandler, TRUE ) ) + if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)handlers::CtrlHandler, TRUE)) { SC_LOG_INFO("Signal handler initialized"); } @@ -80,8 +79,8 @@ void ScSignalHandler::Initialize() sigaction(SIGINT, &sigIntHandler, nullptr); #else -#error "Unsupported platform" +# error "Unsupported platform" #endif } -} // namespace utils +} // namespace utils diff --git a/sc-memory/sc-memory/utils/sc_signal_handler.hpp b/sc-memory/sc-memory/utils/sc_signal_handler.hpp index 47bd655646..dd6c0da57e 100644 --- a/sc-memory/sc-memory/utils/sc_signal_handler.hpp +++ b/sc-memory/sc-memory/utils/sc_signal_handler.hpp @@ -1,8 +1,8 @@ /* -* This source file is part of an OSTIS project. For the latest info, see http://ostis.net -* Distributed under the MIT License -* (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) -*/ + * This source file is part of an OSTIS project. For the latest info, see http://ostis.net + * Distributed under the MIT License + * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT) + */ #include "../sc_defines.hpp" @@ -10,7 +10,6 @@ namespace utils { - /* This class used to handle system signals such as * Ctrl + C, Ctrl + Break and etc. */ @@ -25,4 +24,4 @@ class ScSignalHandler _SC_EXTERN static HandlerDelegate m_onTerminate; }; -} // namespace utils +} // namespace utils diff --git a/sc-network/sctp_server/CMakeLists.txt b/sc-network/sctp_server/CMakeLists.txt index 9eff0ccf12..20e061e63e 100644 --- a/sc-network/sctp_server/CMakeLists.txt +++ b/sc-network/sctp_server/CMakeLists.txt @@ -8,4 +8,8 @@ target_include_directories(sctp-server target_link_libraries(sctp-server sc-memory sc-core ${BOOST_LIBS_LIST} Qt5::Core Qt5::Network) -add_dependencies(sctp-server sc-kpm sc-memory sc-core) \ No newline at end of file +add_dependencies(sctp-server sc-kpm sc-memory sc-core) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sctp-server) +endif () diff --git a/sc-network/sctp_server/main.cpp b/sc-network/sctp_server/main.cpp index d5a65bc233..585ff30514 100644 --- a/sc-network/sctp_server/main.cpp +++ b/sc-network/sctp_server/main.cpp @@ -9,7 +9,8 @@ #include -int main(int argc, char *argv[]) try +int main(int argc, char * argv[]) +try { QCoreApplication a(argc, argv); @@ -19,15 +20,14 @@ int main(int argc, char *argv[]) try sctpServer server; utils::ScSignalHandler::Initialize(); - utils::ScSignalHandler::m_onTerminate = [&server]() - { + utils::ScSignalHandler::m_onTerminate = [&server]() { server.stop(); }; if (!server.start(config)) exit(1); - //QObject::connect(&a, SIGNAL(aboutToQuit()), &server, SLOT(stop())); + // QObject::connect(&a, SIGNAL(aboutToQuit()), &server, SLOT(stop())); return a.exec(); } diff --git a/sc-network/sctp_server/sctpClient.cpp b/sc-network/sctp_server/sctpClient.cpp index 36fbc767c1..598cb1e93d 100644 --- a/sc-network/sctp_server/sctpClient.cpp +++ b/sc-network/sctp_server/sctpClient.cpp @@ -12,7 +12,7 @@ #include #include -sctpClient::sctpClient(QObject *parent, int socketDescriptor) +sctpClient::sctpClient(QObject * parent, int socketDescriptor) : QThread(parent) , mSocket(0) , mCommand(0) @@ -61,7 +61,7 @@ void sctpClient::run() delete mCommand; mCommand = 0; - //deleteLater(); // shedule destroy in main thread + // deleteLater(); // shedule destroy in main thread } void sctpClient::processCommands() diff --git a/sc-network/sctp_server/sctpClient.h b/sc-network/sctp_server/sctpClient.h index 1032dfdd4d..425b124f5b 100644 --- a/sc-network/sctp_server/sctpClient.h +++ b/sc-network/sctp_server/sctpClient.h @@ -10,7 +10,6 @@ #include #include - class QTcpSocket; class sctpCommand; @@ -18,7 +17,7 @@ class sctpClient : public QThread { Q_OBJECT public: - explicit sctpClient(QObject *parent, int socketDescriptor); + explicit sctpClient(QObject * parent, int socketDescriptor); virtual ~sctpClient(); void run(); @@ -28,14 +27,14 @@ class sctpClient : public QThread private: //! Pointer to client socket - QTcpSocket *mSocket; + QTcpSocket * mSocket; //! Pointer to command processing class - sctpCommand *mCommand; + sctpCommand * mCommand; int mSocketDescriptor; signals: - void done(sctpClient *client); + void done(sctpClient * client); }; -#endif // CLIENTTHREAD_H +#endif // CLIENTTHREAD_H diff --git a/sc-network/sctp_server/sctpCommand.cpp b/sc-network/sctp_server/sctpCommand.cpp index b4a970d817..c03c47e7fb 100644 --- a/sc-network/sctp_server/sctpCommand.cpp +++ b/sc-network/sctp_server/sctpCommand.cpp @@ -14,20 +14,20 @@ #include #include -extern "C" { +extern "C" +{ #include #include } -#define SCTP_READ_TIMEOUT 3000 - -#define READ_PARAM(__val) if (params->readRawData((char*)&__val, sizeof(__val)) != sizeof(__val)) \ - return SCTP_ERROR_CMD_READ_PARAMS; +#define SCTP_READ_TIMEOUT 3000 +#define READ_PARAM(__val) \ + if (params->readRawData((char *)&__val, sizeof(__val)) != sizeof(__val)) \ + return SCTP_ERROR_CMD_READ_PARAMS; namespace { - class IterConstsr { public: @@ -59,8 +59,8 @@ class IterConstsr quint8 m_replCount; IterParam m_args[5]; - sc_iterator3 *m_it3; - sc_iterator5 *m_it5; + sc_iterator3 * m_it3; + sc_iterator5 * m_it5; IteratorData() : m_type(SCTP_ITERATOR_COUNT) @@ -68,7 +68,7 @@ class IterConstsr , m_it3(0) , m_it5(0) { - memset(&m_repl[0], 255, sizeof(uint8_t)* 5); + memset(&m_repl[0], 255, sizeof(uint8_t) * 5); } ~IteratorData() @@ -119,10 +119,10 @@ class IterConstsr return argsCount() != 0; } - bool buildRepl(QDataStream *params) + bool buildRepl(QDataStream * params) { quint8 count = fixedCount(); - params->readRawData((char*)&m_repl[0], count); + params->readRawData((char *)&m_repl[0], count); for (quint8 i = 0; i < count; ++i) { @@ -174,17 +174,19 @@ class IterConstsr case SCTP_ITERATOR_5F_A_A_A_A: m_args[0].m_param.is_type = false; - m_args[1].m_param.is_type = m_args[2].m_param.is_type = m_args[3].m_param.is_type = m_args[4].m_param.is_type = true; + m_args[1].m_param.is_type = m_args[2].m_param.is_type = m_args[3].m_param.is_type = m_args[4].m_param.is_type = + true; break; case SCTP_ITERATOR_5A_A_F_A_A: m_args[2].m_param.is_type = false; - m_args[0].m_param.is_type = m_args[1].m_param.is_type = m_args[3].m_param.is_type = m_args[4].m_param.is_type = true; + m_args[0].m_param.is_type = m_args[1].m_param.is_type = m_args[3].m_param.is_type = m_args[4].m_param.is_type = + true; break; } } - bool buildParams(QDataStream *params) + bool buildParams(QDataStream * params) { quint8 count = argsCount(); @@ -195,12 +197,12 @@ class IterConstsr { IterParam & p = m_args[i]; if (p.m_param.is_type) - params->readRawData((char*)&p.m_param.type, sizeof(p.m_param.type)); + params->readRawData((char *)&p.m_param.type, sizeof(p.m_param.type)); else { p.m_repl = m_repl[rCount]; if (!p.isRepl()) - params->readRawData((char*)&p.m_param.addr, sizeof(p.m_param.addr)); + params->readRawData((char *)&p.m_param.addr, sizeof(p.m_param.addr)); ++rCount; } } @@ -314,7 +316,7 @@ class IterConstsr return -1; } - } // switch + } // switch return -1; } @@ -363,7 +365,6 @@ class IterConstsr } else if (count == 5) { - } return false; @@ -377,7 +378,14 @@ class IterConstsr if (count == 3) m_it3 = sc_iterator3_new(ctx, scIterator3Type(m_type), m_args[0].m_param, m_args[1].m_param, m_args[2].m_param); else if (count == 5) - m_it5 = sc_iterator5_new(ctx, scIterator5Type(m_type), m_args[0].m_param, m_args[1].m_param, m_args[2].m_param, m_args[3].m_param, m_args[4].m_param); + m_it5 = sc_iterator5_new( + ctx, + scIterator5Type(m_type), + m_args[0].m_param, + m_args[1].m_param, + m_args[2].m_param, + m_args[3].m_param, + m_args[4].m_param); } void stopIterate() @@ -418,32 +426,30 @@ class IterConstsr for (quint8 i = 0; i < count; ++i) result[pos + i] = sc_iterator5_value(m_it5, i); } - } - }; // IteratorData + }; // IteratorData typedef std::vector IteratorDataVec; IteratorDataVec m_iterators; public: - - bool build(QDataStream *params) + bool build(QDataStream * params) { quint8 iterCount; - if (params->readRawData((char*)&iterCount, sizeof(iterCount)) != sizeof(iterCount)) + if (params->readRawData((char *)&iterCount, sizeof(iterCount)) != sizeof(iterCount)) return false; if (iterCount > 50) return false; m_iterators.resize(iterCount); - for (size_t i = 0; i readRawData((char*)&it.m_type, sizeof(it.m_type)) != sizeof(it.m_type)) + if (params->readRawData((char *)&it.m_type, sizeof(it.m_type)) != sizeof(it.m_type)) return false; if (i > 0) it.buildRepl(params); @@ -557,20 +563,17 @@ class IterConstsr return generateStep(ctx, m_results, 0, 0); } - ScAddrVec const & result() const { return m_results; } - }; -} // namespace - +} // namespace // ----------------------------- -sctpCommand::sctpCommand(QObject *parent) +sctpCommand::sctpCommand(QObject * parent) : QObject(parent) , mSendEventsCount(0) , mContext(0) @@ -597,7 +600,7 @@ void sctpCommand::shutdown() mContext = 0; } -eSctpErrorCode sctpCommand::processCommand(QIODevice *inDevice, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCommand(QIODevice * inDevice, QIODevice * outDevice) { quint8 cmdCode = SCTP_CMD_UNKNOWN; quint8 cmdFlags = 0; @@ -608,17 +611,17 @@ eSctpErrorCode sctpCommand::processCommand(QIODevice *inDevice, QIODevice *outDe if (!waitAvailableBytes(inDevice, cmdHeaderSize())) return SCTP_ERROR_CMD_HEADER_READ_TIMEOUT; - inDevice->read((char*)&cmdCode, sizeof(cmdCode)); - inDevice->read((char*)&cmdFlags, sizeof(cmdFlags)); - inDevice->read((char*)&cmdId, sizeof(cmdId)); - inDevice->read((char*)&cmdParamSize, sizeof(cmdParamSize)); + inDevice->read((char *)&cmdCode, sizeof(cmdCode)); + inDevice->read((char *)&cmdFlags, sizeof(cmdFlags)); + inDevice->read((char *)&cmdId, sizeof(cmdId)); + inDevice->read((char *)&cmdParamSize, sizeof(cmdParamSize)); // read params data QByteArray paramsData(cmdParamSize, 0); if (!waitAvailableBytes(inDevice, cmdParamSize)) return SCTP_ERROR_CMD_PARAM_READ_TIMEOUT; - inDevice->read((char*)paramsData.data(), paramsData.size()); + inDevice->read((char *)paramsData.data(), paramsData.size()); QDataStream paramsStream(paramsData); switch (cmdCode) @@ -687,7 +690,7 @@ eSctpErrorCode sctpCommand::processCommand(QIODevice *inDevice, QIODevice *outDe return SCTP_ERROR; } -bool sctpCommand::waitAvailableBytes(QIODevice *stream, quint32 bytesNum) +bool sctpCommand::waitAvailableBytes(QIODevice * stream, quint32 bytesNum) { while (stream->bytesAvailable() < bytesNum) { @@ -700,17 +703,22 @@ bool sctpCommand::waitAvailableBytes(QIODevice *stream, quint32 bytesNum) return true; } -void sctpCommand::writeResultHeader(eSctpCommandCode cmdCode, quint32 cmdId, eSctpResultCode resCode, quint32 resSize, QIODevice *outDevice) +void sctpCommand::writeResultHeader( + eSctpCommandCode cmdCode, + quint32 cmdId, + eSctpResultCode resCode, + quint32 resSize, + QIODevice * outDevice) { Q_ASSERT(outDevice != 0); quint8 code = cmdCode; - outDevice->write((const char*)&code, sizeof(code)); - outDevice->write((const char*)&cmdId, sizeof(cmdId)); + outDevice->write((const char *)&code, sizeof(code)); + outDevice->write((const char *)&cmdId, sizeof(cmdId)); code = resCode; - outDevice->write((const char*)&code, sizeof(code)); - outDevice->write((const char*)&resSize, sizeof(resSize)); + outDevice->write((const char *)&code, sizeof(code)); + outDevice->write((const char *)&resSize, sizeof(resSize)); } quint32 sctpCommand::cmdHeaderSize() @@ -718,9 +726,12 @@ quint32 sctpCommand::cmdHeaderSize() return 2 * sizeof(quint8) + 2 * sizeof(quint32); } - // ----------- process commands ------------- -eSctpErrorCode sctpCommand::processCheckElement(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCheckElement( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; Q_UNUSED(cmdFlags); @@ -738,7 +749,11 @@ eSctpErrorCode sctpCommand::processCheckElement(quint32 cmdFlags, quint32 cmdId, return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processGetElementType(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processGetElementType( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; Q_UNUSED(cmdFlags); @@ -749,18 +764,23 @@ eSctpErrorCode sctpCommand::processGetElementType(quint32 cmdFlags, quint32 cmdI READ_PARAM(addr); sc_type type = 0; - eSctpResultCode resCode = (sc_memory_get_element_type(mContext, addr, &type) == SC_RESULT_OK) ? SCTP_RESULT_OK : SCTP_RESULT_FAIL; + eSctpResultCode resCode = + (sc_memory_get_element_type(mContext, addr, &type) == SC_RESULT_OK) ? SCTP_RESULT_OK : SCTP_RESULT_FAIL; quint32 resSize = (resCode == SCTP_RESULT_OK) ? sizeof(type) : 0; // send result writeResultHeader(SCTP_CMD_GET_ELEMENT_TYPE, cmdId, resCode, resSize, outDevice); if (resCode == SCTP_RESULT_OK) - outDevice->write((const char*)&type, sizeof(type)); + outDevice->write((const char *)&type, sizeof(type)); return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processElementErase(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processElementErase( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; Q_UNUSED(cmdFlags); @@ -770,14 +790,19 @@ eSctpErrorCode sctpCommand::processElementErase(quint32 cmdFlags, quint32 cmdId, // read sc-addr of sc-element from parameters READ_PARAM(addr); - eSctpResultCode resCode = (sc_memory_element_free(mContext, addr) == SC_RESULT_OK) ? SCTP_RESULT_OK : SCTP_RESULT_FAIL; + eSctpResultCode resCode = + (sc_memory_element_free(mContext, addr) == SC_RESULT_OK) ? SCTP_RESULT_OK : SCTP_RESULT_FAIL; // send result writeResultHeader(SCTP_CMD_ERASE_ELEMENT, cmdId, resCode, 0, outDevice); return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processCreateNode(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCreateNode( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { Q_UNUSED(cmdFlags); @@ -794,10 +819,11 @@ eSctpErrorCode sctpCommand::processCreateNode(quint32 cmdFlags, quint32 cmdId, Q if (SC_ADDR_IS_NOT_EMPTY(addr)) { writeResultHeader(SCTP_CMD_CREATE_NODE, cmdId, SCTP_RESULT_OK, sizeof(addr), outDevice); - outDevice->write((const char*)&addr, sizeof(addr)); + outDevice->write((const char *)&addr, sizeof(addr)); result = SCTP_NO_ERROR; - }else + } + else { writeResultHeader(SCTP_CMD_CREATE_NODE, cmdId, SCTP_RESULT_FAIL, 0, outDevice); result = SCTP_ERROR; @@ -806,7 +832,11 @@ eSctpErrorCode sctpCommand::processCreateNode(quint32 cmdFlags, quint32 cmdId, Q return result; } -eSctpErrorCode sctpCommand::processCreateLink(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCreateLink( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { Q_UNUSED(cmdFlags); @@ -817,10 +847,11 @@ eSctpErrorCode sctpCommand::processCreateLink(quint32 cmdFlags, quint32 cmdId, Q if (SC_ADDR_IS_NOT_EMPTY(addr)) { writeResultHeader(SCTP_CMD_CREATE_LINK, cmdId, SCTP_RESULT_OK, sizeof(addr), outDevice); - outDevice->write((const char*)&addr, sizeof(addr)); + outDevice->write((const char *)&addr, sizeof(addr)); result = SCTP_NO_ERROR; - }else + } + else { writeResultHeader(SCTP_CMD_CREATE_LINK, cmdId, SCTP_RESULT_FAIL, 0, outDevice); result = SCTP_ERROR; @@ -829,7 +860,11 @@ eSctpErrorCode sctpCommand::processCreateLink(quint32 cmdFlags, quint32 cmdId, Q return result; } -eSctpErrorCode sctpCommand::processCreateArc(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCreateArc( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { Q_UNUSED(cmdFlags); @@ -850,10 +885,11 @@ eSctpErrorCode sctpCommand::processCreateArc(quint32 cmdFlags, quint32 cmdId, QD if (SC_ADDR_IS_NOT_EMPTY(addr)) { writeResultHeader(SCTP_CMD_CREATE_ARC, cmdId, SCTP_RESULT_OK, sizeof(addr), outDevice); - outDevice->write((const char*)&addr, sizeof(addr)); + outDevice->write((const char *)&addr, sizeof(addr)); result = SCTP_NO_ERROR; - }else + } + else { writeResultHeader(SCTP_CMD_CREATE_LINK, cmdId, SCTP_RESULT_FAIL, 0, outDevice); result = SCTP_ERROR; @@ -862,7 +898,7 @@ eSctpErrorCode sctpCommand::processCreateArc(quint32 cmdFlags, quint32 cmdId, QD return result; } -eSctpErrorCode sctpCommand::processGetArc(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processGetArc(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice) { Q_UNUSED(cmdFlags); @@ -880,15 +916,19 @@ eSctpErrorCode sctpCommand::processGetArc(quint32 cmdFlags, quint32 cmdId, QData } writeResultHeader(SCTP_CMD_GET_ARC, cmdId, SCTP_RESULT_OK, sizeof(sc_addr) * 2, outDevice); - outDevice->write((const char*)&begin, sizeof(begin)); - outDevice->write((const char*)&end, sizeof(end)); + outDevice->write((const char *)&begin, sizeof(begin)); + outDevice->write((const char *)&end, sizeof(end)); return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processGetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processGetLinkContent( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; - sc_stream *stream = (sc_stream*)null_ptr; + sc_stream * stream = (sc_stream *)null_ptr; sc_char data_buffer[512]; sc_uint32 data_len = 0; sc_uint32 data_written = 0; @@ -898,11 +938,12 @@ eSctpErrorCode sctpCommand::processGetLinkContent(quint32 cmdFlags, quint32 cmdI Q_ASSERT(params != 0); // read sc-addr of sc-element from parameters - if (params->readRawData((char*)&addr, sizeof(addr)) != sizeof(addr)) + if (params->readRawData((char *)&addr, sizeof(addr)) != sizeof(addr)) return SCTP_ERROR_CMD_READ_PARAMS; - eSctpResultCode resCode = (sc_memory_get_link_content(mContext, addr, &stream) == SC_RESULT_OK && stream != null_ptr) ? SCTP_RESULT_OK : SCTP_RESULT_FAIL; - + eSctpResultCode resCode = (sc_memory_get_link_content(mContext, addr, &stream) == SC_RESULT_OK && stream != null_ptr) + ? SCTP_RESULT_OK + : SCTP_RESULT_FAIL; if (resCode == SCTP_RESULT_OK) { @@ -910,7 +951,7 @@ eSctpErrorCode sctpCommand::processGetLinkContent(quint32 cmdFlags, quint32 cmdI { resCode = SCTP_RESULT_FAIL; sc_stream_free(stream); - stream = (sc_stream*)null_ptr; + stream = (sc_stream *)null_ptr; } } // send result @@ -934,10 +975,10 @@ eSctpErrorCode sctpCommand::processGetLinkContent(quint32 cmdFlags, quint32 cmdI if (data_written < data_len) { quint32 len = data_len - data_written; - sc_char *data = new sc_char[len]; + sc_char * data = new sc_char[len]; memset(data, 0, len); outDevice->write(data, len); - delete []data; + delete[] data; sc_stream_free(stream); return SCTP_ERROR; @@ -953,14 +994,17 @@ eSctpErrorCode sctpCommand::processGetLinkContent(quint32 cmdFlags, quint32 cmdI if (resCode == SCTP_RESULT_OK) sc_stream_free(stream); - return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processFindLinks(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processFindLinks( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_int32 data_len = 0; - sc_char *data = 0; + sc_char * data = 0; Q_UNUSED(cmdFlags); @@ -977,17 +1021,18 @@ eSctpErrorCode sctpCommand::processFindLinks(quint32 cmdFlags, quint32 cmdId, QD return SCTP_ERROR_CMD_READ_PARAMS; } - sc_stream *stream = sc_stream_memory_new(data, data_len, SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * stream = sc_stream_memory_new(data, data_len, SC_STREAM_FLAG_READ, SC_FALSE); sc_uint32 result_count = 0; - sc_addr *result = 0; + sc_addr * result = 0; if (sc_memory_find_links_with_content(mContext, stream, &result, &result_count) != SC_RESULT_OK) writeResultHeader(SCTP_CMD_FIND_LINKS, cmdId, SCTP_RESULT_FAIL, 0, outDevice); else { - writeResultHeader(SCTP_CMD_FIND_LINKS, cmdId, SCTP_RESULT_OK, result_count * sizeof(sc_addr) + sizeof(result_count), outDevice); - outDevice->write((const char*)&result_count, sizeof(result_count)); - outDevice->write((const char*)result, sizeof(sc_addr) * result_count); + writeResultHeader( + SCTP_CMD_FIND_LINKS, cmdId, SCTP_RESULT_OK, result_count * sizeof(sc_addr) + sizeof(result_count), outDevice); + outDevice->write((const char *)&result_count, sizeof(result_count)); + outDevice->write((const char *)result, sizeof(sc_addr) * result_count); } delete[] data; sc_stream_free(stream); @@ -995,11 +1040,15 @@ eSctpErrorCode sctpCommand::processFindLinks(quint32 cmdFlags, quint32 cmdId, QD return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processSetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processSetLinkContent( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; sc_int32 data_len = 0; - sc_char *data = 0; + sc_char * data = 0; Q_UNUSED(cmdFlags); @@ -1017,17 +1066,22 @@ eSctpErrorCode sctpCommand::processSetLinkContent(quint32 cmdFlags, quint32 cmdI return SCTP_ERROR_CMD_READ_PARAMS; } - sc_stream *stream = sc_stream_memory_new(data, data_len, SC_STREAM_FLAG_READ, SC_FALSE); + sc_stream * stream = sc_stream_memory_new(data, data_len, SC_STREAM_FLAG_READ, SC_FALSE); sc_result result = sc_memory_set_link_content(mContext, addr, stream); - writeResultHeader(SCTP_CMD_SET_LINK_CONTENT, cmdId, result == SC_RESULT_OK ? SCTP_RESULT_OK : SCTP_RESULT_FAIL, 0, outDevice); + writeResultHeader( + SCTP_CMD_SET_LINK_CONTENT, cmdId, result == SC_RESULT_OK ? SCTP_RESULT_OK : SCTP_RESULT_FAIL, 0, outDevice); sc_stream_free(stream); delete[] data; return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processIterateElements(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processIterateElements( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_uchar iterator_type = 0; sc_type type1, type2, type3, type4; @@ -1045,7 +1099,7 @@ eSctpErrorCode sctpCommand::processIterateElements(quint32 cmdFlags, quint32 cmd // 3-elements iterators if (iterator_type <= SCTP_ITERATOR_3F_A_F) { - sc_iterator3 *it = (sc_iterator3*)null_ptr; + sc_iterator3 * it = (sc_iterator3 *)null_ptr; switch (iterator_type) { @@ -1090,23 +1144,24 @@ eSctpErrorCode sctpCommand::processIterateElements(quint32 cmdFlags, quint32 cmd for (sc_uint i = 0; i < 3; i++) { addr = sc_iterator3_value(it, i); - buffer.write((const char*)&addr, sizeof(addr)); + buffer.write((const char *)&addr, sizeof(addr)); } } buffer.close(); // write result - writeResultHeader(SCTP_CMD_ITERATE_ELEMENTS, cmdId, SCTP_RESULT_OK, results.size() + sizeof(results_count), outDevice); - outDevice->write((const char*)&results_count, sizeof(results_count)); + writeResultHeader( + SCTP_CMD_ITERATE_ELEMENTS, cmdId, SCTP_RESULT_OK, results.size() + sizeof(results_count), outDevice); + outDevice->write((const char *)&results_count, sizeof(results_count)); if (results_count > 0) - outDevice->write((const char*)results.constData(), results.size()); + outDevice->write((const char *)results.constData(), results.size()); sc_iterator3_free(it); - - }else + } + else { // 5-elements iterators - sc_iterator5 *it = (sc_iterator5*)null_ptr; + sc_iterator5 * it = (sc_iterator5 *)null_ptr; switch (iterator_type) { @@ -1184,16 +1239,17 @@ eSctpErrorCode sctpCommand::processIterateElements(quint32 cmdFlags, quint32 cmd for (sc_uint i = 0; i < 5; i++) { addr = sc_iterator5_value(it, i); - buffer.write((const char*)&addr, sizeof(addr)); + buffer.write((const char *)&addr, sizeof(addr)); } } buffer.close(); // write result - writeResultHeader(SCTP_CMD_ITERATE_ELEMENTS, cmdId, SCTP_RESULT_OK, results.size() + sizeof(results_count), outDevice); - outDevice->write((const char*)&results_count, sizeof(results_count)); + writeResultHeader( + SCTP_CMD_ITERATE_ELEMENTS, cmdId, SCTP_RESULT_OK, results.size() + sizeof(results_count), outDevice); + outDevice->write((const char *)&results_count, sizeof(results_count)); if (results_count > 0) - outDevice->write((const char*)results.constData(), results.size()); + outDevice->write((const char *)results.constData(), results.size()); sc_iterator5_free(it); } @@ -1201,7 +1257,11 @@ eSctpErrorCode sctpCommand::processIterateElements(quint32 cmdFlags, quint32 cmd return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processIterateConstruction(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processIterateConstruction( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { IterConstsr constr; if (constr.build(params)) @@ -1218,8 +1278,8 @@ eSctpErrorCode sctpCommand::processIterateConstruction(quint32 cmdFlags, quint32 if (result.size() > 0) { writeResultHeader(SCTP_CMD_ITERATE_CONSTRUCTION, cmdId, SCTP_RESULT_OK, s + sizeof(quint32), outDevice); - outDevice->write((const char*)&count, sizeof(count)); - outDevice->write((const char*)result.data(), s); + outDevice->write((const char *)&count, sizeof(count)); + outDevice->write((const char *)result.data(), s); } else writeResultHeader(SCTP_CMD_ITERATE_CONSTRUCTION, cmdId, SCTP_RESULT_FAIL, 0, outDevice); @@ -1230,7 +1290,11 @@ eSctpErrorCode sctpCommand::processIterateConstruction(quint32 cmdFlags, quint32 return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processGenerateConstruction(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processGenerateConstruction( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { IterConstsr constr; if (constr.build(params) && constr.generate(mContext)) @@ -1249,7 +1313,11 @@ eSctpErrorCode sctpCommand::processGenerateConstruction(quint32 cmdFlags, quint3 return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processCreateEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processCreateEvent( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_uint8 event_type; sc_addr addr; @@ -1260,7 +1328,6 @@ eSctpErrorCode sctpCommand::processCreateEvent(quint32 cmdFlags, quint32 cmdId, READ_PARAM(event_type); READ_PARAM(addr); - tEventId event = 0; if (!sctpEventManager::getSingleton()->createEvent(mContext, (sc_event_type)event_type, addr, this, event)) { @@ -1274,12 +1341,16 @@ eSctpErrorCode sctpCommand::processCreateEvent(quint32 cmdFlags, quint32 cmdId, mEventsSet.insert(event); writeResultHeader(SCTP_CMD_EVENT_CREATE, cmdId, SCTP_RESULT_OK, sizeof(tEventId), outDevice); - outDevice->write((const char*)&event, sizeof(event)); + outDevice->write((const char *)&event, sizeof(event)); return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processDestroyEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processDestroyEvent( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { tEventId eventId = 0; @@ -1291,7 +1362,7 @@ eSctpErrorCode sctpCommand::processDestroyEvent(quint32 cmdFlags, quint32 cmdId, if (sctpEventManager::getSingleton()->destroyEvent(eventId)) { writeResultHeader(SCTP_CMD_EVENT_DESTROY, cmdId, SCTP_RESULT_OK, sizeof(eventId), outDevice); - outDevice->write((const char*)&eventId, sizeof(eventId)); + outDevice->write((const char *)&eventId, sizeof(eventId)); return SCTP_NO_ERROR; } @@ -1299,13 +1370,17 @@ eSctpErrorCode sctpCommand::processDestroyEvent(quint32 cmdFlags, quint32 cmdId, return SCTP_ERROR; } -eSctpErrorCode sctpCommand::processEmitEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processEmitEvent( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { QMutexLocker locker(&mSendMutex); quint32 resSize = sizeof(mSendEventsCount) + mSendData.size(); writeResultHeader(SCTP_CMD_EVENT_EMIT, cmdId, SCTP_RESULT_OK, resSize, outDevice); - outDevice->write((const char*)&mSendEventsCount, sizeof(mSendEventsCount)); + outDevice->write((const char *)&mSendEventsCount, sizeof(mSendEventsCount)); outDevice->write(mSendData); mSendData.clear(); @@ -1314,10 +1389,14 @@ eSctpErrorCode sctpCommand::processEmitEvent(quint32 cmdFlags, quint32 cmdId, QD return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processFindElementBySysIdtf(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processFindElementBySysIdtf( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_int32 data_len = 0; - sc_char *data = 0; + sc_char * data = 0; Q_UNUSED(cmdFlags); @@ -1325,7 +1404,7 @@ eSctpErrorCode sctpCommand::processFindElementBySysIdtf(quint32 cmdFlags, quint3 // read length of content data READ_PARAM(data_len); - Q_ASSERT(data_len > 0); // just for a test + Q_ASSERT(data_len > 0); // just for a test data = new sc_char[data_len]; if (params->readRawData(data, data_len) != data_len) @@ -1340,18 +1419,22 @@ eSctpErrorCode sctpCommand::processFindElementBySysIdtf(quint32 cmdFlags, quint3 else { writeResultHeader(SCTP_CMD_FIND_ELEMENT_BY_SYSITDF, cmdId, SCTP_RESULT_OK, sizeof(sc_addr), outDevice); - outDevice->write((const char*)&result, sizeof(sc_addr)); + outDevice->write((const char *)&result, sizeof(sc_addr)); } delete[] data; return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processSetSysIdtf(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processSetSysIdtf( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { sc_addr addr; sc_int32 data_len = 0; - sc_char *data = 0; + sc_char * data = 0; Q_UNUSED(cmdFlags); @@ -1369,14 +1452,24 @@ eSctpErrorCode sctpCommand::processSetSysIdtf(quint32 cmdFlags, quint32 cmdId, Q return SCTP_ERROR_CMD_READ_PARAMS; } - writeResultHeader(SCTP_CMD_SET_SYSIDTF, cmdId, sc_helper_set_system_identifier(mContext, addr, data, data_len) != SC_RESULT_OK ? SCTP_RESULT_FAIL : SCTP_RESULT_OK, 0, outDevice); + writeResultHeader( + SCTP_CMD_SET_SYSIDTF, + cmdId, + sc_helper_set_system_identifier(mContext, addr, data, data_len) != SC_RESULT_OK ? SCTP_RESULT_FAIL + : SCTP_RESULT_OK, + 0, + outDevice); delete[] data; return SCTP_NO_ERROR; } -eSctpErrorCode sctpCommand::processStatistics(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice) +eSctpErrorCode sctpCommand::processStatistics( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice) { quint64 begin_time; quint64 end_time; @@ -1390,23 +1483,24 @@ eSctpErrorCode sctpCommand::processStatistics(quint32 cmdFlags, quint32 cmdId, Q tStatItemVector stat; sctpStatistic::getInstance()->getStatisticsInTimeRange(begin_time, end_time, stat); - writeResultHeader(SCTP_CMD_STATISTICS, cmdId, SCTP_RESULT_OK, sizeof(quint32) + sStatItem::realSize() * stat.size(), outDevice); + writeResultHeader( + SCTP_CMD_STATISTICS, cmdId, SCTP_RESULT_OK, sizeof(quint32) + sStatItem::realSize() * stat.size(), outDevice); // write result quint32 res_count = stat.size(); - outDevice->write((const char*)&res_count, sizeof(res_count)); + outDevice->write((const char *)&res_count, sizeof(res_count)); for (quint32 idx = 0; idx < res_count; ++idx) - outDevice->write((const char*)&(stat[idx]), sStatItem::realSize()); + outDevice->write((const char *)&(stat[idx]), sStatItem::realSize()); return SCTP_NO_ERROR; } sc_result sctpCommand::processEventEmit(tEventId eventId, sc_addr el_addr, sc_addr arg_addr) -{ +{ QMutexLocker locker(&mSendMutex); - mSendData.append((char*)&eventId, sizeof(eventId)); - mSendData.append((char*)&el_addr, sizeof(el_addr)); - mSendData.append((char*)&arg_addr, sizeof(arg_addr)); + mSendData.append((char *)&eventId, sizeof(eventId)); + mSendData.append((char *)&el_addr, sizeof(el_addr)); + mSendData.append((char *)&arg_addr, sizeof(arg_addr)); ++mSendEventsCount; diff --git a/sc-network/sctp_server/sctpCommand.h b/sc-network/sctp_server/sctpCommand.h index 81b3d4d4aa..bc8ab792c8 100644 --- a/sc-network/sctp_server/sctpCommand.h +++ b/sc-network/sctp_server/sctpCommand.h @@ -15,7 +15,6 @@ #include "../sctp_client/sctpTypes.hpp" - class QIODevice; /*! Base class for sctp commands. @@ -30,10 +29,9 @@ class sctpCommand : public QObject friend class sctpEventManager; public: - explicit sctpCommand(QObject *parent = 0); + explicit sctpCommand(QObject * parent = 0); virtual ~sctpCommand(); - void init(); void shutdown(); @@ -41,14 +39,14 @@ class sctpCommand : public QObject * @param inDevice Pointer to device for input data reading * @param outDevice Pointer to device for output data writing */ - eSctpErrorCode processCommand(QIODevice *inDevice, QIODevice *outDevice); + eSctpErrorCode processCommand(QIODevice * inDevice, QIODevice * outDevice); /*! Wait while specified number of bytes will be available in specified data stream * @param stream Pointer to data stream to wait available bytes * @param bytesNum Number of waiting bytes * @returns If specified \b bytesNum available in \b stream, then return true; otherwise return false */ - bool waitAvailableBytes(QIODevice *stream, quint32 bytesNum); + bool waitAvailableBytes(QIODevice * stream, quint32 bytesNum); /*! Writes result header into output device * @param cmdCode Code of processed command @@ -57,41 +55,58 @@ class sctpCommand : public QObject * @param resSize Size of result data (in bytes) * @param outDevice Pointer to output device (use to write header) */ - void writeResultHeader(eSctpCommandCode cmdCode, quint32 cmdId, eSctpResultCode resCode, quint32 resSize, QIODevice *outDevice); + void writeResultHeader( + eSctpCommandCode cmdCode, + quint32 cmdId, + eSctpResultCode resCode, + quint32 resSize, + QIODevice * outDevice); //! Return size of command header in bytes static quint32 cmdHeaderSize(); protected: //! Type of command processing function - typedef eSctpErrorCode (*fProcessCommand)(quint8 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); + typedef eSctpErrorCode ( + *fProcessCommand)(quint8 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); private: // ------- processing functions ---------- - eSctpErrorCode processCheckElement(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processGetElementType(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processElementErase(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processCreateNode(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processCreateLink(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processCreateArc(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - - - eSctpErrorCode processGetArc(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processGetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processFindLinks(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processSetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processIterateElements(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processIterateConstruction(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processGenerateConstruction(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); + eSctpErrorCode processCheckElement(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processGetElementType(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processElementErase(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processCreateNode(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processCreateLink(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processCreateArc(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + + eSctpErrorCode processGetArc(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processGetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processFindLinks(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processSetLinkContent(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processIterateElements(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processIterateConstruction( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice); + eSctpErrorCode processGenerateConstruction( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice); // events - eSctpErrorCode processCreateEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processDestroyEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processEmitEvent(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - - eSctpErrorCode processFindElementBySysIdtf(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processSetSysIdtf(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); - eSctpErrorCode processStatistics(quint32 cmdFlags, quint32 cmdId, QDataStream *params, QIODevice *outDevice); + eSctpErrorCode processCreateEvent(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processDestroyEvent(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processEmitEvent(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + + eSctpErrorCode processFindElementBySysIdtf( + quint32 cmdFlags, + quint32 cmdId, + QDataStream * params, + QIODevice * outDevice); + eSctpErrorCode processSetSysIdtf(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); + eSctpErrorCode processStatistics(quint32 cmdFlags, quint32 cmdId, QDataStream * params, QIODevice * outDevice); protected: sc_result processEventEmit(tEventId eventId, sc_addr el_addr, sc_addr arg_addr); @@ -109,14 +124,11 @@ class sctpCommand : public QObject tEventsSet mEventsSet; //! Memory context - sc_memory_context *mContext; + sc_memory_context * mContext; signals: public slots: - }; - - -#endif // SCTP_COMMAND_H +#endif // SCTP_COMMAND_H diff --git a/sc-network/sctp_server/sctpEventManager.cpp b/sc-network/sctp_server/sctpEventManager.cpp index 013611fb5a..1aa59c45df 100644 --- a/sc-network/sctp_server/sctpEventManager.cpp +++ b/sc-network/sctp_server/sctpEventManager.cpp @@ -7,11 +7,12 @@ #include "sctpEventManager.h" #include "sctpCommand.h" -extern "C" { +extern "C" +{ #include } -sctpEventManager* sctpEventManager::msInstance = 0; +sctpEventManager * sctpEventManager::msInstance = 0; sctpEventManager::sctpEventManager() : mLastEventId(1) @@ -25,7 +26,7 @@ sctpEventManager::~sctpEventManager() msInstance = 0; } -sctpEventManager* sctpEventManager::getSingleton() +sctpEventManager * sctpEventManager::getSingleton() { return msInstance; } @@ -44,7 +45,7 @@ void sctpEventManager::shutdown() tScEventsMap::iterator it, itEnd = mEvents.end(); for (it = mEvents.begin(); it != itEnd; ++it) { - sEventData *evt = it->second; + sEventData * evt = it->second; sc_event_destroy(evt->event); delete evt; } @@ -52,15 +53,19 @@ void sctpEventManager::shutdown() mEvents.clear(); } -bool sctpEventManager::createEvent(sc_memory_context *ctx, sc_event_type type, sc_addr addr, sctpCommand *cmd, tEventId &event) +bool sctpEventManager::createEvent( + sc_memory_context * ctx, + sc_event_type type, + sc_addr addr, + sctpCommand * cmd, + tEventId & event) { QMutexLocker locker(&mEventsMutex); - if (!_getAvailableEventId(event)) return false; - sEventData *evt = new sEventData(); + sEventData * evt = new sEventData(); evt->cmd = cmd; evt->id = event; @@ -92,7 +97,7 @@ bool sctpEventManager::destroyEvent(tEventId event) return true; } -bool sctpEventManager::_getAvailableEventId(tEventId &eventId) +bool sctpEventManager::_getAvailableEventId(tEventId & eventId) { tEventId start = mLastEventId; eventId = start + 1; @@ -109,8 +114,7 @@ bool sctpEventManager::_getAvailableEventId(tEventId &eventId) return false; } - -sc_result sctpEventManager::_eventsCallback(const sc_event *event, sc_addr arg) +sc_result sctpEventManager::_eventsCallback(const sc_event * event, sc_addr arg) { QMutexLocker locker(&sctpEventManager::msInstance->mEventsMutex); @@ -120,7 +124,7 @@ sc_result sctpEventManager::_eventsCallback(const sc_event *event, sc_addr arg) if (it == sctpEventManager::msInstance->mEvents.end()) return SC_RESULT_ERROR_INVALID_STATE; - sEventData *evt = it->second; + sEventData * evt = it->second; Q_ASSERT(evt && evt->cmd); Q_ASSERT(event == evt->event); diff --git a/sc-network/sctp_server/sctpEventManager.h b/sc-network/sctp_server/sctpEventManager.h index f38695d7c8..4589d4d565 100644 --- a/sc-network/sctp_server/sctpEventManager.h +++ b/sc-network/sctp_server/sctpEventManager.h @@ -17,32 +17,29 @@ class sctpCommand; struct sEventData { - sc_event *event; - sctpCommand *cmd; + sc_event * event; + sctpCommand * cmd; tEventId id; }; - struct sEventDataCompare { - bool operator() (const sEventData& lhs, const sEventData& rhs) const + bool operator()(const sEventData & lhs, const sEventData & rhs) const { return lhs.id < rhs.id; } }; - class sctpEventManager { - public: explicit sctpEventManager(); virtual ~sctpEventManager(); - static sctpEventManager* getSingleton(); + static sctpEventManager * getSingleton(); private: - static sctpEventManager *msInstance; + static sctpEventManager * msInstance; public: //! Initialize event manager @@ -52,40 +49,39 @@ class sctpEventManager void shutdown(); /*! Creates new event - * @param type Event type - * @param addr sc-addr of sc-element to create event - * @param cmd Pointer to sctpCommand class instance that works with client. It will notified on event fires - * @param eventId Reference to eventId container - * @returns If event created, then function returns true and id of a created event stores in \p eventId; otherwise - * it returns false - */ - bool createEvent(sc_memory_context *ctx, sc_event_type type, sc_addr addr, sctpCommand *cmd, tEventId &event); + * @param type Event type + * @param addr sc-addr of sc-element to create event + * @param cmd Pointer to sctpCommand class instance that works with client. It will notified on event fires + * @param eventId Reference to eventId container + * @returns If event created, then function returns true and id of a created event stores in \p eventId; otherwise + * it returns false + */ + bool createEvent(sc_memory_context * ctx, sc_event_type type, sc_addr addr, sctpCommand * cmd, tEventId & event); /*! Destroys event - * @param eventId Id of event, that need to be destroyed. - * @see sctpCommand::createEvent - * @returns If event destroyed, then returns true; otherwise returns false - */ + * @param eventId Id of event, that need to be destroyed. + * @see sctpCommand::createEvent + * @returns If event destroyed, then returns true; otherwise returns false + */ bool destroyEvent(tEventId event); - /*! Function to find unused event id. - * @param eventId Reference to variable that will contains found event id - * @returns If unused event id found, then it stored in \p eventId and function returns true; - * otherwise function returns false. - * @note This function is not thread safe, so you need to use it just when access to - * mEvents dictionary synchronized - */ - bool _getAvailableEventId(tEventId &eventId); + * @param eventId Reference to variable that will contains found event id + * @returns If unused event id found, then it stored in \p eventId and function returns true; + * otherwise function returns false. + * @note This function is not thread safe, so you need to use it just when access to + * mEvents dictionary synchronized + */ + bool _getAvailableEventId(tEventId & eventId); private: /*! Callback function for all events - */ - static sc_result _eventsCallback(const sc_event *event, sc_addr arg); + */ + static sc_result _eventsCallback(const sc_event * event, sc_addr arg); protected: //! Array of events - typedef std::map tScEventsMap; + typedef std::map tScEventsMap; tScEventsMap mEvents; tEventId mLastEventId; diff --git a/sc-network/sctp_server/sctpServer.cpp b/sc-network/sctp_server/sctpServer.cpp index 08512a7518..550e6f4283 100644 --- a/sc-network/sctp_server/sctpServer.cpp +++ b/sc-network/sctp_server/sctpServer.cpp @@ -19,7 +19,7 @@ #include -sctpServer::sctpServer(QObject *parent) +sctpServer::sctpServer(QObject * parent) : QTcpServer(parent) , mPort(0) , mStatistic(0) @@ -32,10 +32,9 @@ sctpServer::~sctpServer() { if (mStatistic) delete mStatistic; - } -bool sctpServer::start(const QString &config) +bool sctpServer::start(const QString & config) { parseConfig(config); @@ -48,9 +47,10 @@ bool sctpServer::start(const QString &config) QString ipAddress; QList ipAddressesList = QNetworkInterface::allAddresses(); // use the first non-localhost IPv4 address - for (int i = 0; i < ipAddressesList.size(); ++i) { - if (ipAddressesList.at(i) != QHostAddress::LocalHost && - ipAddressesList.at(i).toIPv4Address()) { + for (int i = 0; i < ipAddressesList.size(); ++i) + { + if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) + { ipAddress = ipAddressesList.at(i).toString(); break; } @@ -59,8 +59,7 @@ bool sctpServer::start(const QString &config) // if we did not find one, use IPv4 localhost if (ipAddress.isEmpty()) ipAddress = QHostAddress(QHostAddress::LocalHost).toString(); - QString message = QObject::tr("The server is running on\nIP: %1\tport: %2\n") - .arg(ipAddress).arg(serverPort()); + QString message = QObject::tr("The server is running on\nIP: %1\tport: %2\n").arg(ipAddress).arg(serverPort()); qDebug() << message.toUtf8().constData(); // initialize sc-memory @@ -97,7 +96,7 @@ bool sctpServer::start(const QString &config) return true; } -void sctpServer::parseConfig(const QString &config_path) +void sctpServer::parseConfig(const QString & config_path) { QSettings settings(config_path, QSettings::IniFormat); @@ -131,7 +130,8 @@ void sctpServer::parseConfig(const QString &config_path) if (!result) qWarning() << "Can't parse period statistic from configuration file\n"; if (mStatUpdatePeriod > 0 && mStatUpdatePeriod < 60) - qWarning() << "Statistics update period is very short, it would be take much processor time. Recomend to make it more long"; + qWarning() << "Statistics update period is very short, it would be take much processor time. Recomend to make it " + "more long"; mStatPath = settings.value("Stat/Path").toString(); if (mStatPath.isEmpty() && mStatUpdatePeriod > 0) @@ -143,9 +143,9 @@ void sctpServer::parseConfig(const QString &config_path) void sctpServer::incomingConnection(qintptr socketDescriptor) { - sctpClient *client = new sctpClient(this, socketDescriptor); + sctpClient * client = new sctpClient(this, socketDescriptor); connect(client, SIGNAL(finished()), client, SLOT(deleteLater())); - connect(client, SIGNAL(destroyed(QObject*)), this, SLOT(clientDestroyed(QObject*))); + connect(client, SIGNAL(destroyed(QObject *)), this, SLOT(clientDestroyed(QObject *))); mClients.insert(client); client->start(); } @@ -163,9 +163,9 @@ void sctpServer::stop() exit(0); } -void sctpServer::clientDestroyed(QObject *client) +void sctpServer::clientDestroyed(QObject * client) { - QSet::iterator it = mClients.find(static_cast(client)); + QSet::iterator it = mClients.find(static_cast(client)); if (it == mClients.end()) qWarning("Recieve event from non existing client"); diff --git a/sc-network/sctp_server/sctpServer.h b/sc-network/sctp_server/sctpServer.h index 4f841da569..fb240ed91b 100644 --- a/sc-network/sctp_server/sctpServer.h +++ b/sc-network/sctp_server/sctpServer.h @@ -24,16 +24,15 @@ class sctpServer : public QTcpServer { Q_OBJECT public: - explicit sctpServer(QObject *parent = 0); + explicit sctpServer(QObject * parent = 0); virtual ~sctpServer(); //! Starts server - bool start(const QString &config); + bool start(const QString & config); protected: //! Parse configuration file - void parseConfig(const QString &config_path); - + void parseConfig(const QString & config_path); protected: void incomingConnection(qintptr socketDescriptor); @@ -48,27 +47,25 @@ class sctpServer : public QTcpServer QString mStatPath; quint32 mStatUpdatePeriod; - sctpStatistic *mStatistic; + sctpStatistic * mStatistic; quint32 mSavePeriod; - QSet mClients; + QSet mClients; //! Event manager instance - sctpEventManager *mEventManager; + sctpEventManager * mEventManager; //! Pointer to default memory context std::unique_ptr mContext; signals: - public slots: void stop(); void onSave(); - void clientDestroyed(QObject *client); - + void clientDestroyed(QObject * client); }; -#endif // SERVER_H +#endif // SERVER_H diff --git a/sc-network/sctp_server/sctpStatistic.cpp b/sc-network/sctp_server/sctpStatistic.cpp index eb8b69cd33..451f1f368c 100644 --- a/sc-network/sctp_server/sctpStatistic.cpp +++ b/sc-network/sctp_server/sctpStatistic.cpp @@ -17,16 +17,15 @@ extern "C" #include } +sctpStatistic * sctpStatistic::mInstance = 0; -sctpStatistic* sctpStatistic::mInstance = 0; - -sctpStatistic* sctpStatistic::getInstance() +sctpStatistic * sctpStatistic::getInstance() { Q_ASSERT(mInstance != 0); return mInstance; } -sctpStatistic::sctpStatistic(QObject *parent) +sctpStatistic::sctpStatistic(QObject * parent) : QObject(parent) , mStatUpdatePeriod(0) , mStatUpdateTimer(0) @@ -42,7 +41,7 @@ sctpStatistic::~sctpStatistic() mInstance = 0; } -bool sctpStatistic::initialize(const QString &statDirPath, quint32 updatePeriod, sc_memory_context const * context) +bool sctpStatistic::initialize(const QString & statDirPath, quint32 updatePeriod, sc_memory_context const * context) { mStatPath = statDirPath; mStatUpdatePeriod = updatePeriod; @@ -91,7 +90,6 @@ void sctpStatistic::shutdown() mFsMutex = 0; } - void sctpStatistic::update() { QMutexLocker dataLocker(mDataMutex); @@ -105,7 +103,8 @@ void sctpStatistic::update() // determine date QDateTime dateTime(QDateTime::currentDateTime()); - QString statFileName = QString("%1_%2_%3").arg(dateTime.date().day()).arg(dateTime.date().month()).arg(dateTime.date().year()); + QString statFileName = + QString("%1_%2_%3").arg(dateTime.date().day()).arg(dateTime.date().month()).arg(dateTime.date().year()); QDir statDir(mStatPath); QString statFilePath = statDir.filePath(statFileName); @@ -119,20 +118,21 @@ void sctpStatistic::update() // read exist information in file if (file.open(QFile::ReadOnly)) { - if (file.read((char*)&stat.mCount, sizeof(stat.mCount)) != sizeof(stat.mCount)) + if (file.read((char *)&stat.mCount, sizeof(stat.mCount)) != sizeof(stat.mCount)) stat.mCount = 0; if (stat.mCount > 0) { int bytesToRead = sizeof(sStatItem) * stat.mCount; stat.mItems = new sStatItem[stat.mCount + 1]; - if (file.read((char*)&stat.mItems[0], bytesToRead) != bytesToRead) + if (file.read((char *)&stat.mItems[0], bytesToRead) != bytesToRead) stat.mCount = 0; } file.close(); - }else - qCritical() << "Can't open statistic file: " << statFilePath; + } + else + qCritical() << "Can't open statistic file: " << statFilePath; } // collect information @@ -158,11 +158,12 @@ void sctpStatistic::update() // save to file if (file.open(QFile::WriteOnly)) { - file.write((char*)&stat.mCount, sizeof(stat.mCount)); - file.write((char*)stat.mItems, sizeof(sStatItem) * stat.mCount); + file.write((char *)&stat.mCount, sizeof(stat.mCount)); + file.write((char *)stat.mItems, sizeof(sStatItem) * stat.mCount); file.close(); - }else + } + else qCritical() << "Can't write statistic file: " << statFilePath; memset(&mCurrentStat, 0, sizeof(mCurrentStat)); @@ -170,7 +171,7 @@ void sctpStatistic::update() mStatUpdateTimer->singleShot(mStatUpdatePeriod * 1000, this, SLOT(update())); } -void sctpStatistic::getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, tStatItemVector &result) +void sctpStatistic::getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, tStatItemVector & result) { QMutexLocker fsLocker(mFsMutex); @@ -188,7 +189,8 @@ void sctpStatistic::getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, { // build date from file name QStringList values = fileName.split("_"); - if (values.size() != 3) continue; //! TODO: error reports + if (values.size() != 3) + continue; //! TODO: error reports fileDate.setDate(QDate(values[2].toInt(), values[1].toInt(), values[0].toInt())); @@ -202,14 +204,14 @@ void sctpStatistic::getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, // read exist information in file if (file.open(QFile::ReadOnly)) { - if (file.read((char*)&stat.mCount, sizeof(stat.mCount)) != sizeof(stat.mCount)) + if (file.read((char *)&stat.mCount, sizeof(stat.mCount)) != sizeof(stat.mCount)) stat.mCount = 0; if (stat.mCount > 0) { int bytesToRead = sizeof(sStatItem) * stat.mCount; stat.mItems = new sStatItem[stat.mCount]; - if (file.read((char*)stat.mItems, bytesToRead) == bytesToRead) + if (file.read((char *)stat.mItems, bytesToRead) == bytesToRead) { // iterate internal data for (quint32 idx = 0; idx < stat.mCount; idx++) @@ -221,15 +223,16 @@ void sctpStatistic::getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, else { if (stat.mItems[idx].mTime > end_time) - break; // do not process file, because we gone out of range + break; // do not process file, because we gone out of range } } - }//! TODO report error + } //! TODO report error } file.close(); - }else - qCritical() << "Can't open statistic file: " << statFilePath; + } + else + qCritical() << "Can't open statistic file: " << statFilePath; } } diff --git a/sc-network/sctp_server/sctpStatistic.h b/sc-network/sctp_server/sctpStatistic.h index f9662cab25..13b85a58a3 100644 --- a/sc-network/sctp_server/sctpStatistic.h +++ b/sc-network/sctp_server/sctpStatistic.h @@ -11,24 +11,23 @@ #include "../sctp_client/sctpTypes.hpp" - class QTimer; class QMutex; //! Structure to store statistic information for on time value struct sStatItem { - quint64 mTime; // unix time - quint64 mNodeCount; // amount of all nodes - quint64 mArcCount; // amount of all arcs - quint64 mLinksCount; // amount of all links - quint64 mEmptyCount; // amount of empty sc-elements - quint64 mConnectionsCount; // amount of collected clients - quint64 mCommandsCount; // amount of processed commands (it includes commands with errors) - quint64 mCommandErrorsCount; // amount of command, that was processed with error - quint8 mIsInitStat; // flag on initial stat save - - bool operator < (const sStatItem &other) const + quint64 mTime; // unix time + quint64 mNodeCount; // amount of all nodes + quint64 mArcCount; // amount of all arcs + quint64 mLinksCount; // amount of all links + quint64 mEmptyCount; // amount of empty sc-elements + quint64 mConnectionsCount; // amount of collected clients + quint64 mCommandsCount; // amount of processed commands (it includes commands with errors) + quint64 mCommandErrorsCount; // amount of command, that was processed with error + quint8 mIsInitStat; // flag on initial stat save + + bool operator<(const sStatItem & other) const { return mTime < other.mTime; } @@ -45,8 +44,8 @@ typedef QVector tStatItemVector; */ struct sStat { - quint32 mCount; // number of stat items - sStatItem *mItems; // array of stat items + quint32 mCount; // number of stat items + sStatItem * mItems; // array of stat items sStat() : mCount(0) @@ -57,11 +56,10 @@ struct sStat ~sStat() { if (mItems) - delete []mItems; + delete[] mItems; } }; - /*! * \brief Class to work with statistics information */ @@ -70,26 +68,23 @@ class sctpStatistic : public QObject Q_OBJECT public: - explicit sctpStatistic(QObject *parent = 0); + explicit sctpStatistic(QObject * parent = 0); virtual ~sctpStatistic(); //! Initialize statistics - bool initialize(const QString &statDirPath, quint32 updatePeriod, sc_memory_context const * context); + bool initialize(const QString & statDirPath, quint32 updatePeriod, sc_memory_context const * context); //! Shutdown statistics void shutdown(); //! Returns pointer to singleton instance - static sctpStatistic* getInstance(); - + static sctpStatistic * getInstance(); /*! Collect statistics information in specified time range - * @param beg_time Begin range time - * @param end_time End range time - * @param result vector, that will be filled with statistics - */ - void getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, tStatItemVector &result); - - + * @param beg_time Begin range time + * @param end_time End range time + * @param result vector, that will be filled with statistics + */ + void getStatisticsInTimeRange(quint64 beg_time, quint64 end_time, tStatItemVector & result); protected: //! Path to directory to store statistics information @@ -97,15 +92,15 @@ class sctpStatistic : public QObject //! Time period to collect statistics (seconds) quint32 mStatUpdatePeriod; //! Statistics update timer - QTimer *mStatUpdateTimer; + QTimer * mStatUpdateTimer; //! Flag that determine, if statistics was updated on start bool mStatInitUpdate; //! Current statistic info sStatItem mCurrentStat; //! Pointer to mutex, that used to synchronize data - QMutex *mDataMutex; + QMutex * mDataMutex; //! Pointer to mutex, that used to synchronize filesystem routines - QMutex *mFsMutex; + QMutex * mFsMutex; //! Pointer to default memory context sc_memory_context const * mContext; @@ -115,10 +110,10 @@ class sctpStatistic : public QObject void commandProcessed(bool error); private: - static sctpStatistic *mInstance; + static sctpStatistic * mInstance; protected slots: void update(); }; -#endif // _sctpStat_h_ +#endif // _sctpStat_h_ diff --git a/sc-server/CMakeLists.txt b/sc-server/CMakeLists.txt index e84d325154..9a2701153a 100644 --- a/sc-server/CMakeLists.txt +++ b/sc-server/CMakeLists.txt @@ -26,3 +26,7 @@ add_dependencies(sc-server sc-kpm sc-memory ) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-server) +endif () diff --git a/sc-server/src/main.cpp b/sc-server/src/main.cpp index 93c5338cb4..bc4c44931b 100644 --- a/sc-server/src/main.cpp +++ b/sc-server/src/main.cpp @@ -15,19 +15,19 @@ #include #include -int main(int argc, char *argv[]) try +int main(int argc, char * argv[]) +try { boost::program_options::options_description options_description("Builder usage"); - options_description.add_options() - ("help", "Display this message") - ("ext-path,e", boost::program_options::value(), "Path to directory with sc-memory extensions") - ("repo-path,r", boost::program_options::value(), "Path to repository") - ("verbose,v", "Flag to don't save sc-memory state on exit") - ("clear,c", "Flag to clear sc-memory on start") - ("config-file,i", boost::program_options::value(), "Path to configuration file"); + options_description.add_options()("help", "Display this message")( + "ext-path,e", boost::program_options::value(), "Path to directory with sc-memory extensions")( + "repo-path,r", boost::program_options::value(), "Path to repository")( + "verbose,v", "Flag to don't save sc-memory state on exit")("clear,c", "Flag to clear sc-memory on start")( + "config-file,i", boost::program_options::value(), "Path to configuration file"); boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(options_description).run(), vm); + boost::program_options::store( + boost::program_options::command_line_parser(argc, argv).options(options_description).run(), vm); boost::program_options::notify(vm); std::string configFile; @@ -56,10 +56,9 @@ int main(int argc, char *argv[]) try return 0; } - std::atomic_bool isRun = { true }; + std::atomic_bool isRun = {true}; utils::ScSignalHandler::Initialize(); - utils::ScSignalHandler::m_onTerminate = [&isRun]() - { + utils::ScSignalHandler::m_onTerminate = [&isRun]() { isRun = false; }; @@ -81,7 +80,7 @@ int main(int argc, char *argv[]) try ScMemory::Shutdown(saveState); - return EXIT_SUCCESS; // : EXIT_FAILURE; + return EXIT_SUCCESS; // : EXIT_FAILURE; } catch (utils::ScException const & ex) { diff --git a/scripts/ci/check-formatting.sh b/scripts/ci/check-formatting.sh new file mode 100755 index 0000000000..c7a870f0ba --- /dev/null +++ b/scripts/ci/check-formatting.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eo pipefail + +cmake -B build -DSC_CLANG_FORMAT_CODE=ON +cmake --build build --target clangformat_check diff --git a/scripts/ci/make-tests.sh b/scripts/ci/make-tests.sh index ea1413e8bc..3ef77f1588 100755 --- a/scripts/ci/make-tests.sh +++ b/scripts/ci/make-tests.sh @@ -4,14 +4,11 @@ set -eo pipefail pip3 install --user -r requirements.txt -mkdir build -pushd build - -cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DSC_COVERAGE=${COVERAGE} -DSC_AUTO_TEST=ON -DSC_BUILD_TESTS=ON -DSC_KPM_SCP=OFF +cmake -B build -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DSC_COVERAGE=${COVERAGE} -DSC_AUTO_TEST=ON -DSC_BUILD_TESTS=ON -DSC_KPM_SCP=OFF echo ::group::Make -make -j$(nproc) +cmake --build build -j$(nproc) echo ::endgroup:: +pushd build ../bin/sc-builder -i ../tools/builder/tests/kb -o ../bin/sc-builder-test-repo -c -f - -popd \ No newline at end of file +popd diff --git a/scripts/install_deps_ubuntu.sh b/scripts/install_deps_ubuntu.sh index 8552d51e9b..9bbb7242bf 100755 --- a/scripts/install_deps_ubuntu.sh +++ b/scripts/install_deps_ubuntu.sh @@ -4,4 +4,4 @@ sudo apt-get install -y librocksdb-dev \ libboost-filesystem-dev libboost-program-options-dev \ make cmake antlr gcc g++ llvm-7 \ libcurl4-openssl-dev libclang-7-dev libboost-python-dev \ - python3-dev python3 python3-pip python3-setuptools + python3-dev python3 python3-pip python3-setuptools clang-format diff --git a/tools/builder/CMakeLists.txt b/tools/builder/CMakeLists.txt index b7efc8949c..41e4092dc7 100644 --- a/tools/builder/CMakeLists.txt +++ b/tools/builder/CMakeLists.txt @@ -36,6 +36,10 @@ include_directories(${SC_MEMORY_SRC} ${GLIB2_INCLUDE_DIRS}) target_link_libraries(sc-builder-lib sc-memory ${BOOST_LIBS_LIST}) target_link_libraries(sc-builder sc-builder-lib) +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-builder) +endif () + install_targets("/bin" sc-builder sc-builder-lib) sc_codegen(sc-builder-lib ${CMAKE_CURRENT_SOURCE_DIR}/src) diff --git a/tools/builder/src/builder.cpp b/tools/builder/src/builder.cpp index 6614b8ef0f..a76b53adee 100644 --- a/tools/builder/src/builder.cpp +++ b/tools/builder/src/builder.cpp @@ -18,10 +18,7 @@ namespace impl { - -std::unordered_set gSupportedFormats = { - "scs", "scsi" -}; +std::unordered_set gSupportedFormats = {"scs", "scsi"}; std::string NormalizeExt(std::string ext) { @@ -37,7 +34,7 @@ bool IsSupportedFormat(std::string const & fileExt) class ExtParser { public: - void operator() (std::string const & file_path) + void operator()(std::string const & file_path) { if (!file_path.empty()) { @@ -60,17 +57,17 @@ class ExtParser m_params.push_back(nullptr); } - std::vector & GetParams() + std::vector & GetParams() { return m_params; } private: - std::vector m_params; + std::vector m_params; std::vector m_names; }; -} // namespace impl +} // namespace impl Builder::Builder() { @@ -83,7 +80,7 @@ bool Builder::Run(BuilderParams const & params) CollectFiles(); // initialize sc-memory - bool noErrors = true; + bool noErrors = true; impl::ExtParser extParser; extParser(m_params.m_enabledExtPath); @@ -97,7 +94,7 @@ bool Builder::Run(BuilderParams const & params) ScMemory::Initialize(p); m_ctx.reset(new ScMemoryContext(sc_access_lvl_make_min, "Builder")); - + Keynodes::InitGlobal(); std::cout << "Build knowledge base from sources... " << std::endl; @@ -117,8 +114,8 @@ bool Builder::Run(BuilderParams const & params) ScConsole::SetColor(ScConsole::Color::Green); std::cout << "ok" << std::endl; - } - catch(utils::ScException const & e) + } + catch (utils::ScException const & e) { ScConsole::SetColor(ScConsole::Color::Red); std::cout << "failed" << std::endl; @@ -126,22 +123,22 @@ bool Builder::Run(BuilderParams const & params) std::cout << e.Message() << std::endl; noErrors = false; break; - } + } } ScConsole::PrintLine() << ScConsole::Color::Green << "Clean state..."; Translator::Clean(*m_ctx); if (noErrors) - { + { // print statistics ScMemoryContext::Stat const stats = m_ctx->CalculateStat(); auto const allCount = stats.GetAllNum(); - auto const printLine = [](std::string const & name, uint32_t num, float percent) - { - ScConsole::PrintLine() << ScConsole::Color::LightBlue << name << ": " << ScConsole::Color::White << num << "(" << percent << "%)"; + auto const printLine = [](std::string const & name, uint32_t num, float percent) { + ScConsole::PrintLine() << ScConsole::Color::LightBlue << name << ": " << ScConsole::Color::White << num << "(" + << percent << "%)"; }; ScConsole::PrintLine() << ScConsole::Color::White << "Statistics"; @@ -164,20 +161,15 @@ bool Builder::ProcessFile(std::string const & fileName) std::string const ext = utils::StringUtils::GetFileExtension(fileName); if (ext.empty()) { - SC_THROW_EXCEPTION( - utils::ExceptionInvalidState, - "Can't determine file extension " << fileName); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't determine file extension " << fileName); return false; } - std::shared_ptr translator = CreateTranslator(ext); if (!translator) { - SC_THROW_EXCEPTION( - utils::ExceptionInvalidState, - "Can't create translator for a file " << fileName); + SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't create translator for a file " << fileName); return false; } @@ -216,8 +208,8 @@ void Builder::CollectFiles(std::string const & path) try { ++it; - } - catch(...) + } + catch (...) { std::cout << ex.what() << std::endl; return; @@ -258,7 +250,8 @@ void Builder::CollectFiles() } } } - } else + } + else { SC_THROW_EXCEPTION(utils::ExceptionInvalidState, "Can't open file: " << m_params.m_inputPath); } @@ -268,12 +261,9 @@ void Builder::CollectFiles() std::shared_ptr Builder::CreateTranslator(std::string const & fileExt) { std::string const ext = impl::NormalizeExt(fileExt); - + if (ext == "scs" || ext == "scsi") return std::make_shared(*m_ctx); return {}; } - - - diff --git a/tools/builder/src/builder.hpp b/tools/builder/src/builder.hpp index 47736c771e..84dda04436 100644 --- a/tools/builder/src/builder.hpp +++ b/tools/builder/src/builder.hpp @@ -22,9 +22,9 @@ struct BuilderParams //! Path to file with a list of enabled extensions std::string m_enabledExtPath; //! Flag to clear output - bool m_clearOutput:1; + bool m_clearOutput : 1; //! Flag to generate format information based on file extensions - bool m_autoFormatInfo:1; + bool m_autoFormatInfo : 1; //! Path to configuration file std::string m_configFile; }; @@ -35,7 +35,7 @@ class Builder Builder(); bool Run(BuilderParams const & options); - + protected: bool ProcessFile(std::string const & filename); @@ -43,7 +43,7 @@ class Builder void CollectFiles(); std::shared_ptr CreateTranslator(std::string const & fileExt); - + private: std::list m_files; diff --git a/tools/builder/src/main.cpp b/tools/builder/src/main.cpp index 3cf37a00c1..33f665999a 100644 --- a/tools/builder/src/main.cpp +++ b/tools/builder/src/main.cpp @@ -10,23 +10,22 @@ #include -int main(int argc, char *argv[]) try +int main(int argc, char * argv[]) +try { - boost::program_options::options_description options_description("Builder usage"); - options_description.add_options() - ("help", "Display this message") - ("version", "Displays version number") - ("input-path,i", boost::program_options::value(), "Path to directory with sources") - ("output-path,o", boost::program_options::value(), "Path to output directory (repository)") - ("extension-path,e", boost::program_options::value(), "Path to extensions directory") - ("enabled-ext", boost::program_options::value(), "Path to file with enabled extensions") - ("clear-output,c", "Clear output directory (repository) before build") - ("settings,s", boost::program_options::value(), "Path to configuration file for sc-memory") - ("auto-formats,f", "Enable automatic formats info generation"); + options_description.add_options()("help", "Display this message")("version", "Displays version number")( + "input-path,i", boost::program_options::value(), "Path to directory with sources")( + "output-path,o", boost::program_options::value(), "Path to output directory (repository)")( + "extension-path,e", boost::program_options::value(), "Path to extensions directory")( + "enabled-ext", boost::program_options::value(), "Path to file with enabled extensions")( + "clear-output,c", "Clear output directory (repository) before build")( + "settings,s", boost::program_options::value(), "Path to configuration file for sc-memory")( + "auto-formats,f", "Enable automatic formats info generation"); boost::program_options::variables_map vm; - boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(options_description).run(), vm); + boost::program_options::store( + boost::program_options::command_line_parser(argc, argv).options(options_description).run(), vm); boost::program_options::notify(vm); if (vm.count("help") || !vm.count("input-path") || !vm.count("output-path")) diff --git a/tools/codegen/CMakeLists.txt b/tools/codegen/CMakeLists.txt index e344c6e451..38ef7ed6cc 100644 --- a/tools/codegen/CMakeLists.txt +++ b/tools/codegen/CMakeLists.txt @@ -26,3 +26,7 @@ else() endif (${WIN32}) target_link_libraries(sc-code-generator ${LIBCLANG_LIBRARY} ${BOOST_LIBS_LIST}) + +if (${SC_CLANG_FORMAT_CODE}) + target_clangformat_setup(sc-code-generator) +endif () diff --git a/tools/codegen/Parser/Cache.cpp b/tools/codegen/Parser/Cache.cpp index 4ad50e5a71..468306f2cc 100644 --- a/tools/codegen/Parser/Cache.cpp +++ b/tools/codegen/Parser/Cache.cpp @@ -57,7 +57,7 @@ void SourceCache::CheckGenerator(std::string const & fileName) if (it != m_cache.end()) { if (it->second == checksum) - return; // generator doesn't changed + return; // generator doesn't changed } // clear cache, because of new generator diff --git a/tools/codegen/Parser/Cache.hpp b/tools/codegen/Parser/Cache.hpp index 9018a4ba24..a8afc838ad 100644 --- a/tools/codegen/Parser/Cache.hpp +++ b/tools/codegen/Parser/Cache.hpp @@ -19,6 +19,7 @@ class SourceCache static std::string FileChecksum(std::string const & fileName); void Reset(); + private: using CacheMap = std::unordered_map; CacheMap m_cache; diff --git a/tools/codegen/Parser/Cursor.cpp b/tools/codegen/Parser/Cursor.cpp index 012cb49b87..f81124c791 100644 --- a/tools/codegen/Parser/Cursor.cpp +++ b/tools/codegen/Parser/Cursor.cpp @@ -2,7 +2,7 @@ #include "MetaUtils.hpp" -Cursor::Cursor(const CXCursor &handle) +Cursor::Cursor(const CXCursor & handle) : m_handle(handle) { CXSourceLocation loc = clang_getCursorLocation(m_handle); @@ -69,7 +69,6 @@ CX_CXXAccessSpecifier Cursor::GetAccessModifier(void) const return clang_getCXXAccessSpecifier(m_handle); } - CursorType Cursor::GetType(void) const { return clang_getCursorType(m_handle); @@ -89,8 +88,7 @@ Cursor::List Cursor::GetChildren(void) const { List children; - auto visitor = [](CXCursor cursor, CXCursor parent, CXClientData data) - { + auto visitor = [](CXCursor cursor, CXCursor parent, CXClientData data) { auto container = static_cast(data); container->emplace_back(cursor); @@ -106,7 +104,7 @@ Cursor::List Cursor::GetChildren(void) const return children; } -void Cursor::VisitChildren(Visitor visitor, void *data) +void Cursor::VisitChildren(Visitor visitor, void * data) { clang_visitChildren(m_handle, visitor, data); } diff --git a/tools/codegen/Parser/Cursor.hpp b/tools/codegen/Parser/Cursor.hpp index bc29398713..ea46f67ce0 100644 --- a/tools/codegen/Parser/Cursor.hpp +++ b/tools/codegen/Parser/Cursor.hpp @@ -10,7 +10,7 @@ class Cursor typedef std::vector List; typedef CXCursorVisitor Visitor; - Cursor(const CXCursor &handle); + Cursor(const CXCursor & handle); CXCursorKind GetKind(void) const; @@ -25,14 +25,14 @@ class Cursor bool IsStatic(void) const; CX_CXXAccessSpecifier GetAccessModifier(void) const; - //CX_StorageClass GetStorageClass(void) const; + // CX_StorageClass GetStorageClass(void) const; CursorType GetType(void) const; CursorType GetReturnType(void) const; CursorType GetTypedefType(void) const; List GetChildren(void) const; - void VisitChildren(Visitor visitor, void *data = nullptr); + void VisitChildren(Visitor visitor, void * data = nullptr); private: CXCursor m_handle; diff --git a/tools/codegen/Parser/CursorType.cpp b/tools/codegen/Parser/CursorType.cpp index 2a6ac507c2..e2fddd20fb 100644 --- a/tools/codegen/Parser/CursorType.cpp +++ b/tools/codegen/Parser/CursorType.cpp @@ -3,10 +3,9 @@ #include "MetaUtils.hpp" -CursorType::CursorType(const CXType &handle) +CursorType::CursorType(const CXType & handle) : m_handle(handle) { - } std::string CursorType::GetDisplayName(void) const diff --git a/tools/codegen/Parser/CursorType.hpp b/tools/codegen/Parser/CursorType.hpp index 5a95f7291c..d142f1c939 100644 --- a/tools/codegen/Parser/CursorType.hpp +++ b/tools/codegen/Parser/CursorType.hpp @@ -9,7 +9,7 @@ class Cursor; class CursorType { public: - CursorType(const CXType &handle); + CursorType(const CXType & handle); std::string GetDisplayName(void) const; diff --git a/tools/codegen/Parser/LanguageTypes/Class.cpp b/tools/codegen/Parser/LanguageTypes/Class.cpp index 9de1e90a84..315b90a31f 100644 --- a/tools/codegen/Parser/LanguageTypes/Class.cpp +++ b/tools/codegen/Parser/LanguageTypes/Class.cpp @@ -10,21 +10,17 @@ #include -BaseClass::BaseClass(const Cursor &cursor) +BaseClass::BaseClass(const Cursor & cursor) : name(cursor.GetType().GetCanonicalType().GetDisplayName()) { - } bool BaseClass::IsNative() const { - return (name == Classes::Object || - name == Classes::Agent || - name == Classes::AgentAction || - name == Classes::Module); + return (name == Classes::Object || name == Classes::Agent || name == Classes::AgentAction || name == Classes::Module); } -Class::Class(const Cursor &cursor, const Namespace ¤tNamespace) +Class::Class(const Cursor & cursor, const Namespace & currentNamespace) : LanguageType(cursor, currentNamespace) , m_name(cursor.GetDisplayName()) , m_qualifiedName(cursor.GetType().GetDisplayName()) @@ -33,11 +29,10 @@ Class::Class(const Cursor &cursor, const Namespace ¤tNamespace) m_isScObject = false; m_displayName = cursor.GetSpelling(); - for (auto &child : cursor.GetChildren()) + for (auto & child : cursor.GetChildren()) { switch (child.GetKind()) { - case CXCursor_CXXBaseSpecifier: { auto baseClass = new BaseClass(child); @@ -55,7 +50,7 @@ Class::Class(const Cursor &cursor, const Namespace ¤tNamespace) m_metaData.SetProperty(ParserMeta::ParentClass, baseClass->name); } } - break; + break; // constructor case CXCursor_Constructor: @@ -96,7 +91,6 @@ Class::Class(const Cursor &cursor, const Namespace ¤tNamespace) default: break; } - } m_metaData.Check(); @@ -189,10 +183,11 @@ void Class::GenerateStaticFieldsInitCode(std::stringstream & outCode) const if (IsActionAgent()) { outCode << "\t"; - Field::GenerateResolveKeynodeCode(m_metaData.GetNativeString(Props::AgentCommandClass), - "ms_cmdClass_" + m_displayName, - "ScType::NodeConstClass", - outCode); + Field::GenerateResolveKeynodeCode( + m_metaData.GetNativeString(Props::AgentCommandClass), + "ms_cmdClass_" + m_displayName, + "ScType::NodeConstClass", + outCode); outCode << " \\\n"; } } @@ -226,7 +221,9 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const outCode << "\\\nprotected: "; outCode << "\\\n\t" << constrCode; - outCode << m_displayName << "(ScAddr const & cmdClassAddr, char const * name, sc_uint8 accessLvl) : Super(cmdClassAddr, name, accessLvl) {}"; + outCode << m_displayName + << "(ScAddr const & cmdClassAddr, char const * name, sc_uint8 accessLvl) : Super(cmdClassAddr, name, " + "accessLvl) {}"; } else { @@ -257,8 +254,8 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const outCode << "\\\nprotected: "; outCode << "\\\n " << constrCode; outCode << m_displayName << "(char const * name, sc_uint8 accessLvl) : Super(name, accessLvl) {}"; - outCode << "\\\n virtual sc_result Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & otherAddr) override; "; - + outCode << "\\\n virtual sc_result Run(ScAddr const & listenAddr, ScAddr const & edgeAddr, ScAddr const & " + "otherAddr) override; "; } outCode << "\\\nprivate:"; @@ -275,10 +272,13 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const { outCode << "\\\n static ScAddr const & GetCommandClassAddr() { return ms_cmdClass_" << m_displayName << "; }"; } - outCode << "\\\n static bool handler_emit" << "(ScAddr const & addr, ScAddr const & edgeAddr, ScAddr const & otherAddr)"; + outCode << "\\\n static bool handler_emit" + << "(ScAddr const & addr, ScAddr const & edgeAddr, ScAddr const & otherAddr)"; outCode << "\\\n {"; - outCode << "\\\n " << m_displayName << " Instance(" << instConstructParams << "\"" << m_displayName << "\", sc_access_lvl_make_min);"; - outCode << "\\\n " << "return Instance.Run(addr, edgeAddr, otherAddr) == SC_RESULT_OK;"; + outCode << "\\\n " << m_displayName << " Instance(" << instConstructParams << "\"" << m_displayName + << "\", sc_access_lvl_make_min);"; + outCode << "\\\n " + << "return Instance.Run(addr, edgeAddr, otherAddr) == SC_RESULT_OK;"; outCode << "\\\n }"; // register/unregister @@ -286,16 +286,19 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const outCode << "\\\n {"; outCode << "\\\n SC_ASSERT(!ms_event.get(), ());"; outCode << "\\\n SC_ASSERT(!ms_context.get(), ());"; - outCode << "\\\n ms_context.reset(new ScMemoryContext(sc_access_lvl_make_min, \"handler_" << m_displayName << "\"));"; - outCode << "\\\n ms_event.reset(new ScEvent(*ms_context, " << listenAddr << ", " - << eventType << ", &" << m_displayName << "::handler_emit" << "));"; + outCode << "\\\n ms_context.reset(new ScMemoryContext(sc_access_lvl_make_min, \"handler_" << m_displayName + << "\"));"; + outCode << "\\\n ms_event.reset(new ScEvent(*ms_context, " << listenAddr << ", " << eventType << ", &" + << m_displayName << "::handler_emit" + << "));"; outCode << "\\\n if (ms_event.get())"; outCode << "\\\n {"; /// TODO: Use common log system if (isActionAgent) { - outCode << "\\\n SC_LOG_INFO(\"Register agent " << m_displayName << " to action " << m_metaData.GetNativeString(Props::AgentCommandClass) << "\");"; + outCode << "\\\n SC_LOG_INFO(\"Register agent " << m_displayName << " to action " + << m_metaData.GetNativeString(Props::AgentCommandClass) << "\");"; } else { @@ -315,7 +318,7 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const outCode << "\\\n ms_context.reset();"; outCode << "\\\n }"; } - else if (IsModule()) // overrides for modules + else if (IsModule()) // overrides for modules { outCode << "\\\npublic:"; outCode << "\\\n sc_result InitializeGenerated()"; @@ -326,7 +329,6 @@ void Class::GenerateDeclarations(std::stringstream & outCode) const outCode << "\\\n if (!ScAgentInit(false))"; outCode << "\\\n return SC_RESULT_ERROR;"; - outCode << "\\\n return InitializeImpl();"; outCode << "\\\n }"; diff --git a/tools/codegen/Parser/LanguageTypes/Class.hpp b/tools/codegen/Parser/LanguageTypes/Class.hpp index d0e3bdf11e..697788d245 100644 --- a/tools/codegen/Parser/LanguageTypes/Class.hpp +++ b/tools/codegen/Parser/LanguageTypes/Class.hpp @@ -13,7 +13,7 @@ struct BaseClass { - BaseClass(const Cursor &cursor); + BaseClass(const Cursor & cursor); bool IsNative() const; @@ -30,7 +30,7 @@ class Class : public LanguageType friend class Field; public: - Class(const Cursor &cursor, const Namespace ¤tNamespace); + Class(const Cursor & cursor, const Namespace & currentNamespace); bool ShouldGenerate(void) const; bool IsAgent() const; diff --git a/tools/codegen/Parser/LanguageTypes/Constructor.cpp b/tools/codegen/Parser/LanguageTypes/Constructor.cpp index f6e18554a6..bef4a62fc1 100644 --- a/tools/codegen/Parser/LanguageTypes/Constructor.cpp +++ b/tools/codegen/Parser/LanguageTypes/Constructor.cpp @@ -18,8 +18,7 @@ bool Constructor::ShouldCompile() const bool Constructor::isAccessible() const { - return m_accessModifier == CX_CXXPublic && - !m_metaData.GetFlag(kMetaDisable); + return m_accessModifier == CX_CXXPublic && !m_metaData.GetFlag(kMetaDisable); } std::string Constructor::getTemplateParameters() const diff --git a/tools/codegen/Parser/LanguageTypes/Constructor.hpp b/tools/codegen/Parser/LanguageTypes/Constructor.hpp index 8b26af45c5..06445d0de1 100644 --- a/tools/codegen/Parser/LanguageTypes/Constructor.hpp +++ b/tools/codegen/Parser/LanguageTypes/Constructor.hpp @@ -3,7 +3,9 @@ #include "LanguageType.hpp" #include "Invokable.hpp" -class Constructor final : public LanguageType, public Invokable +class Constructor final + : public LanguageType + , public Invokable { public: Constructor(Cursor const & cursor, Namespace const & currentNamespace, class Class * parent); diff --git a/tools/codegen/Parser/LanguageTypes/Field.cpp b/tools/codegen/Parser/LanguageTypes/Field.cpp index e9e4cdc699..84282ac659 100644 --- a/tools/codegen/Parser/LanguageTypes/Field.cpp +++ b/tools/codegen/Parser/LanguageTypes/Field.cpp @@ -13,7 +13,7 @@ Field::Field(Cursor const & cursor, Namespace const & currentNamespace) { auto displayName = m_metaData.GetNativeString(kMetaDisplayName); m_displayName = displayName.empty() ? m_name : displayName; - + m_metaData.Check(); } @@ -26,7 +26,6 @@ bool Field::isAccessible() const { bool const metaFlag = (m_accessModifier == CX_CXXPublic && !m_metaData.GetFlag(kMetaDisable)); return m_hasExplicitGetter || m_hasExplicitSetter || metaFlag; - } bool Field::isGetterAccessible() const @@ -54,19 +53,19 @@ void Field::GenarateInitCode(std::stringstream & outCode) const { if (m_metaData.HasProperty(Props::Keynode)) { - GenerateResolveKeynodeCode(m_metaData.GetNativeString(Props::Keynode), - m_displayName, - GetForceType(m_metaData), - outCode); + GenerateResolveKeynodeCode( + m_metaData.GetNativeString(Props::Keynode), m_displayName, GetForceType(m_metaData), outCode); } else if (m_metaData.HasProperty(Props::Template)) { - GenerateTemplateBuildCode(m_metaData.GetNativeString(Props::Template), - m_displayName, outCode); + GenerateTemplateBuildCode(m_metaData.GetNativeString(Props::Template), m_displayName, outCode); } } -void Field::GenerateTemplateBuildCode(std::string const & sysIdtf, std::string const & displayName, std::stringstream & outCode) +void Field::GenerateTemplateBuildCode( + std::string const & sysIdtf, + std::string const & displayName, + std::stringstream & outCode) { std::string vName = displayName + "_Addr_"; outCode << "ScAddr " << vName << "; "; diff --git a/tools/codegen/Parser/LanguageTypes/Field.hpp b/tools/codegen/Parser/LanguageTypes/Field.hpp index 06f4dfd78e..65aac8763e 100644 --- a/tools/codegen/Parser/LanguageTypes/Field.hpp +++ b/tools/codegen/Parser/LanguageTypes/Field.hpp @@ -15,10 +15,15 @@ class Field final : public LanguageType static std::string GetForceType(MetaDataManager const & metaData); - static void GenerateResolveKeynodeCode(std::string const & sysIdtf, std::string const & displayName, - std::string const & forceType, std::stringstream & outCode); - static void GenerateTemplateBuildCode(std::string const & sysIdtf, std::string const & displayName, - std::stringstream & outCode); + static void GenerateResolveKeynodeCode( + std::string const & sysIdtf, + std::string const & displayName, + std::string const & forceType, + std::stringstream & outCode); + static void GenerateTemplateBuildCode( + std::string const & sysIdtf, + std::string const & displayName, + std::stringstream & outCode); std::string const & GetDisplayName() const; diff --git a/tools/codegen/Parser/LanguageTypes/Function.hpp b/tools/codegen/Parser/LanguageTypes/Function.hpp index c29dff647e..13c63f8de7 100644 --- a/tools/codegen/Parser/LanguageTypes/Function.hpp +++ b/tools/codegen/Parser/LanguageTypes/Function.hpp @@ -3,7 +3,9 @@ #include "LanguageType.hpp" #include "Invokable.hpp" -class Function final : public LanguageType, public Invokable +class Function final + : public LanguageType + , public Invokable { public: Function(Cursor const & cursor, Namespace const & currentNamespace); diff --git a/tools/codegen/Parser/LanguageTypes/Global.cpp b/tools/codegen/Parser/LanguageTypes/Global.cpp index e90cb76a89..be1aa00eb6 100644 --- a/tools/codegen/Parser/LanguageTypes/Global.cpp +++ b/tools/codegen/Parser/LanguageTypes/Global.cpp @@ -19,7 +19,7 @@ Global::Global(Cursor const & cursor, Namespace const & currentNamespace, Class { auto displayName = m_metaData.GetNativeString(kMetaDisplayName); m_displayName = displayName.empty() ? m_qualifiedName : utils::GetQualifiedName(displayName, currentNamespace); - + m_metaData.Check(); } @@ -30,19 +30,15 @@ bool Global::ShouldCompile() const void Global::GenerateInitCode(std::stringstream & outCode) const { - /// TODO: merge with field code generation if (m_metaData.HasProperty(Props::Keynode)) { - Field::GenerateResolveKeynodeCode(m_metaData.GetNativeString(Props::Keynode), - m_displayName, - Field::GetForceType(m_metaData), - outCode); + Field::GenerateResolveKeynodeCode( + m_metaData.GetNativeString(Props::Keynode), m_displayName, Field::GetForceType(m_metaData), outCode); } else if (m_metaData.HasProperty(Props::Template)) { - Field::GenerateTemplateBuildCode(m_metaData.GetNativeString(Props::Template), - m_displayName, outCode); + Field::GenerateTemplateBuildCode(m_metaData.GetNativeString(Props::Template), m_displayName, outCode); } } diff --git a/tools/codegen/Parser/LanguageTypes/Global.hpp b/tools/codegen/Parser/LanguageTypes/Global.hpp index 8bacb008ed..bf75ab96e8 100644 --- a/tools/codegen/Parser/LanguageTypes/Global.hpp +++ b/tools/codegen/Parser/LanguageTypes/Global.hpp @@ -28,6 +28,4 @@ class Global final : public LanguageType std::string m_displayName; std::string m_qualifiedName; std::string m_type; - - }; diff --git a/tools/codegen/Parser/LanguageTypes/Method.hpp b/tools/codegen/Parser/LanguageTypes/Method.hpp index ec0f7c1ed2..bdad83127d 100644 --- a/tools/codegen/Parser/LanguageTypes/Method.hpp +++ b/tools/codegen/Parser/LanguageTypes/Method.hpp @@ -3,7 +3,9 @@ #include "LanguageType.hpp" #include "Invokable.hpp" -class Method final : public LanguageType, public Invokable +class Method final + : public LanguageType + , public Invokable { public: Method(Cursor const & cursor, Namespace const & currentNamespace); diff --git a/tools/codegen/Parser/MacrosManager.cpp b/tools/codegen/Parser/MacrosManager.cpp index 4433c88c1f..1b6b905abe 100644 --- a/tools/codegen/Parser/MacrosManager.cpp +++ b/tools/codegen/Parser/MacrosManager.cpp @@ -4,12 +4,10 @@ MacrosManager::MacrosManager() { - } MacrosManager::~MacrosManager() { - } bool MacrosManager::AddMacros(MacrosInfo const & inMacros) @@ -40,7 +38,7 @@ bool MacrosManager::FindMacros(size_t line, std::string const & fileName, Macros count += classMacros.IsValid() ? 1 : 0; count += propertyMacros.IsValid() ? 1 : 0; - if (count > 1) // invalid state + if (count > 1) // invalid state { std::cout << "More that one SC_... macros used at line " << line << " in " << fileName << std::endl; } @@ -66,7 +64,11 @@ void MacrosManager::Clear() m_macrosStorage = MacrosTypedMap(); } -bool MacrosManager::FindMacrosInternal(MacrosInfo::Type type, size_t line, std::string const & fileName, MacrosInfo & outResult) const +bool MacrosManager::FindMacrosInternal( + MacrosInfo::Type type, + size_t line, + std::string const & fileName, + MacrosInfo & outResult) const { MacrosTypedMap::const_iterator itTyped = m_macrosStorage.find(type); if (itTyped != m_macrosStorage.end()) diff --git a/tools/codegen/Parser/MacrosManager.hpp b/tools/codegen/Parser/MacrosManager.hpp index 18959c52c3..dd5d1f4592 100644 --- a/tools/codegen/Parser/MacrosManager.hpp +++ b/tools/codegen/Parser/MacrosManager.hpp @@ -20,10 +20,14 @@ struct MacrosInfo , m_line(0) , m_column(0) { - } - MacrosInfo(std::string const & name, std::string const & code, size_t line, size_t column, std::string const & filename) + MacrosInfo( + std::string const & name, + std::string const & code, + size_t line, + size_t column, + std::string const & filename) : m_name(name) , m_code(code) , m_line(line) @@ -53,11 +57,10 @@ struct MacrosInfo return (m_type != MT_NONE); } - bool operator == (MacrosInfo const & other) const + bool operator==(MacrosInfo const & other) const { - return (m_name == other.m_name) && (m_fileName == other.m_fileName) - && (m_line == other.m_line) && (m_column == other.m_column) - && (m_type == other.m_type); + return (m_name == other.m_name) && (m_fileName == other.m_fileName) && (m_line == other.m_line) && + (m_column == other.m_column) && (m_type == other.m_type); } static bool RequestProcess(std::string const & name) @@ -65,7 +68,6 @@ struct MacrosInfo return (name == "SC_CLASS") || (name == "SC_PROPERTY") || (name == "SC_GENERATED_BODY"); } - std::string m_name; std::string m_code; Type m_type; @@ -88,11 +90,12 @@ class MacrosManager void Clear(); private: - bool FindMacrosInternal(MacrosInfo::Type type, size_t line, std::string const & fileName, MacrosInfo & outResult) const; + bool FindMacrosInternal(MacrosInfo::Type type, size_t line, std::string const & fileName, MacrosInfo & outResult) + const; private: - using MacrosLineMap = std::map< size_t, MacrosInfo>; - using MacrosTypedMap = std::map< MacrosInfo::Type, MacrosLineMap>; + using MacrosLineMap = std::map; + using MacrosTypedMap = std::map; MacrosTypedMap m_macrosStorage; }; diff --git a/tools/codegen/Parser/Main.cpp b/tools/codegen/Parser/Main.cpp index b3689dff38..6e54b0188e 100644 --- a/tools/codegen/Parser/Main.cpp +++ b/tools/codegen/Parser/Main.cpp @@ -23,15 +23,12 @@ void parse(std::string const & appName, boost::program_options::variables_map co // default arguments options.arguments = { - { - "-x", - "c++", - "-D__SC_REFLECTION_PARSER__", - "-std=c++17", - "-Wno-pragma-once-outside-header", - "-Wno-nullability-completeness" - } - }; + {"-x", + "c++", + "-D__SC_REFLECTION_PARSER__", + "-std=c++17", + "-Wno-pragma-once-outside-header", + "-Wno-nullability-completeness"}}; if (cmdLine.count("flags")) { @@ -71,7 +68,7 @@ void parse(std::string const & appName, boost::program_options::variables_map co } } -int main(int argc, char *argv[]) +int main(int argc, char * argv[]) { auto start = std::chrono::system_clock::now(); @@ -80,46 +77,18 @@ int main(int argc, char *argv[]) { boost::program_options::options_description program("SC Reflection Parser"); - program.add_options() - ( - "help,h", - "Displays help information." - ) - ( - "target,t", - boost::program_options::value()->required(), - "Input target project name." - ) - ( - "source,i", - boost::program_options::value()->required(), - "Source path to parse headers in." - ) - ( - "output,o", - boost::program_options::value()->required(), - "Output path for generated headers." - ) - ( - "build_dir,b", - boost::program_options::value()->default_value("./build"), - "Directory that contains the build intermediate files." - ) - ( - "flags,f", - boost::program_options::value>()->multitoken()->required(), - "Optional list of flags to pass to the compiler." - ) - ( - "debug,d", - boost::program_options::value()->implicit_value(false), - "Display compiler errors" - ) - ( - "cache,c", - boost::program_options::value()->implicit_value(false), - "Force cache usage" - ); + program.add_options()("help,h", "Displays help information.")( + "target,t", boost::program_options::value()->required(), "Input target project name.")( + "source,i", boost::program_options::value()->required(), "Source path to parse headers in.")( + "output,o", boost::program_options::value()->required(), "Output path for generated headers.")( + "build_dir,b", + boost::program_options::value()->default_value("./build"), + "Directory that contains the build intermediate files.")( + "flags,f", + boost::program_options::value>()->multitoken()->required(), + "Optional list of flags to pass to the compiler.")( + "debug,d", boost::program_options::value()->implicit_value(false), "Display compiler errors")( + "cache,c", boost::program_options::value()->implicit_value(false), "Force cache usage"); boost::program_options::variables_map cmdLine; @@ -137,7 +106,7 @@ int main(int argc, char *argv[]) std::string const appName = argv[0]; parse(appName, cmdLine); } - catch (std::exception &e) + catch (std::exception & e) { utils::FatalError(e.what()); } @@ -148,10 +117,8 @@ int main(int argc, char *argv[]) auto duration = std::chrono::system_clock::now() - start; - std::cout << "Completed in " - << std::chrono::duration_cast(duration).count() - << "ms" << std::endl; + std::cout << "Completed in " << std::chrono::duration_cast(duration).count() << "ms" + << std::endl; return EXIT_SUCCESS; } - diff --git a/tools/codegen/Parser/MetaDataManager.cpp b/tools/codegen/Parser/MetaDataManager.cpp index cca256f2f3..d4218cfcd7 100644 --- a/tools/codegen/Parser/MetaDataManager.cpp +++ b/tools/codegen/Parser/MetaDataManager.cpp @@ -7,13 +7,13 @@ MetaDataManager::MetaDataManager(Cursor const & cursor) { m_lineNumber = cursor.GetLineNumber() - 1; - for (auto &child : cursor.GetChildren()) + for (auto & child : cursor.GetChildren()) { if (child.GetKind() != CXCursor_AnnotateAttr) continue; auto const props = ExtractProperties(child); - for (auto &prop : props) + for (auto & prop : props) m_properties[prop.first] = prop.second; } } @@ -75,14 +75,14 @@ std::string MetaDataManager::GetNativeString(std::string const & key) const return ""; static const std::regex quotedString( - // opening quote - "(?:\\s*\")" - // actual string contents - "([^\"]*)" - // closing quote - "\""); + // opening quote + "(?:\\s*\")" + // actual string contents + "([^\"]*)" + // closing quote + "\""); - std::smatch match; + std::smatch match; if (std::regex_match(search->second, match, quotedString)) { @@ -99,23 +99,22 @@ std::vector MetaDataManager::ExtractProperties(Cursor std::vector properties; static const std::regex propertyList( - // property name - "([a-zA-Z\\:]+)" - // optional whitespace before - "(?:\\s*)" - // constructor - "(" - // opening paren - "\\(" - // arguments - "([^\\)]*)" - // closing paren - "\\)" - // end constructor - ")?" - // optional comma/whitespace - "(?:(\\s|,)*)" - ); + // property name + "([a-zA-Z\\:]+)" + // optional whitespace before + "(?:\\s*)" + // constructor + "(" + // opening paren + "\\(" + // arguments + "([^\\)]*)" + // closing paren + "\\)" + // end constructor + ")?" + // optional comma/whitespace + "(?:(\\s|,)*)"); auto const meta = cursor.GetDisplayName(); auto start = meta.cbegin(); @@ -171,7 +170,8 @@ void MetaDataManager::Check() const if (hasTemplate && GetNativeString(Props::Template).empty()) { - EMIT_ERROR_LINE("Can't use empty " << Props::Template << ". You should specify system identifier of sc-structure in it"); + EMIT_ERROR_LINE( + "Can't use empty " << Props::Template << ". You should specify system identifier of sc-structure in it"); } std::string const cmdClass = GetNativeString(Props::AgentCommandClass); @@ -194,7 +194,5 @@ void MetaDataManager::Check() const { EMIT_ERROR_LINE("Don't use empty " << Props::AgentCommandClass); } - } - } diff --git a/tools/codegen/Parser/MetaDataManager.hpp b/tools/codegen/Parser/MetaDataManager.hpp index 78dfdf4e4e..0f04eba762 100644 --- a/tools/codegen/Parser/MetaDataManager.hpp +++ b/tools/codegen/Parser/MetaDataManager.hpp @@ -35,5 +35,4 @@ class MetaDataManager private: std::unordered_map m_properties; size_t m_lineNumber; - }; diff --git a/tools/codegen/Parser/MetaUtils.cpp b/tools/codegen/Parser/MetaUtils.cpp index 889195f14f..44511789ee 100644 --- a/tools/codegen/Parser/MetaUtils.cpp +++ b/tools/codegen/Parser/MetaUtils.cpp @@ -10,8 +10,7 @@ namespace utils { - -void ToString(const CXString &str, std::string &output) +void ToString(const CXString & str, std::string & output) { auto cstr = clang_getCString(str); @@ -32,16 +31,16 @@ std::string GetQualifiedName(const std::string & displayName, const Namespace & return name; } -std::string GetQualifiedName(const Cursor &cursor, const Namespace ¤tNamespace) +std::string GetQualifiedName(const Cursor & cursor, const Namespace & currentNamespace) { return GetQualifiedName(cursor.GetSpelling(), currentNamespace); } -void FatalError(const std::string &error) +void FatalError(const std::string & error) { std::cerr << "Error: " << error << std::endl; exit(EXIT_FAILURE); } -} // namespace utils +} // namespace utils diff --git a/tools/codegen/Parser/MetaUtils.hpp b/tools/codegen/Parser/MetaUtils.hpp index 260122f5d2..0916413382 100644 --- a/tools/codegen/Parser/MetaUtils.hpp +++ b/tools/codegen/Parser/MetaUtils.hpp @@ -7,11 +7,11 @@ class Cursor; namespace utils { -void ToString(const CXString &str, std::string &output); +void ToString(const CXString & str, std::string & output); std::string GetQualifiedName(std::string const & displayName, Namespace const & currentNamespace); std::string GetQualifiedName(Cursor const & cursor, Namespace const & currentNamespace); -void FatalError(const std::string &error); -} +void FatalError(const std::string & error); +} // namespace utils diff --git a/tools/codegen/Parser/ReflectionParser.cpp b/tools/codegen/Parser/ReflectionParser.cpp index fa2c8e1c13..7c3da79612 100644 --- a/tools/codegen/Parser/ReflectionParser.cpp +++ b/tools/codegen/Parser/ReflectionParser.cpp @@ -20,8 +20,7 @@ namespace impl { - -void displayDiagnostics (CXTranslationUnit tu) +void displayDiagnostics(CXTranslationUnit tu) { if (tu == 0) { @@ -32,18 +31,18 @@ void displayDiagnostics (CXTranslationUnit tu) int const numDiagnostics = clang_getNumDiagnostics(tu); for (int i = 0; i < numDiagnostics; ++i) { - auto const diagnostic = clang_getDiagnostic (tu, i); - auto const string = clang_formatDiagnostic (diagnostic, clang_defaultDiagnosticDisplayOptions()); + auto const diagnostic = clang_getDiagnostic(tu, i); + auto const string = clang_formatDiagnostic(diagnostic, clang_defaultDiagnosticDisplayOptions()); - std::cerr << clang_getCString (string) << std::endl; - clang_disposeString (string); - clang_disposeDiagnostic (diagnostic); + std::cerr << clang_getCString(string) << std::endl; + clang_disposeString(string); + clang_disposeDiagnostic(diagnostic); } } -} // namespace impl +} // namespace impl -ReflectionParser::ReflectionParser(const ReflectionOptions &options) +ReflectionParser::ReflectionParser(const ReflectionOptions & options) : m_options(options) , m_index(nullptr) , m_translationUnit(nullptr) @@ -148,7 +147,6 @@ void ReflectionParser::Parse() m_sourceCache->Save(); } - void ReflectionParser::Clear() { m_currentFile = ""; @@ -173,7 +171,7 @@ bool ReflectionParser::ProcessFile(std::string const & fileName, bool inProcessM std::vector arguments; - for (auto &argument : m_options.arguments) + for (auto & argument : m_options.arguments) { // unescape flags boost::algorithm::replace_all(argument, "\\-", "-"); @@ -181,13 +179,7 @@ bool ReflectionParser::ProcessFile(std::string const & fileName, bool inProcessM } m_translationUnit = clang_createTranslationUnitFromSourceFile( - m_index, - fileName.c_str(), - static_cast(arguments.size()), - arguments.data(), - 0, - nullptr - ); + m_index, fileName.c_str(), static_cast(arguments.size()), arguments.data(), 0, nullptr); if (m_options.displayDiagnostic) impl::displayDiagnostics(m_translationUnit); @@ -240,7 +232,6 @@ bool ReflectionParser::ProcessFile(std::string const & fileName, bool inProcessM clang_disposeIndex(m_index); clang_disposeTranslationUnit(m_translationUnit); - } catch (Exception e) { @@ -250,7 +241,6 @@ bool ReflectionParser::ProcessFile(std::string const & fileName, bool inProcessM EMIT_ERROR(e.GetDescription()); } - return true; } @@ -287,9 +277,9 @@ bool ReflectionParser::ContainsModule() const return false; } -void ReflectionParser::buildClasses(const Cursor &cursor, Namespace ¤tNamespace) +void ReflectionParser::buildClasses(const Cursor & cursor, Namespace & currentNamespace) { - for (auto &child : cursor.GetChildren()) + for (auto & child : cursor.GetChildren()) { // skip classes from other files if (!IsInCurrentFile(child)) @@ -305,7 +295,6 @@ void ReflectionParser::buildClasses(const Cursor &cursor, Namespace ¤tName } } - void ReflectionParser::DumpTree(Cursor const & cursor, size_t level, std::stringstream & outData) { outData << "\n"; @@ -314,87 +303,87 @@ void ReflectionParser::DumpTree(Cursor const & cursor, size_t level, std::string outData << cursor.GetDisplayName() << ", " << cursor.GetKind(); - for (auto &child : cursor.GetChildren()) + for (auto & child : cursor.GetChildren()) { DumpTree(child, level + 1, outData); } } -//void ReflectionParser::buildGlobals(const Cursor &cursor, Namespace ¤tNamespace) +// void ReflectionParser::buildGlobals(const Cursor &cursor, Namespace ¤tNamespace) //{ -// for (auto &child : cursor.GetChildren()) -// { -// // skip static globals (hidden) -// if (child.GetStorageClass() == CX_SC_Static) -// continue; +// for (auto &child : cursor.GetChildren()) +// { +// // skip static globals (hidden) +// if (child.GetStorageClass() == CX_SC_Static) +// continue; // -// auto kind = child.GetKind(); +// auto kind = child.GetKind(); // -// // variable declaration, which is global -// if (kind == CXCursor_VarDecl) -// { -// m_globals.emplace_back( -// new Global(child, currentNamespace) -// ); -// } +// // variable declaration, which is global +// if (kind == CXCursor_VarDecl) +// { +// m_globals.emplace_back( +// new Global(child, currentNamespace) +// ); +// } // -// RECURSE_NAMESPACES(kind, child, buildGlobals, currentNamespace); -// } -//} +// RECURSE_NAMESPACES(kind, child, buildGlobals, currentNamespace); +// } +// } // -//void ReflectionParser::buildGlobalFunctions(const Cursor &cursor, Namespace ¤tNamespace) +// void ReflectionParser::buildGlobalFunctions(const Cursor &cursor, Namespace ¤tNamespace) //{ -// for (auto &child : cursor.GetChildren()) -// { -// // skip static globals (hidden) -// if (child.GetStorageClass() == CX_SC_Static) -// continue; +// for (auto &child : cursor.GetChildren()) +// { +// // skip static globals (hidden) +// if (child.GetStorageClass() == CX_SC_Static) +// continue; // -// auto kind = child.GetKind(); +// auto kind = child.GetKind(); // -// // function declaration, which is global -// if (kind == CXCursor_FunctionDecl) -// { -// m_globalFunctions.emplace_back(new Function(child, currentNamespace)); -// } +// // function declaration, which is global +// if (kind == CXCursor_FunctionDecl) +// { +// m_globalFunctions.emplace_back(new Function(child, currentNamespace)); +// } // -// RECURSE_NAMESPACES( -// kind, -// child, -// buildGlobalFunctions, -// currentNamespace -// ); -// } -//} +// RECURSE_NAMESPACES( +// kind, +// child, +// buildGlobalFunctions, +// currentNamespace +// ); +// } +// } // -//void ReflectionParser::buildEnums(const Cursor &cursor, Namespace ¤tNamespace) +// void ReflectionParser::buildEnums(const Cursor &cursor, Namespace ¤tNamespace) //{ -// for (auto &child : cursor.GetChildren()) -// { -// auto kind = child.GetKind(); +// for (auto &child : cursor.GetChildren()) +// { +// auto kind = child.GetKind(); // -// // actual definition and an enum -// if (child.IsDefinition() && kind == CXCursor_EnumDecl) -// { -// // anonymous enum if the underlying type display name contains this -// if (child.GetType().GetDisplayName().find("anonymous enum at") -// != std::string::npos) -// { -// // anonymous enums are just loaded as -// // globals with each of their values -// Enum::LoadAnonymous(m_globals, child, currentNamespace); -// } -// else -// { -// m_enums.emplace_back( -// new Enum(child, currentNamespace) -// ); -// } -// } +// // actual definition and an enum +// if (child.IsDefinition() && kind == CXCursor_EnumDecl) +// { +// // anonymous enum if the underlying type display name contains this +// if (child.GetType().GetDisplayName().find("anonymous enum at") +// != std::string::npos) +// { +// // anonymous enums are just loaded as +// // globals with each of their values +// Enum::LoadAnonymous(m_globals, child, currentNamespace); +// } +// else +// { +// m_enums.emplace_back( +// new Enum(child, currentNamespace) +// ); +// } +// } // -// RECURSE_NAMESPACES(kind, child, buildEnums, currentNamespace); -// } -//} +// RECURSE_NAMESPACES(kind, child, buildEnums, currentNamespace); +// } +// } std::string ReflectionParser::GetFileExtension(std::string const & fileName) { @@ -428,4 +417,3 @@ std::string ReflectionParser::GetFileID(std::string const & fileName) return res; } - diff --git a/tools/codegen/Parser/ReflectionParser.hpp b/tools/codegen/Parser/ReflectionParser.hpp index e306b25a98..5e3c2734a0 100644 --- a/tools/codegen/Parser/ReflectionParser.hpp +++ b/tools/codegen/Parser/ReflectionParser.hpp @@ -14,7 +14,6 @@ class ReflectionParser final { public: - explicit ReflectionParser(ReflectionOptions const & options); void Parse(); diff --git a/tools/codegen/Parser/ReservedTypes.hpp b/tools/codegen/Parser/ReservedTypes.hpp index c71c3c2fb5..1ca2874761 100644 --- a/tools/codegen/Parser/ReservedTypes.hpp +++ b/tools/codegen/Parser/ReservedTypes.hpp @@ -4,7 +4,6 @@ namespace Props { - const std::string Body = "GenBody"; const std::string Keynode = "Keynode"; const std::string Template = "Template"; @@ -14,21 +13,19 @@ const std::string AgentCommandClass = "CmdClass"; const std::string Event = "Event"; const std::string LoadOrder = "LoadOrder"; -} // namespace Props +} // namespace Props namespace Classes { - const std::string Object = "ScObject"; const std::string Agent = "ScAgent"; const std::string AgentAction = "ScAgentAction"; const std::string Module = "ScModule"; -} // namespace Classes +} // namespace Classes namespace ParserMeta { - const std::string ParentClass = "ParentClass"; -} // namespace ParserMeta +} // namespace ParserMeta diff --git a/tools/codegen/Parser/Sha256.cpp b/tools/codegen/Parser/Sha256.cpp index 4711136ff9..fb672a0837 100644 --- a/tools/codegen/Parser/Sha256.cpp +++ b/tools/codegen/Parser/Sha256.cpp @@ -3,46 +3,42 @@ #include #include -const unsigned int SHA256::sha256_k[64] = //UL = uint32 -{ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, -0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, -0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, -0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, -0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, -0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, -0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, -0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, -0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, -0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, -0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, -0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, -0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, -0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, -0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, -0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; +const unsigned int SHA256::sha256_k[64] = // UL = uint32 + {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; -void SHA256::transform(const unsigned char *message, unsigned int block_nb) +void SHA256::transform(const unsigned char * message, unsigned int block_nb) { uint32 w[64]; uint32 wv[8]; uint32 t1, t2; - const unsigned char *sub_block; + const unsigned char * sub_block; int i; int j; - for (i = 0; i < (int)block_nb; i++) { + for (i = 0; i < (int)block_nb; i++) + { sub_block = message + (i << 6); - for (j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) + { SHA2_PACK32(&sub_block[j << 2], &w[j]); } - for (j = 16; j < 64; j++) { + for (j = 16; j < 64; j++) + { w[j] = SHA256_F4(w[j - 2]) + w[j - 7] + SHA256_F3(w[j - 15]) + w[j - 16]; } - for (j = 0; j < 8; j++) { + for (j = 0; j < 8; j++) + { wv[j] = m_h[j]; } - for (j = 0; j < 64; j++) { - t1 = wv[7] + SHA256_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) - + sha256_k[j] + w[j]; + for (j = 0; j < 64; j++) + { + t1 = wv[7] + SHA256_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; @@ -53,7 +49,8 @@ void SHA256::transform(const unsigned char *message, unsigned int block_nb) wv[1] = wv[0]; wv[0] = t1 + t2; } - for (j = 0; j < 8; j++) { + for (j = 0; j < 8; j++) + { m_h[j] += wv[j]; } } @@ -73,15 +70,16 @@ void SHA256::init() m_tot_len = 0; } -void SHA256::update(const unsigned char *message, unsigned int len) +void SHA256::update(const unsigned char * message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; - const unsigned char *shifted_message; + const unsigned char * shifted_message; tmp_len = SHA224_256_BLOCK_SIZE - m_len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&m_block[m_len], message, rem_len); - if (m_len + len < SHA224_256_BLOCK_SIZE) { + if (m_len + len < SHA224_256_BLOCK_SIZE) + { m_len += len; return; } @@ -96,21 +94,21 @@ void SHA256::update(const unsigned char *message, unsigned int len) m_tot_len += (block_nb + 1) << 6; } -void SHA256::final(unsigned char *digest) +void SHA256::final(unsigned char * digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; int i; - block_nb = (1 + ((SHA224_256_BLOCK_SIZE - 9) - < (m_len % SHA224_256_BLOCK_SIZE))); + block_nb = (1 + ((SHA224_256_BLOCK_SIZE - 9) < (m_len % SHA224_256_BLOCK_SIZE))); len_b = (m_tot_len + m_len) << 3; pm_len = block_nb << 6; memset(m_block + m_len, 0, pm_len - m_len); m_block[m_len] = 0x80; SHA2_UNPACK32(len_b, m_block + pm_len - 4); transform(m_block, block_nb); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) + { SHA2_UNPACK32(m_h[i], &digest[i << 2]); } } @@ -122,12 +120,12 @@ std::string sha256(std::string input) SHA256 ctx = SHA256(); ctx.init(); - ctx.update((unsigned char*)input.c_str(), input.length()); + ctx.update((unsigned char *)input.c_str(), input.length()); ctx.final(digest); char buf[2 * SHA256::DIGEST_SIZE + 1]; buf[2 * SHA256::DIGEST_SIZE] = 0; - for (size_t i = 0; i < SHA256::DIGEST_SIZE; i++) + for (size_t i = 0; i < SHA256::DIGEST_SIZE; i++) sprintf(buf + i * 2, "%02x", digest[i]); return std::string(buf); } diff --git a/tools/codegen/Parser/Sha256.hpp b/tools/codegen/Parser/Sha256.hpp index d4a0e40a77..0fe2c3f561 100644 --- a/tools/codegen/Parser/Sha256.hpp +++ b/tools/codegen/Parser/Sha256.hpp @@ -1,89 +1,88 @@ #pragma once /* -* Updated to C++, zedwood.com 2012 -* Based on Olivier Gay's version -* See Modified BSD License below: -* -* FIPS 180-2 SHA-224/256/384/512 implementation -* Issue date: 04/30/2005 -* http://www.ouah.org/ogay/sha2/ -* -* Copyright (C) 2005, 2007 Olivier Gay -* 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. -* 3. Neither the name of the project nor the names of its contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. -*/ + * Updated to C++, zedwood.com 2012 + * Based on Olivier Gay's version + * See Modified BSD License below: + * + * FIPS 180-2 SHA-224/256/384/512 implementation + * Issue date: 04/30/2005 + * http://www.ouah.org/ogay/sha2/ + * + * Copyright (C) 2005, 2007 Olivier Gay + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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 class SHA256 { protected: - typedef unsigned char uint8; - typedef unsigned int uint32; - typedef unsigned long long uint64; + typedef unsigned char uint8; + typedef unsigned int uint32; + typedef unsigned long long uint64; + + const static uint32 sha256_k[]; + static const unsigned int SHA224_256_BLOCK_SIZE = (512 / 8); - const static uint32 sha256_k[]; - static const unsigned int SHA224_256_BLOCK_SIZE = (512 / 8); public: - void init(); - void update(const unsigned char *message, unsigned int len); - void final(unsigned char *digest); - static const unsigned int DIGEST_SIZE = (256 / 8); + void init(); + void update(const unsigned char * message, unsigned int len); + void final(unsigned char * digest); + static const unsigned int DIGEST_SIZE = (256 / 8); protected: - void transform(const unsigned char *message, unsigned int block_nb); - unsigned int m_tot_len; - unsigned int m_len; - unsigned char m_block[2 * SHA224_256_BLOCK_SIZE]; - uint32 m_h[8]; + void transform(const unsigned char * message, unsigned int block_nb); + unsigned int m_tot_len; + unsigned int m_len; + unsigned char m_block[2 * SHA224_256_BLOCK_SIZE]; + uint32 m_h[8]; }; std::string sha256(std::string input); -#define SHA2_SHFR(x, n) (x >> n) -#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) -#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) -#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z)) +#define SHA2_SHFR(x, n) (x >> n) +#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z)) #define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) -#define SHA256_F1(x) (SHA2_ROTR(x, 2) ^ SHA2_ROTR(x, 13) ^ SHA2_ROTR(x, 22)) -#define SHA256_F2(x) (SHA2_ROTR(x, 6) ^ SHA2_ROTR(x, 11) ^ SHA2_ROTR(x, 25)) -#define SHA256_F3(x) (SHA2_ROTR(x, 7) ^ SHA2_ROTR(x, 18) ^ SHA2_SHFR(x, 3)) +#define SHA256_F1(x) (SHA2_ROTR(x, 2) ^ SHA2_ROTR(x, 13) ^ SHA2_ROTR(x, 22)) +#define SHA256_F2(x) (SHA2_ROTR(x, 6) ^ SHA2_ROTR(x, 11) ^ SHA2_ROTR(x, 25)) +#define SHA256_F3(x) (SHA2_ROTR(x, 7) ^ SHA2_ROTR(x, 18) ^ SHA2_SHFR(x, 3)) #define SHA256_F4(x) (SHA2_ROTR(x, 17) ^ SHA2_ROTR(x, 19) ^ SHA2_SHFR(x, 10)) -#define SHA2_UNPACK32(x, str) \ -{ \ - *((str) + 3) = (uint8) ((x) ); \ - *((str) + 2) = (uint8) ((x) >> 8); \ - *((str) + 1) = (uint8) ((x) >> 16); \ - *((str) + 0) = (uint8) ((x) >> 24); \ -} -#define SHA2_PACK32(str, x) \ -{ \ - *(x) = ((uint32) *((str) + 3) ) \ - | ((uint32) *((str) + 2) << 8) \ - | ((uint32) *((str) + 1) << 16) \ - | ((uint32) *((str) + 0) << 24); \ -} +#define SHA2_UNPACK32(x, str) \ + { \ + *((str) + 3) = (uint8)((x)); \ + *((str) + 2) = (uint8)((x) >> 8); \ + *((str) + 1) = (uint8)((x) >> 16); \ + *((str) + 0) = (uint8)((x) >> 24); \ + } +#define SHA2_PACK32(str, x) \ + { \ + *(x) = ((uint32) * ((str) + 3)) | ((uint32) * ((str) + 2) << 8) | ((uint32) * ((str) + 1) << 16) | \ + ((uint32) * ((str) + 0) << 24); \ + } diff --git a/tools/codegen/Parser/Types.hpp b/tools/codegen/Parser/Types.hpp index d6e4755cba..092201420b 100644 --- a/tools/codegen/Parser/Types.hpp +++ b/tools/codegen/Parser/Types.hpp @@ -10,7 +10,7 @@ using Namespace = std::vector; -class Exception final: public std::exception +class Exception final : public std::exception { public: Exception(std::string const & descr) @@ -22,13 +22,18 @@ class Exception final: public std::exception { return m_description; } + private: std::string m_description; }; #ifndef EMIT_ERROR -#define EMIT_ERROR(__desc) \ -{ std::stringstream ss; ss << __desc; throw Exception(ss.str()); } +# define EMIT_ERROR(__desc) \ + { \ + std::stringstream ss; \ + ss << __desc; \ + throw Exception(ss.str()); \ + } #endif typedef std::list tStringList;