diff --git a/.github/workflows/ContinuousIntegration.yml b/.github/workflows/ContinuousIntegration.yml index 86bd741ee..f57079935 100644 --- a/.github/workflows/ContinuousIntegration.yml +++ b/.github/workflows/ContinuousIntegration.yml @@ -21,6 +21,12 @@ jobs: build_type: [ Debug, Release ] steps: + - name: Install hdf5 libraries for Linux + if: matrix.os == 'ubuntu-18.04' + run: sudo apt-get install libhdf5-dev + - name: Install hdf5 libraries for MacOS + if: matrix.os == 'macos-10.15' + run: brew install hdf5 - name: which CXX run: | which ${{matrix.cxx}} diff --git a/CMakeLists.txt b/CMakeLists.txt index a33c52da1..860548540 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ target_link_libraries( GNDStk INTERFACE catch-adapter INTERFACE pugixml-adapter INTERFACE nlohmann_json::nlohmann_json + INTERFACE HighFive ) add_executable( json2class.exe diff --git a/autogen/.gitignore b/autogen/.gitignore deleted file mode 100644 index 321656c44..000000000 --- a/autogen/.gitignore +++ /dev/null @@ -1 +0,0 @@ -json2class.exe diff --git a/autogen/changes.json b/autogen/changes.json index 87832d157..77733b650 100644 --- a/autogen/changes.json +++ b/autogen/changes.json @@ -11,7 +11,6 @@ "metadata": { "type": { "Boolean": "bool", - "string": "std::string", "encoding": "enums::Encoding", "frame": "enums::Frame", "interaction": "enums::Interaction", diff --git a/autogen/json2class.cpp b/autogen/json2class.cpp index ff4a91686..abfeef96e 100644 --- a/autogen/json2class.cpp +++ b/autogen/json2class.cpp @@ -4,8 +4,8 @@ // ----------------------------------------------------------------------------- #include "GNDStk.hpp" -#include "cstring" -using namespace njoy::GNDStk::core; +#include +using namespace njoy::GNDStk; // Report cases of nodes that have no metadata, and zero or one child node(s). // Where these exist, a simplification of the spec may be worth considering. @@ -20,9 +20,7 @@ const bool singletons = true; // KeyValue // Too bad the JSON library doesn't provide this more straightforwardly using KeyValue = nlohmann::detail::iteration_proxy_value< - nlohmann::detail::iter_impl< - const nlohmann::basic_json<> - > + nlohmann::detail::iter_impl >; // NamespaceAndClass @@ -57,12 +55,12 @@ struct Class2Dependencies { // InfoMetadata struct InfoMetadata { - // A .json spec can make a metadatum be: + // A JSON spec can make a metadatum be: // - a std::optional, or // - a GNDStk::defaulted // but (in contrast with child nodes) can't make it be a vector of metadata. // An individual metadatum may be a vector in its own right, as in an XML - // construct such as (so that meta is a vector of + // construct such as (so that meta is a vector of // integers). We mean here that there isn't a vector of such [meta] entries, // and shouldn't be (XML wouldn't allow it). std::string name; @@ -75,7 +73,7 @@ struct InfoMetadata { // InfoChildren struct InfoChildren { - // A .json spec can make a child node be: + // A JSON spec can make a child node be: // - a std::optional, and/or // - a std::vector // but can't make it be a GNDStk::defaulted. (The use of a default value for @@ -156,26 +154,28 @@ struct PerClass { // Overarching data structure reflecting all of the autogenerator's input // as well as various processed information struct InfoSpecs { - // From the .json file on the command line + // From the JSON file on the command line + std::string Path; + std::string Project; + std::string Version; std::string JSONDir; std::vector JSONFiles; - std::string GNDSDir; - std::string Version; // Version, but with '_' in place of '.' std::string VersionUnderscore; // Directory-prefixed names std::string hppVersion; // hpp file for this version - std::string hppKey; // hpp file for this version's Meta<>/Child<> keys + std::string hppKey; // hpp file for this version's Meta and Child keys - // Changes to apply to a metadatum's or child node's name. - // Example: "double" (GNDS v1.9 does have this) to "Double" for C++. + // Changes to apply to a metadatum's name or a child node's name. + // Example: "double" (GNDS v1.9 actually has "double") to "Double" for C++. std::map mapName; // Changes to apply to metadata/attribute type and default. // Examples: "Boolean" to "bool", "interpolation" to "enums::Interpolation". - std::map mapMetaType; + // We'll give a string ==> std::string type change as a freebie. :-) + std::map mapMetaType = {{"string","std::string"}}; std::map mapMetaDefault; // For each class in the input JSON specifications, the namespace(s) @@ -194,7 +194,7 @@ struct InfoSpecs { std::map namespace2data; // Map from namespace::class to information about the class - std::map class2data; + nlohmann::ordered_map class2data; }; @@ -206,9 +206,7 @@ struct InfoSpecs { // Print text describing an action the code is about to take void action(const std::string &str) { - std::cout - << "\n" - << colors::plain::blue << str << "..." << colors::reset << std::endl; + std::cout << colors::plain::blue << str << colors::reset << std::endl; } // Is the string all whitespace? @@ -286,10 +284,10 @@ std::string replace(const std::string &str, const char from, const char to) // Stringify JSON // See: https://github.com/nlohmann/json/issues/642 -std::string stringify(const nlohmann::json &j) +std::string stringify(const orderedJSON &j) { const auto tmp = j.dump(); - return j.type() == nlohmann::json::value_t::string + return j.type() == orderedJSON::value_t::string ? tmp.substr(1, tmp.size()-2) : tmp; } @@ -322,6 +320,18 @@ bool isClass(const KeyValue &keyval) return true; } +std::string getTimes(const orderedJSON &value) +{ + const std::string times = "times"; // shorter, less easily misspelled + const std::string occurrence = "occurrence"; // accept; used in GNDS specs + + // need exactly one - not neither, not both + assert(value.contains(times) != value.contains(occurrence)); + + return value.contains(times) + ? value[times] + : value[occurrence]; +} // ----------------------------------------------------------------------------- @@ -382,7 +392,7 @@ std::string namePython(const std::string &name) // ----------------------------------------------------------------------------- // Get the JSON's "namespace" -std::string getFileNamespace(const nlohmann::json &j) +std::string getFileNamespace(const orderedJSON &j) { return j.contains("__namespace__") ? j["__namespace__"] @@ -390,7 +400,7 @@ std::string getFileNamespace(const nlohmann::json &j) } // Get the JSON's "type", with any relevant specs.mapMetaType entry applied -std::string getMetadatumType(const nlohmann::json &j, const InfoSpecs &specs) +std::string getMetadatumType(const orderedJSON &j, const InfoSpecs &specs) { const std::string type = j["type"]; const auto it = specs.mapMetaType.find(type); @@ -400,9 +410,9 @@ std::string getMetadatumType(const nlohmann::json &j, const InfoSpecs &specs) // Determine to what namespace childClass belongs. Context: we're (1) in a JSON // spec with namespace parent.nsname, (2) in a parent node named parent.clname, // and (3) wish to determine the proper namespace for the parent's child node -// named "child". Parameter j is the JSON value ({...}) for this child node. +// named childClass. Parameter j is the JSON value ({...}) for this child node. std::string getChildNamespace( - const nlohmann::json &j, const InfoSpecs &specs, + const orderedJSON &j, const InfoSpecs &specs, const PerClass &per, const std::string &childClass ) { // childClass' namespace... @@ -414,7 +424,7 @@ std::string getChildNamespace( // ...isn't given, and this child isn't in any of the JSONs :-( if (specs.class2nspace.count(childClass) == 0) { log::warning( - "{}::{} has child of unknown class {}", + "{}::{} has a child of unknown class {}", per.nsname, per.clname, childClass ); return "unknownNamespace"; @@ -429,7 +439,13 @@ std::string getChildNamespace( const auto range = specs.class2nspace.equal_range(childClass); for (auto it = range.first; it != range.second; ++it) if (it->second == per.nsname) { - // fixme: a *warning* might be in order, re: our assumption + log::warning( + "{}::{} has a child {} that appears in the present\n" + "namespace but also in one or more other namespaces. We'll\n" + "assume that the one in the present namespace is intended.\n" + "If this is wrong, please provide a \"namespace\" entry.", + per.nsname, per.clname, childClass + ); return per.nsname; } @@ -440,7 +456,7 @@ std::string getChildNamespace( for (auto it = range.first; it != range.second; ++it) warn << (count++ == 0 ? "" : ", ") << it->second; log::warning( - "{}::{} has child of ambiguous class {}.\n" + "{}::{} has a child of ambiguous class {}.\n" "Child class {} appears in all of the following namespaces:\n{}", per.nsname, per.clname, childClass, childClass, warn.str() ); @@ -456,7 +472,7 @@ std::string getChildNamespace( // getClassMetadata void getClassMetadata( - const nlohmann::json &j, const InfoSpecs &specs, PerClass &per + const orderedJSON &j, const InfoSpecs &specs, PerClass &per ) { for (const auto &field : j.items()) { const auto &metaRHS = field.value(); @@ -478,6 +494,11 @@ void getClassMetadata( }; if (m.defaultValue != "") { // If it has a default, then presumably it isn't required... + // fixme Should print a real, useful error message here. The mistake + // in question is something a user could easily make!! Look at other + // assert()s in this file as well; assert should be more for internal + // sanity checks than for diagnostic messages, as they aren't very + // helpful to typical users. assert(!metaRHS["required"]); } @@ -505,15 +526,15 @@ void getClassMetadata( // getClassChildren void getClassChildren( - const nlohmann::json &j, const InfoSpecs &specs, + const orderedJSON &j, const InfoSpecs &specs, PerClass &per, Class2Dependencies &dep ) { for (const auto &field : j.items()) { const auto &elemRHS = field.value(); // Choice children are handled elsewhere - const std::string occ = elemRHS["occurrence"]; - if (occ == "choice" || occ == "choice+" || occ == "choice2+") + const std::string times = getTimes(elemRHS); + if (times == "choice" || times == "choice+" || times == "choice2+") continue; // Name @@ -531,7 +552,7 @@ void getClassChildren( const std::string optSuffix = c.isOptional ? ">" : ""; // Vector? - c.isVector = occ == "0+" || occ == "1+" || occ == "2+"; + c.isVector = times == "0+" || times == "1+" || times == "2+"; const std::string vecPrefix = c.isVector ? "std::vector<" : ""; const std::string vecSuffix = c.isVector ? ">" : ""; @@ -563,7 +584,7 @@ void getClassChildren( // getClassVariants void getClassVariants( - const nlohmann::json &j, const InfoSpecs &specs, + const orderedJSON &j, const InfoSpecs &specs, PerClass &per, Class2Dependencies &dep ) { // Initialize per.variants, a vector that has the "choice" @@ -587,8 +608,8 @@ void getClassVariants( for (const auto &field : j.items()) { // Is it a choice child? const auto &elemRHS = field.value(); - const std::string occ = elemRHS["occurrence"]; - if (occ != "choice" && occ != "choice+" && occ != "choice2+") + const std::string times = getTimes(elemRHS); + if (times != "choice" && times != "choice+" && times != "choice2+") continue; // Variant name @@ -602,15 +623,15 @@ void getClassVariants( for (const auto &field : j.items()) { // Is it a choice child? const auto &elemRHS = field.value(); - const std::string occ = elemRHS["occurrence"]; - if (occ != "choice" && occ != "choice+" && occ != "choice2+") + const std::string times = getTimes(elemRHS); + if (times != "choice" && times != "choice+" && times != "choice2+") continue; // Variant name - const std::string variant = elemRHS.contains("variant") + const std::string variantName = elemRHS.contains("variant") ? elemRHS["variant"] : ""; - auto it = map.find(variant); + auto it = map.find(variantName); assert(it != map.end()); // should be there from the earlier loop // For the individual child that's part of a choice... @@ -622,7 +643,7 @@ void getClassVariants( const std::string ns = getChildNamespace(elemRHS, specs, per, c.type); c.type = ns + "::" + c.type; // ...its vector-ness - c.isVector = occ == "choice+" || occ == "choice2+"; + c.isVector = times == "choice+" || times == "choice2+"; // The GNDS JSON specifications all have "required":false for individual // choices in a set of choices; the concept of "the entire choice can be @@ -695,9 +716,9 @@ class writer { if (recurse == 0) { using last = decltype( std::get(std::make_tuple(value,args...))); - const size_t nsub = std::count(str.begin(), str.end(), substitute); + const std::size_t nsub = std::count(str.begin(),str.end(),substitute); // a bool last argument is not interpreted as an argument to print... - const size_t narg = + const std::size_t narg = 1 + sizeof...(args) - std::is_same_v,bool>; if (narg != nsub) { log::error( @@ -830,7 +851,6 @@ void writeClassPrefix(writer &out, const PerClass &per) // comment introducing class out(); out(); - out(); out(largeComment); out("// @::", per.nsname); out("// class @", per.clname); @@ -840,8 +860,14 @@ void writeClassPrefix(writer &out, const PerClass &per) out(); out("namespace @ {", per.nsname); out(); - out("class @ : public Component<@@> {", - per.clname, per.clname, + out("class @ : public Component<@::@@> {", + // A namespace prefix in Component<> prevents possible ambiguities with + // the Child<> object for the class that was brought in through key.hpp. + // Normally the class name is capitalized while the Child<> object isn't, + // but if the node name was already capitalized in the specs (an example + // we encountered was "XYs1d"), then the Child<> key would reflect that. + // Then, without the nsname:: here, we'd have an ambiguity. + per.clname, per.nsname, per.clname, per.isData ? (",true" + (per.dataType == "" ? "" : "," + per.dataType)) : "" @@ -853,7 +879,8 @@ void writeClassPrefix(writer &out, const PerClass &per) void writeClassForComponent(writer &out, const PerClass &per) { // using [name for variant] = ... - out(); + if (per.variants.size()) + out(); for (const auto &v : per.variants) { out(1,"using @ = std::variant<", v.type); int count = 0, total = v.children.size(); @@ -869,18 +896,18 @@ void writeClassForComponent(writer &out, const PerClass &per) out(); out(1,"friend class Component;"); out(); - out(1,"// Current namespace, current class, and GNDS node name"); - out(1,"static auto namespaceName() { return \"@\"; }", per.nsname); - out(1,"static auto className() { return \"@\"; }", per.clname); - out(1,"static auto GNDSName() { return \"@\"; }", per.nameGNDS); + out(1,"// Names: this namespace, this class, a field / node of this type"); + out(1,"static auto NAMESPACE() { return \"@\"; }", per.nsname); + out(1,"static auto CLASS() { return \"@\"; }", per.clname); + out(1,"static auto FIELD() { return \"@\"; }", per.nameGNDS); - // keys() begin + // KEYS() begin out(); out(1,"// Core Interface multi-query to extract metadata and child nodes"); - out(1,"static auto keys()"); + out(1,"static auto KEYS()"); out(1,"{"); - // keys() contents + // KEYS() contents int count = 0, total = per.nfields(); if (total == 0) out(2,"return std::tuple<>{};"); @@ -917,7 +944,7 @@ void writeClassForComponent(writer &out, const PerClass &per) out(2,";"); } - // keys() end + // KEYS() end out(1,"}"); out(); out("public:"); @@ -926,7 +953,7 @@ void writeClassForComponent(writer &out, const PerClass &per) // Class suffix void writeClassSuffix( - writer &out, const PerClass &per, const std::string &version + writer &out, const PerClass &per, const InfoSpecs &specs ) { // assignment out(); @@ -946,8 +973,8 @@ void writeClassSuffix( out(1,"// Custom functionality"); out(1,smallComment); out(); - out(1,"#include \"GNDStk/@/@/@/src/custom.hpp\"", - version, per.nsname, per.clname); + out(1,"#include \"@/@/@/@/src/custom.hpp\"", + specs.Project, specs.Version, per.nsname, per.clname); // class+namespace end out(); @@ -958,7 +985,6 @@ void writeClassSuffix( - // ----------------------------------------------------------------------------- // writeClass* // For metadata, children, and variant children @@ -1019,26 +1045,19 @@ void writeClassGetters(writer &out, const PerClass &per) out(); out(1,"// @", i.name); out(1,"const @ &@() const", i.typeFull, i.name); - out(2,"{ return content.@; }", i.name); + out(2,"{ return Content.@; }", i.name); out(1, "@ &@()", i.typeFull, i.name); - out(2,"{ return content.@; }", i.name); - - const auto indlab = - [&out,&i](const auto &T, const auto &par) - { - // T par: index or label parameter - out(); - out(1,"// @(@)", i.name, par); - out(1,"const @ &@(const @@) const", i.type, i.name, T, par); - out(2,"{ return getter(@(), @, \"@\"); }", i.name, par, i.name); - out(1, "@ &@(const @@)", i.type, i.name, T, par); - out(2,"{ return getter(@(), @, \"@\"); }", i.name, par, i.name); - }; + out(2,"{ return Content.@; }", i.name); if (isVector) { - // with index or label - indlab("std::size_t ", "index"); - indlab("std::string &", "label"); + out(); + out(1,"// @(index/label/Lookup)", i.name); + out(1,"template>"); + out(1,"decltype(auto) @(const KEY &key) const", i.name); + out(2, "{ return getter(@(), key, \"@\"); }", i.name, i.name); + out(1,"template>"); + out(1,"decltype(auto) @(const KEY &key)", i.name); + out(2, "{ return getter(@(), key, \"@\"); }", i.name, i.name); } }; @@ -1050,24 +1069,17 @@ void writeClassGetters(writer &out, const PerClass &per) // variant alternatives for (const auto &v : per.variants) { for (const auto &c : v.children) { - const auto indlab = - [&out,&v,&c](const auto &T, const auto &par) - { - // T par: index or label parameter - out(); - out(1,"// @(@)", c.name, par); - out(1,"const @ *@(const @@) const", c.type, c.name, T, par); - out(2,"{ return getter<@>(@(), @, \"@\"); }", - c.type, v.name, par, c.name); - out(1, "@ *@(const @@)", c.type, c.name, T, par); - out(2,"{ return getter<@>(@(), @, \"@\"); }", - c.type, v.name, par, c.name); - }; - if (v.isVector) { - // with index or label - indlab("std::size_t ", "index"); - indlab("std::string &", "label"); + out(); + out(1,"// @(index/label/Lookup)", c.name); + out(1,"template>"); + out(1,"decltype(auto) @(const KEY &key) const", c.name); + out(2, "{ return getter<@>(@(), key, \"@\"); }", + c.type, v.name, c.name); + out(1,"template>"); + out(1,"decltype(auto) @(const KEY &key)", c.name); + out(2, "{ return getter<@>(@(), key, \"@\"); }", + c.type, v.name, c.name); } else { out(); out(1,"// @", c.name); @@ -1094,28 +1106,32 @@ void writeClassSetterChild( // setter // note that if type is optional, a T can still be sent out(); - out(1,"// @(value)", child.name); + if (child.isVector) + out(1,"// @(vector): replace vector", child.name); + else + out(1,"// @(value)", child.name); out(1,"@ &@(const @ &obj)", parent.clname, child.name, child.typeFull); out(2,"{ @() = obj; return *this; }", child.name); - const auto indlab = - [&out,&parent,&child](const auto &T, const auto &par) - { - // T par: index or label parameter - out(); - out(1,"// @(@,value)", child.name, par); - out(1,"@ &@(", parent.clname, child.name); - out(2,"const @@,", T, par); - out(2,"const @ &obj", child.type); - out(1,") {"); - out(2,"@(@) = obj; return *this;", child.name, par); - out(1,"}"); - }; - - // with index or label + // if vector or optional if (child.isVector) { - indlab("std::size_t ", "index"); - indlab("std::string &", "label"); + // push vector element + out(); + out(1,"// @(scalar): vector push_back", child.name); + out(1,"@ &@(const @ &obj)", parent.clname, child.name, child.type); + out(2,"{ setter(@(), obj); return *this; }", child.name); + + // replace one vector value + out(); + out(1,"// @(index/label/Lookup, value): replace vector entry", + child.name); + out(1,"template>"); + out(1,"@ &@(const KEY &key, const @ &obj)", + parent.clname, child.name, child.type); + out(1,"{"); + out(2, "@(key) = obj; return *this;", + child.name); + out(1,"}"); } } // writeClassSetterChild @@ -1140,7 +1156,7 @@ void writeClassSetters(writer &out, const PerClass &per) out(1,"// @(value)", m.name); // special cases: we want to send length, start, and valueType - // to the BodyText base as well + // to the BlockData base as well const bool special = per.isData && (m.name == "length" || m.name == "start" || m.name == "valueType"); @@ -1148,26 +1164,17 @@ void writeClassSetters(writer &out, const PerClass &per) // setter // note that if type is optional, a T can still be sent out(1,"@ &@(const @ &obj)", per.clname, m.name, m.typeFull); - if (special && m.isDefaulted) - out(2,"{ BodyText::@(content.@ = obj); return *this; }", - m.name, m.name); - if (special && !m.isDefaulted) - out(2,"{ BodyText::@(@() = obj); return *this; }", - m.name, m.name); - if (!special && m.isDefaulted) - out(2,"{ content.@ = obj; return *this; }", - m.name); - if (!special && !m.isDefaulted) - out(2,"{ @() = obj; return *this; }", - m.name); + + special + ? out(2,"{ BlockData::@(@() = obj); return *this; }", m.name, m.name) + : out(2,"{ @() = obj; return *this; }", m.name); // setter, if type is Defaulted if (m.isDefaulted) { out(1,"@ &@(const std::optional<@> &obj)", per.clname, m.name, m.type); special - ? out(2,"{ BodyText::@(content.@ = obj); return *this; }", - m.name, m.name) - : out(2,"{ content.@ = obj; return *this; }", m.name); + ? out(2,"{ BlockData::@(@() = obj); return *this; }", m.name, m.name) + : out(2,"{ @() = obj; return *this; }", m.name); } } @@ -1180,24 +1187,19 @@ void writeClassSetters(writer &out, const PerClass &per) if (v.isVector) { // choice is a vector for (const auto &c : v.children) { - const auto indlab = - [&out,&per,&v,&c](const auto &T, const auto &par) - { - // T par: index or label parameter - out(); - out(1,"// @(@,value)", c.name, par); - out(1,"@ &@(", per.clname, c.name); - out(2,"const @@,", T, par); - out(2,"const std::optional<@> &obj", c.type); - out(1,") {"); - out(2,"if (obj) @(@,obj.value());", v.name, par); - out(2,"return *this;"); - out(1,"}"); - }; - - // with index or label - indlab("std::size_t ", "index"); - indlab("std::string &", "label"); + // replace one vector value + out(); + out(1,"// @(index/label/Lookup, value): replace vector entry", + c.name); + out(1,"template>"); + out(1,"@ &@(", per.clname, c.name); + out(2, "const KEY &key,"); + out(2, "const std::optional<@> &obj", c.type); + out(1,") {"); + out(2, "if (obj) @(key,obj.value());", v.name); + out(2, "return *this;"); + out(1,"}"); } } else { // choice is a variant @@ -1220,22 +1222,22 @@ void writeClassSetters(writer &out, const PerClass &per) // writeClassCtorComponent void writeClassCtorComponent( - writer &out, const PerClass &per, const bool hasOther + writer &out, const PerClass &per, const bool copyOrMove ) { out(2,"Component{"); - out(3, hasOther ? "other" : "BodyText{}", false); + out(3, copyOrMove ? "other.baseBlockData()" : "BlockData{}", false); for (const auto &m : per.metadata) { // metadata out(","); - out(3,"content.@", m.name, false); + out(3,"this->@()", m.name, false); } for (const auto &c : per.children) { // children out(","); - out(3,"content.@", c.name, false); + out(3,"this->@()", c.name, false); } for (const auto &v : per.variants) { // variants out(","); - out(3,"content.@", v.name, false); + out(3,"this->@()", v.name, false); } out(); @@ -1255,48 +1257,23 @@ void writeClassCtorBody(writer &out, const std::string &argName) // writeClassCtors void writeClassCtors(writer &out, const PerClass &per) { - // ctor: default - out(); - out(1,"// default"); - out(1,"@() :", per.clname); - writeClassCtorComponent(out, per, false); - out(); - writeClassCtorBody(out, ""); - - // ctor: copy - out(); - out(1,"// copy"); - out(1,"@(const @ &other) :", per.clname, per.clname); - writeClassCtorComponent(out, per, true); - out(","); - out(2,"content{other.content}"); - writeClassCtorBody(out, "other"); - - // ctor: move - out(); - out(1,"// move"); - out(1,"@(@ &&other) :", per.clname, per.clname); - writeClassCtorComponent(out, per, true); - out(","); - out(2,"content{std::move(other.content)}"); - writeClassCtorBody(out, "other"); - - // ctor: node - out(); - out(1,"// from node"); - out(1,"@(const Node &node) :", per.clname); - writeClassCtorComponent(out, per, false); - out(); - writeClassCtorBody(out, "node"); - // ------------------------ - // ctor: fields + // ctor: default, + // and from fields // ------------------------ const auto total = per.nfields(); - if (total != 0) { + out(); + + if (total == 0) { + out(1,"// default"); + out(1,"@() :", per.clname); + writeClassCtorComponent(out, per, false); out(); - out(1,"// from fields"); + } else { + out(1,"// default, and from fields"); + + // informational message, if applicable for (const auto &m : per.metadata) if (m.isDefaulted) { out(1,"// std::optional replaces Defaulted; " @@ -1305,28 +1282,30 @@ void writeClassCtors(writer &out, const PerClass &per) } // signature, and base constructor call - // Note: we don't need "explicit" unless this constructor can be called - // with one argument. We'll always write it, however, in case someone - // modifies the auto-generated constructor (say, giving its arguments - // defaults) in such a way that is *can* be called with one argument. - // But we'd rather nobody modify the auto-generated classes. int count = 0; out(1,"explicit @(", per.clname); - for (const auto &m : per.metadata) - out(2,"const @ &@@", - m.isDefaulted ? "std::optional<" + m.type + ">" : m.typeFull, - m.name, ++count < total ? "," : ""); - for (const auto &c : per.children) - out(2,"const @ &@@", c.typeFull, c.name, ++count < total ? "," : ""); - for (const auto &v : per.variants) - out(2,"const @ &@@", v.typeFull, v.name, ++count < total ? "," : ""); + + for (const auto &m : per.metadata) { + const std::string type = + m.isDefaulted ? "std::optional<" + m.type + ">" : m.typeFull; + out(2,"const @ &@ =", type, m.name); + out(3,"@{}@", type, ++count < total ? "," : ""); + } + for (const auto &c : per.children) { + out(2,"const @ &@ =", c.typeFull, c.name); + out(3,"@{}@", c.typeFull, ++count < total ? "," : ""); + } + for (const auto &v : per.variants) { + out(2,"const @ &@ =", v.typeFull, v.name); + out(3,"@{}@", v.typeFull, ++count < total ? "," : ""); + } out(1,") :"); writeClassCtorComponent(out, per, false); // initialize fields out(","); - out(2,"content{"); + out(2,"Content{"); count = 0; for (const auto &m : per.metadata) out(3,"@@", @@ -1339,11 +1318,46 @@ void writeClassCtors(writer &out, const PerClass &per) for (const auto &v : per.variants) out(3,"@@", v.name, ++count < total ? "," : ""); out(2,"}"); - - // body - writeClassCtorBody(out, ""); } + // body + writeClassCtorBody(out, ""); + + // ------------------------ + // ctor: copy + // ------------------------ + + out(); + out(1,"// copy"); + out(1,"@(const @ &other) :", per.clname, per.clname); + writeClassCtorComponent(out, per, true); + out(","); + out(2,"Content{other.Content}"); + writeClassCtorBody(out, "other"); + + // ------------------------ + // ctor: move + // ------------------------ + + out(); + out(1,"// move"); + out(1,"@(@ &&other) :", per.clname, per.clname); + writeClassCtorComponent(out, per, true); + out(","); + out(2,"Content{std::move(other.Content)}"); + writeClassCtorBody(out, "other"); + + // ------------------------ + // ctor: node + // ------------------------ + + out(); + out(1,"// from node"); + out(1,"@(const Node &node) :", per.clname); + writeClassCtorComponent(out, per, false); + out(); + writeClassCtorBody(out, "node"); + // ------------------------ // ctor: vector // ------------------------ @@ -1352,7 +1366,7 @@ void writeClassCtors(writer &out, const PerClass &per) out(); out(1,"// from vector"); out(1,"template>>"); + "std::enable_if_t>>"); out(1,"@(const std::vector &vector) :", per.clname); writeClassCtorComponent(out, per, false); out(); @@ -1373,31 +1387,38 @@ void writeClass(PerClass &per, const InfoSpecs &specs) writer out(false); // output: class begin - writeClassPrefix(out,per); + writeClassPrefix(out, per); // output: for the Component base - writeClassForComponent(out,per); + writeClassForComponent(out, per); // output: using directives out(); out(1,"using Component::construct;"); if (per.isData) - out(1,"using BodyText::operator=;"); + out(1,"using BlockData::operator=;"); // output: defaults (applicable only to metadata) - out(); - out(1,smallComment); - out(1,"// Relevant defaults"); - out(1,"// FYI for users"); - out(1,smallComment); - out(); - out(1,"static inline const struct Defaults {"); + std::size_t ndefaults = 0; for (auto &m : per.metadata) if (m.isDefaulted) - out(2,"static inline const @ @ = @;", m.type, m.name, initializer(m)); - out(1,"} defaults;"); + ++ndefaults; + if (ndefaults > 0) { + out(); + out(1,smallComment); + out(1,"// Relevant defaults"); + out(1,"// FYI for users"); + out(1,smallComment); + out(); + out(1,"static inline const struct Defaults {"); + for (auto &m : per.metadata) + if (m.isDefaulted) + out(2, "static inline const @ @ = @;", + m.type, m.name, initializer(m)); + out(1,"} defaults;"); + } - // output: content (the metadata/children computed earlier) + // output: struct Content (for the metadata/children computed earlier) out(); out(1,smallComment); out(1,"// Raw GNDS content"); @@ -1407,7 +1428,7 @@ void writeClass(PerClass &per, const InfoSpecs &specs) writeClassContentMetadata(out, per); writeClassContentChildren(out, per); writeClassContentVariants(out, per); - out(1,"} content;"); + out(1,"} Content;"); // output: getters, setters if (per.metadata.size() || per.children.size() || per.variants.size()) { @@ -1418,12 +1439,12 @@ void writeClass(PerClass &per, const InfoSpecs &specs) // output: constructors out(); out(1,smallComment); - out(1,"// Construction"); + out(1,"// Constructors"); out(1,smallComment); writeClassCtors(out, per); // output: class end - writeClassSuffix(out, per, specs.Version); + writeClassSuffix(out, per, specs); // done per.code = out.str(); @@ -1436,7 +1457,7 @@ void writeClass(PerClass &per, const InfoSpecs &specs) // ----------------------------------------------------------------------------- // readJSONFile -nlohmann::json readJSONFile(const std::string &file, const bool print = false) +orderedJSON readJSONFile(const std::string &file, const bool print = false) { static const std::string underlineON = "\033[4m"; static const std::string underlineOFF = "\033[24m"; @@ -1455,7 +1476,7 @@ nlohmann::json readJSONFile(const std::string &file, const bool print = false) throw std::exception{}; } - nlohmann::json j; + orderedJSON j; ifs >> j; return j; } // readJSONFile @@ -1463,7 +1484,7 @@ nlohmann::json readJSONFile(const std::string &file, const bool print = false) // getMetadataJSON template -auto getMetadataJSON(const nlohmann::json &j) +auto getMetadataJSON(const orderedJSON &j) { static const std::string metastr = "metadata"; static const std::string attrstr = "attributes"; @@ -1476,15 +1497,15 @@ auto getMetadataJSON(const nlohmann::json &j) return meta ? j[metastr] : j[attrstr]; } else { assert(!(meta && attr)); // not both - return std::optional( - meta ? j[metastr] : attr ? j[attrstr] : nlohmann::json{}); + return std::optional( + meta ? j[metastr] : attr ? j[attrstr] : orderedJSON{}); } } // getMetadataJSON // getChildrenJSON template -auto getChildrenJSON(const nlohmann::json &j) +auto getChildrenJSON(const orderedJSON &j) { static const std::string chldstr = "children"; static const std::string nodestr = "childNodes"; @@ -1497,8 +1518,8 @@ auto getChildrenJSON(const nlohmann::json &j) return chld ? j[chldstr] : j[nodestr]; } else { assert(!(chld && node)); // not both - return std::optional( - chld ? j[chldstr] : node ? j[nodestr] : nlohmann::json{}); + return std::optional( + chld ? j[chldstr] : node ? j[nodestr] : orderedJSON{}); } } // getChildrenJSON @@ -1511,7 +1532,7 @@ auto getChildrenJSON(const nlohmann::json &j) // readChangesFile void readChangesFile(const std::string &file, InfoSpecs &specs) { - const nlohmann::json jchanges = readJSONFile(file); + const orderedJSON jchanges = readJSONFile(file); using pair = std::pair; // Changes to name? @@ -1540,19 +1561,21 @@ void readChangesFile(const std::string &file, InfoSpecs &specs) // printSingletons void printSingletons(const std::string &file) { - const nlohmann::json &jfile = readJSONFile(file,true); + const orderedJSON &jfile = readJSONFile(file,true); for (const auto &item : jfile.items()) { const std::string parent = item.key(); - const nlohmann::json rhs = item.value(); + const orderedJSON rhs = item.value(); if (!isClass(item)) continue; const auto metadata = getMetadataJSON(rhs); const auto children = getChildrenJSON(rhs); + const bool data = rhs.contains("data") && !rhs["data"].is_null(); + const bool body = rhs.contains("bodyText") && !rhs["bodyText"].is_null(); - if (metadata.size() == 0 && children.size() == 0) - log::info("Class \"{}\" has no metadata and no children", parent); + if (metadata.size() == 0 && children.size() == 0 && !data && !body) + log::info("Class \"{}\" has no metadata, children, or data", parent); if (metadata.size() == 0 && children.size() == 1) log::info("Class \"{}\" has no metadata and just one child", parent); } @@ -1560,16 +1583,17 @@ void printSingletons(const std::string &file) // commandLine -// Gather information from the .json file given on the command line +// Gather information from the JSON file given on the command line void commandLine( const int argc, const char *const *const argv, InfoSpecs &specs ) { - // Keys we'll look for + // JSON keys we'll look for + static const std::string path = "Path"; + static const std::string project = "Project"; + static const std::string version = "Version"; static const std::string input = "JSONDir"; static const std::string files = "JSONFiles"; - static const std::string output = "GNDSDir"; - static const std::string version = "Version"; static const std::string changes = "Changes"; // Usage @@ -1579,21 +1603,26 @@ void commandLine( } // Input file - const nlohmann::json jmain = readJSONFile(argv[1]); + const orderedJSON jmain = readJSONFile(argv[1]); // Validate content - if (!(jmain.contains(input) && jmain.contains(output) && - jmain.contains(files) && jmain.contains(version))) { - log::error("The input json file needs {}, {}, {}, and {}", - input, files, output, version); + if (!(jmain.contains(version) && + jmain.contains(input) && + jmain.contains(files))) { + log::error("The input JSON file needs {}, {}, and {}", + version, input, files); throw std::exception{}; } - // Extract information from the command line .json - specs.JSONDir = jmain[input]; - specs.JSONFiles = std::vector(jmain[files]); - specs.GNDSDir = jmain[output]; - specs.Version = jmain[version]; + // Extract information from the command line JSON file + specs.Path = jmain.contains(path) ? jmain[path] : "."; + specs.Project = jmain.contains(project) ? jmain[project] : "GNDStk"; + specs.Version = jmain[version]; + specs.JSONDir = jmain[input]; + for (const auto &str : jmain[files]) + specs.JSONFiles.push_back(str); + + // Version, with underscores in place of periods specs.VersionUnderscore = replace(specs.Version, '.', '_'); // Prepend the JSON file names with their directory @@ -1601,14 +1630,17 @@ void commandLine( file = specs.JSONDir + '/' + file; // File names - specs.hppVersion = specs.GNDSDir + "/src/GNDStk/" + specs.Version + ".hpp"; - specs.hppKey = specs.GNDSDir + "/src/GNDStk/" + specs.Version + "/key.hpp"; + const std::string base = + specs.Path + "/" + specs.Project + "/src/" + specs.Project + "/"; + specs.hppVersion = base + specs.Version + ".hpp"; + specs.hppKey = base + specs.Version + "/key.hpp"; // Report on "singletons" if (singletons) { - action("Finding possible simplifications"); + action("\nFinding possible simplifications..."); for (const std::string &file : specs.JSONFiles) printSingletons(file); + action("Done."); } // Changes? @@ -1641,17 +1673,17 @@ void preprocessClass( // custom files as needed // ------------------------ - // Given the base GNDS directory and the GNDS version, as obtained earlier - // from the JSON input file to this tool, compute relevant directory names. - const std::string - // For the present namespace: C++ and Python directories. The present - // namespace probably contains multiple classes, so its directories - // may have been created already, but that's fine. - nsdir = specs.GNDSDir + "/src/GNDStk/" + specs.Version + "/" + nsname, - nsdirpy = specs.GNDSDir + "/python/src/" + specs.Version + "/" + nsname, - // For the present class: C++ source and test directories. - clsrc = nsdir + "/" + clname + "/src", - cltest = nsdir + "/" + clname + "/test"; + // For the present namespace: C++ and Python directories. The present + // namespace probably contains multiple classes, so these directories + // may have been created already, but that's fine. + const std::string nsdir = specs.Path + "/" + specs.Project + + "/src/" + specs.Project + "/" + specs.Version + "/" + nsname; + const std::string nsdirpy = specs.Path + "/" + specs.Project + + "/python/src" + "/" + specs.Version + "/" + nsname; + + // For the present class: C++ source and test directories. + const std::string clsrc = nsdir + "/" + clname + "/src"; + const std::string cltest = nsdir + "/" + clname + "/test"; // Create the above directories, if (and only if) they don't already exist. system(("mkdir -p " + nsdir ).data()); @@ -1708,15 +1740,16 @@ void preprocessClass( // names are computed as part of the "information" for the maps just mentioned. void preprocessFiles(InfoSpecs &specs) { - action("Preprocessing input files"); + action("\nPreprocessing input files..."); // files for (const std::string &file : specs.JSONFiles) { - const nlohmann::json jmain = readJSONFile(file,true); + const orderedJSON jmain = readJSONFile(file,true); const std::string nsname = getFileNamespace(jmain); // classes in the file for (const auto &cl : jmain.items()) preprocessClass(specs, nsname, cl); } + action("Done."); } // preprocessFiles @@ -1728,7 +1761,7 @@ void preprocessFiles(InfoSpecs &specs) // ----------------------------------------------------------------------------- // Helper: validateMetadata -void validateMetadata(const nlohmann::json &metadata) +void validateMetadata(const orderedJSON &metadata) { for (const auto &field : metadata.items()) { assert(field.value().contains("type")); @@ -1738,18 +1771,17 @@ void validateMetadata(const nlohmann::json &metadata) // Helper: validateChildren -void validateChildren(const nlohmann::json &children) +void validateChildren(const orderedJSON &children) { for (const auto &field : children.items()) { - assert(field.value().contains("occurrence")); assert(field.value().contains("required")); - // Consistency check: certain "occurrence" values imply *not* required. + // Consistency check: certain occurrence values imply *not* required. // Remark: the GNDS manual speaks of "choice2" and "choice2+" options // for occurrence. We're not sure if those will remain in future GNDS // specifications, so we won't worry now about how they might fit in. - const std::string occ = field.value()["occurrence"]; - if (occ == "0+" || occ == "choice" || occ == "choice+") + const std::string times = getTimes(field.value()); + if (times == "0+" || times == "choice" || times == "choice+") assert(!field.value()["required"]); // not required } } @@ -1779,8 +1811,8 @@ void getClass( per.nameGNDS = nameGNDS(keyval); // metadata/children information - const nlohmann::json attrs = getMetadataJSON(classRHS); - const nlohmann::json elems = getChildrenJSON(classRHS); + const orderedJSON attrs = getMetadataJSON(classRHS); + const orderedJSON elems = getChildrenJSON(classRHS); validateMetadata(attrs); validateChildren(elems); getClassMetadata(attrs, specs, per); @@ -1794,7 +1826,15 @@ void getClass( const bool body = classRHS.contains(bodystr) && !classRHS[bodystr].is_null(); assert(!(data && body)); // not both per.isData = data || body; - per.dataType = data ? classRHS[datastr] : ""; + if (data) { + // A type change, as with metadata, could be wanted in this context as + // well. Perhaps the name "mapMetaType" (and the location and name for + // it in the changes.json file) should be modified to reflect this + const std::string type = classRHS[datastr]; + const auto it = specs.mapMetaType.find(type); + per.dataType = it == specs.mapMetaType.end() ? type : it->second; + } else + per.dataType = ""; // per.code will contain printed C++ code for the class itself writeClass(per,specs); @@ -1807,15 +1847,16 @@ void getClass( // getFiles void getFiles(InfoSpecs &specs) { - action("Creating classes"); + action("\nCreating classes..."); // files for (const std::string &file : specs.JSONFiles) { - const nlohmann::json jmain = readJSONFile(file,true); + const orderedJSON jmain = readJSONFile(file,true); const std::string nsname = getFileNamespace(jmain); // classes in the file for (const auto &cl : jmain.items()) getClass(specs, nsname, cl); } + action("Done."); } // getFiles @@ -1867,8 +1908,8 @@ void fileGNDStkVersion(const InfoSpecs &specs) // Create an overarching file for this version writer out(specs.hppVersion); out(); - out("#ifndef NJOY_GNDSTK_@", allcaps(specs.VersionUnderscore)); - out("#define NJOY_GNDSTK_@", allcaps(specs.VersionUnderscore)); + out("#ifndef @_@", allcaps(specs.Project), allcaps(specs.VersionUnderscore)); + out("#define @_@", allcaps(specs.Project), allcaps(specs.VersionUnderscore)); std::string nsname_last = ""; for (auto &c : specs.class2data) { @@ -1877,41 +1918,16 @@ void fileGNDStkVersion(const InfoSpecs &specs) if (nsname != nsname_last) out(); nsname_last = nsname; - out("#include \"GNDStk/@/@/@.hpp\"", specs.Version, nsname, clname); + out("#include \"@/@/@/@.hpp\"", + specs.Project, specs.Version, nsname, clname); } - out(); - out("#include \"GNDStk/@/key.hpp\"", specs.Version); out(); out("#endif"); } // fileGNDStkVersion -// fixme Reconsider the arrangement described here... // fileGNDStkKey -const std::string file_key_comment = -R"***( -This file contains Meta and Child objects for metadata and child nodes in the -current GNDS version. These may prove to be useful if you wish to use the Core -Interface in conjunction with the autogenerated classes for this GNDS version. - -Within the outer njoy::GNDStk::version namespace below, the remaining namespace -arrangement was chosen to make the use of these objects smooth and logical. - -Meta and Child objects are collectively called "keys." Meta keys are placed -into key::meta. Child keys correspond to autogenerated classes, each of which -is already in some namespace; we thus use theNamespace::key::child::. That way, -an autogenerated class [ns::Foo] has [ns::key::foo] as its Child object, and -a "using namespace ns" allows the class and the Child object to be [Foo] and -[key::foo], respectively. (If we reordered ns:: and key::, that wouldn't work.) - -Within key::, we use meta:: and child:: around Meta and Child objects, just in -case there exist any identical GNDS metadata names and child-node names. (That -can, in fact, happen). The "using namespace meta" and "using namespace child" -directives then make the Meta<> and Child<> objects appear directly in key::, -so that "meta::" and "child::" are needed only to disambiguate identical names. -)***"; - void fileGNDStkKey(const InfoSpecs &specs) { // ------------------------ @@ -1930,7 +1946,7 @@ void fileGNDStkKey(const InfoSpecs &specs) std::multimap> namespace2children; for (const auto &file : specs.JSONFiles) { - const nlohmann::json jmain = readJSONFile(file); + const orderedJSON jmain = readJSONFile(file); auto it = namespace2children.insert( std::make_pair(getFileNamespace(jmain),std::set{})); @@ -1958,16 +1974,20 @@ void fileGNDStkKey(const InfoSpecs &specs) writer out(specs.hppKey); out(); - out("/*",false); - out(file_key_comment,false); - out("*/"); + out("#ifndef @_@_KEY", + allcaps(specs.Project), allcaps(specs.VersionUnderscore)); + out("#define @_@_KEY", + allcaps(specs.Project), allcaps(specs.VersionUnderscore)); out(); - out("#ifndef NJOY_GNDSTK_@_KEY", allcaps(specs.VersionUnderscore)); - out("#define NJOY_GNDSTK_@_KEY", allcaps(specs.VersionUnderscore)); + out("// GNDStk Core Interface"); + out("#include \"GNDStk.hpp\""); out(); - out("namespace njoy {"); - out("namespace GNDStk {"); + if (specs.Project == "GNDStk") // <== use namespace njoy only for this + out("namespace njoy {"); + out("namespace @ {", specs.Project); out("namespace @ {", specs.VersionUnderscore); + out(); + out("using namespace njoy::GNDStk;"); // ------------------------ // Meta<> objects @@ -1976,22 +1996,29 @@ void fileGNDStkKey(const InfoSpecs &specs) out(); out(); out(largeComment); - out("// key::meta::"); + out("// meta::"); out(largeComment); out(); - out("namespace key {"); out("namespace meta {"); if (metadata.size() > 0) { + out(); + out(0,"#define GNDSTK_MAKE_LOOKUP(nameField,nameGNDS) \\"); + out(1, "inline const auto nameField = makeLookup( \\"); + out(2, "[](const auto &obj) -> decltype(obj.nameField()) \\"); + out(2, "{ return obj.nameField(); }, \\"); + out(2, "#nameGNDS \\"); + out(1, ")"); + out(0, "// nameField vs. nameGNDS: for, e.g., Double vs. double in GNDS"); out(); for (const auto &meta : metadata) - out("inline const Meta<> @(\"@\");", meta.first, meta.second); + out("GNDSTK_MAKE_LOOKUP(@,@);", meta.first, meta.second); + out(); + out(0,"#undef GNDSTK_MAKE_LOOKUP"); out(); } out("} // namespace meta"); - out("using namespace meta;"); - out("} // namespace key"); // ------------------------ // Child<> objects @@ -2001,11 +2028,10 @@ void fileGNDStkKey(const InfoSpecs &specs) out(); out(); out(largeComment); - out("// @::key::child::", nspace.first); + out("// @::child::", nspace.first); out(largeComment); out(); out("namespace @ {", nspace.first); - out("namespace key {"); out("namespace child {"); const auto &children = nspace.second; @@ -2018,10 +2044,29 @@ void fileGNDStkKey(const InfoSpecs &specs) out("} // namespace child"); out("using namespace child;"); - out("} // namespace key"); out("} // namespace @", nspace.first); } + // ------------------------ + // Using directives + // ------------------------ + + out(); + out(); + out(largeComment); + out("// For convenience: using directives"); + out(largeComment); + out(); + out("namespace key {"); + out(1,"using namespace meta;"); + for (const auto &nspace : namespace2children) + out(1,"using namespace @::child;", nspace.first); + out("} // namespace key"); + out(); + out("using namespace key;"); + for (const auto &nspace : namespace2children) + out("using namespace @;", nspace.first); + // ------------------------ // finish // ------------------------ @@ -2032,8 +2077,9 @@ void fileGNDStkKey(const InfoSpecs &specs) out(largeComment); out(); out("} // namespace @", specs.VersionUnderscore); - out("} // namespace GNDStk"); - out("} // namespace njoy"); + out("} // namespace @", specs.Project); + if (specs.Project == "GNDStk") // <== end namespace njoy only for this + out("} // namespace njoy"); out(); out("#endif"); } // fileGNDStkKey @@ -2046,34 +2092,31 @@ void fileGNDStkClass( // class-specific hpp file writer out(per.hppGNDStk); const std::string guard = - "NJOY_GNDSTK_" + allcaps(specs.VersionUnderscore) + "_" + - allcaps(per.nsname) + "_" + allcaps(per.clname); + allcaps(specs.Project) + "_" + + allcaps(specs.VersionUnderscore) + "_" + + allcaps(per.nsname) + "_" + + allcaps(per.clname); out(); out("#ifndef @", guard); out("#define @", guard); - out(); - out("// core interface"); - out("#include \"GNDStk.hpp\""); - if (c2d.dependencies.size() > 0) { - out(); - out("// @ dependencies", specs.Version); - for (const auto &dep : c2d.dependencies) - out("#include \"GNDStk/@/@/@.hpp\"", - specs.Version, dep.nsname, dep.clname); - } + out(); + out("#include \"@/@/key.hpp\"", specs.Project, specs.Version); + for (const auto &dep : c2d.dependencies) + out("#include \"@/@/@/@.hpp\"", + specs.Project, specs.Version, dep.nsname, dep.clname); out(); - out("namespace njoy {"); - out("namespace GNDStk {"); + if (specs.Project == "GNDStk") + out("namespace njoy {"); + out("namespace @ {", specs.Project); out("namespace @ {", specs.VersionUnderscore); - out(); - out("using namespace njoy::GNDStk::core;"); out(per.code,false); out("} // namespace @", specs.VersionUnderscore); - out("} // namespace GNDStk"); - out("} // namespace njoy"); + out("} // namespace @", specs.Project); + if (specs.Project == "GNDStk") + out("} // namespace njoy"); out(); out("#endif"); } // fileGNDStkClass @@ -2107,7 +2150,10 @@ void filePythonNamespace(const InfoSpecs &specs, const PerNamespace &per) out(1,"// create the @ submodule", per.nsname); out(1,"python::module submodule = module.def_submodule("); out(2,"\"@\",", per.nsname); - out(2,"\"GNDS @ @\"", specs.Version, per.nsname); + if (specs.Project == "GNDStk") + out(2,"\"GNDS @ @\"", specs.Version, per.nsname); // "GNDS", not "GNDStk" + else + out(2,"\"@ @ @\"", specs.Project, specs.Version, per.nsname); out(1,");"); out(); @@ -2196,7 +2242,8 @@ void filePythonClass(const InfoSpecs &specs, const PerClass &per) out(); out("// local includes"); - out("#include \"GNDStk/@/@/@.hpp\"", specs.Version, nsname, clname); + out("#include \"@/@/@/@.hpp\"", + specs.Project, specs.Version, nsname, clname); out("#include \"definitions.hpp\""); out(); @@ -2211,8 +2258,10 @@ void filePythonClass(const InfoSpecs &specs, const PerClass &per) out("// @ wrapper", clname); out("void wrap@(python::module &module)", clname); out("{"); - out(1,"using namespace njoy::GNDStk;"); - out(1,"using namespace njoy::GNDStk::@;", specs.VersionUnderscore); + const std::string prefix = specs.Project == "GNDStk" ? "njoy::" : ""; + out(1,"using namespace @@;", prefix, specs.Project); + out(1,"using namespace @@::@;", + prefix, specs.Project, specs.VersionUnderscore); out(); out(1,"// type aliases"); out(1,"using Component = @::@;", nsname, clname); @@ -2291,7 +2340,11 @@ void filePythonClass(const InfoSpecs &specs, const PerClass &per) const auto pyname = namePython(c.name); out(2,".def_property_readonly("); out(3,"\"@\",", pyname); - out(3,"python::overload_cast<>(&Component::@),", c.name); + if (c.isVector) { + out(3,"(const @ &(Component::*)() const)", c.typeFull); + out(4,"&Component::@,", c.name); + } else + out(3,"python::overload_cast<>(&Component::@),", c.name); out(3,"Component::documentation(\"@\").data()", pyname); out(2,")"); } @@ -2309,7 +2362,11 @@ void filePythonClass(const InfoSpecs &specs, const PerClass &per) const auto pyname = namePython(v.name); out(2,".def_property_readonly("); out(3,"\"@\",", pyname); - out(3,"python::overload_cast<>(&Component::@),", v.name); + if (v.isVector) { + out(3,"(const @ &(Component::*)() const)", v.typeFull); + out(4,"&Component::@,", v.name); + } else + out(3,"python::overload_cast<>(&Component::@),", v.name); out(3,"Component::documentation(\"@\").data()", pyname); out(2,")"); } @@ -2317,7 +2374,8 @@ void filePythonClass(const InfoSpecs &specs, const PerClass &per) for ( const auto& dataTypeName : dataTypesNames ) { out(2,".def_property_readonly("); out(3,"\"@\",", dataTypeName.second); - out(3,"[] (const Component &self) { return self.@(); },", dataTypeName.second); + out(3,"[] (const Component &self) { return self.@(); },", + dataTypeName.second); out(3,"Component::documentation(\"@\").data()", dataTypeName.second); out(2,")"); } diff --git a/autogen/prototype.json b/autogen/prototype.json index 856a88ec1..527936a9e 100644 --- a/autogen/prototype.json +++ b/autogen/prototype.json @@ -1,20 +1,30 @@ { "comment" : [ - "GNDSDir", - " Base GNDStk directory into which the autogenerator tool", - " should place src/GNDStk/version.hpp and src/GNDStk/version/*", + "Path", + " Path to the Project directory.", + " Optional (defaults to .).", + "", + "Project", + " Base project directory into which the code generator should", + " place files. IMPORTANT: this should be a **plain** name only,", + " without any directory path. Use Path for that, if it's needed.", + " Optional (defaults to GNDStk).", "", "JSONDir", - " Directory where the listed .json input files are located", + " Directory where the .json input files are located", + "", + "JSONFiles", + " The .json input files", "", "TO AUTOGENERATE THE PROTOTYPE IN THE REAL GNDStk HIERARCHY", - " Set GNDSDir to .. if you run json2class.exe from within", - " GNDStk/autogen/, where GNDStk/ is the cloned repository", + " Set Path to ../.. if you run json2class.exe from within", + " GNDStk/autogen/, where GNDStk/ is the cloned repository.", + " This (../..) is where GNDStk is located.", "", - "Do NOT end the directories (JSONDir and GNDSDir) with a /" + "Do NOT end directories with a /" ], - "GNDSDir": "..", + "Path": "../..", "Version": "v1.9", "JSONDir": "prototype", @@ -22,5 +32,6 @@ "generalPurpose.json", "reactionSuite.json" ], + "Changes": "changes.json" } diff --git a/autogen/prototype/generalPurpose.json b/autogen/prototype/generalPurpose.json index 0f0456417..a0f41ebc2 100644 --- a/autogen/prototype/generalPurpose.json +++ b/autogen/prototype/generalPurpose.json @@ -33,11 +33,11 @@ }, "children": { "axes": { - "occurrence": "1", + "times": "1", "required": false }, "values": { - "occurrence": "1", + "times": "1", "required": true } } @@ -52,12 +52,12 @@ }, "children": { "axis": { - "occurrence": "choice+", + "times": "choice+", "variant": "axis_grid", "required": false }, "grid": { - "occurrence": "choice+", + "times": "choice+", "variant": "axis_grid", "required": false } @@ -108,12 +108,12 @@ }, "children": { "values": { - "occurrence": "choice", + "times": "choice", "variant": "link_values", "required": false }, "link": { - "occurrence": "choice", + "times": "choice", "variant": "link_values", "required": false } @@ -154,11 +154,11 @@ }, "children": { "axes": { - "occurrence": "1", + "times": "1", "required": false }, "XYs1d": { - "occurrence": "1+", + "times": "1+", "required": true } }, diff --git a/autogen/prototype/reactionSuite.json b/autogen/prototype/reactionSuite.json index 56280918b..814478bae 100644 --- a/autogen/prototype/reactionSuite.json +++ b/autogen/prototype/reactionSuite.json @@ -30,7 +30,7 @@ }, "children": { "reactions": { - "occurrence": "1", + "times": "1", "required": false } } @@ -40,7 +40,7 @@ "metadata": {}, "children": { "reaction": { - "occurrence": "1+", + "times": "1+", "required": true } } @@ -63,7 +63,7 @@ }, "children": { "crossSection": { - "occurrence": "1", + "times": "1", "required": true } } @@ -73,12 +73,12 @@ "metadata": {}, "children": { "XYs1d": { - "occurrence": "choice+", + "times": "choice+", "variant": "XYs1d_regions1d", "required": false }, "regions1d": { - "occurrence": "choice+", + "times": "choice+", "variant": "XYs1d_regions1d", "required": false } diff --git a/autogen/v1.9.json b/autogen/v1.9.json index 87bde7140..83fc57b83 100644 --- a/autogen/v1.9.json +++ b/autogen/v1.9.json @@ -1,4 +1,7 @@ { + "Path": "../..", + "Version": "v1.9", + "JSONDir": "v1.9", "JSONFiles": [ "summary_abstract.json", @@ -19,7 +22,5 @@ "summary_tsl.json" ], - "GNDSDir": "test", - "Version": "v1.9", "Changes": "changes.json" } diff --git a/cmake/GNDStk_dependencies.cmake b/cmake/GNDStk_dependencies.cmake index 46c409ac9..34c3b9f5c 100644 --- a/cmake/GNDStk_dependencies.cmake +++ b/cmake/GNDStk_dependencies.cmake @@ -10,28 +10,28 @@ include( FetchContent ) # Declare project dependencies ######################################################################## -FetchContent_Declare( catch-adapter - GIT_REPOSITORY http://github.com/njoy/catch-adapter - GIT_TAG origin/master - GIT_SHALLOW TRUE +FetchContent_Declare(catch-adapter + GIT_REPOSITORY http://github.com/njoy/catch-adapter + GIT_TAG origin/master + GIT_SHALLOW TRUE ) -FetchContent_Declare( Log - GIT_REPOSITORY http://github.com/njoy/Log - GIT_TAG origin/build/fetchcontent - GIT_SHALLOW TRUE +FetchContent_Declare(Log + GIT_REPOSITORY http://github.com/njoy/Log + GIT_TAG origin/master + GIT_SHALLOW TRUE ) -FetchContent_Declare( pugixml-adapter - GIT_REPOSITORY http://github.com/njoy/pugixml-adapter - GIT_TAG origin/master - GIT_SHALLOW TRUE +FetchContent_Declare(pugixml-adapter + GIT_REPOSITORY http://github.com/njoy/pugixml-adapter + GIT_TAG origin/master + GIT_SHALLOW TRUE ) FetchContent_Declare(json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.7.3 - GIT_SHALLOW true + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG origin/release/3.10.5 + GIT_SHALLOW TRUE ) FetchContent_GetProperties(json) @@ -41,10 +41,19 @@ if(NOT json_POPULATED) add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) endif() -FetchContent_Declare( pybind11 - GIT_REPOSITORY https://github.com/pybind/pybind11 - GIT_TAG v2.6.1 - GIT_SHALLOW TRUE +FetchContent_Declare(hdf5 + GIT_REPOSITORY https://github.com/BlueBrain/HighFive.git + GIT_TAG v2.3.1 + GIT_SHALLOW TRUE + ) +set( HIGHFIVE_USE_BOOST OFF CACHE INTERNAL "" ) +set( HIGHFIVE_UNIT_TESTS OFF CACHE INTERNAL "" ) +set( HIGHFIVE_EXAMPLES OFF CACHE INTERNAL "" ) + +FetchContent_Declare(pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11 + GIT_TAG v2.6.1 + GIT_SHALLOW TRUE ) @@ -57,5 +66,6 @@ FetchContent_MakeAvailable( Log pugixml-adapter json + hdf5 pybind11 ) diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index bf5bacd44..22fb67be0 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -10,7 +10,6 @@ enable_testing() # Unit testing directories ####################################################################### -add_subdirectory( src/GNDStk/test ) add_subdirectory( src/GNDStk/Defaulted/test ) add_subdirectory( src/GNDStk/Tree/test ) add_subdirectory( src/GNDStk/type2string/test ) @@ -20,13 +19,13 @@ add_subdirectory( src/GNDStk/string2type/test ) add_subdirectory( src/GNDStk/Meta/test ) add_subdirectory( src/GNDStk/XML/test ) add_subdirectory( src/GNDStk/JSON/test ) +add_subdirectory( src/GNDStk/HDF5/test ) add_subdirectory( src/GNDStk/Node/test ) -add_subdirectory( src/GNDStk/keyword/test ) add_subdirectory( src/GNDStk/Child/test ) add_subdirectory( src/GNDStk/convert/test ) add_subdirectory( src/GNDStk/utility/test ) add_subdirectory( src/GNDStk/Component/test ) -add_subdirectory( src/GNDStk/BodyText/test ) +add_subdirectory( src/GNDStk/BlockData/test ) add_subdirectory( src/GNDStk/precision/test ) add_subdirectory( src/GNDStk/enums/Encoding/test ) diff --git a/docs/build.rst b/docs/build.rst index 89d8e30de..0d4848f59 100644 --- a/docs/build.rst +++ b/docs/build.rst @@ -78,7 +78,7 @@ it depends -- automatically. The *bad* news is that the download may, for the same reason, take quite some time. Resist the temptation to terminate the command, perhaps believing that your computer has hung, and consider starting ``cmake ..`` before lunch hour if you have a slow Internet connection. The main -culprit appears to be the "nlohmann json" library, +culprit appears to be the `nlohmann/json` library, https://github.com/nlohmann/json. An excellent library, by all accounts, and invaluable as the workhorse for GNDStk's JSON capabilities; but responsible, at the time of the writing, for over 400MB -- about 95% -- of diff --git a/docs/files/code-tables/node-add-child.cc b/docs/files/code-tables/node-add-child.cc index 820bb982b..97dd3372c 100644 --- a/docs/files/code-tables/node-add-child.cc +++ b/docs/files/code-tables/node-add-child.cc @@ -1,6 +1,6 @@ // string -Node &add( const string &name = "" ); +Node &add( const string &name = emptyNodeName ); // value Node &add( const T &val ); diff --git a/docs/files/code-tables/node-multi.cc b/docs/files/code-tables/node-multi.cc index 9b3fe048a..2d9090a6e 100644 --- a/docs/files/code-tables/node-multi.cc +++ b/docs/files/code-tables/node-multi.cc @@ -1,3 +1,3 @@ -auto operator()( const KeywordTup &kwds ) const; -auto operator()( const KeywordTup &kwds ); +auto operator()( const KeyTuple &keytup ) const; +auto operator()( const KeyTuple &keytup ); diff --git a/docs/primer.rst b/docs/primer.rst index 724fb8f2b..fb7863db5 100644 --- a/docs/primer.rst +++ b/docs/primer.rst @@ -207,7 +207,7 @@ Here's a simple code that reads the XML format GNDS file named Obviously, but worth a reminder, this assumes that the file resides right there, in the directory from which this code is run. If it doesn't, include a suitable -absolute or relative path in the file name string. We, and no doubt everyone +absolute or relative path in the file name. We, and no doubt everyone reading this, have probably made this mistake often enough over the years. ``Tree`` is GNDStk's data structure for holding an entire GNDS hierarchy, a.k.a. @@ -262,8 +262,6 @@ or can be a direct string: ``"xml"``, etc. A direct string is shorter and slightly easier to type -- but, if mistyped, would lead to a run-time error, not a compile-time error, if that matters to you in this simple context. -**HDF5 is not supported at this time!** Just XML and JSON. - *You should seldom, if ever, need to provide the second argument*. Absent the second argument, **GNDStk determines the file type automatically**, and we doubt that you'll have any objections to that. If you do choose provide the second @@ -276,9 +274,9 @@ as we attempt to read the file pursuant to the (incorrect) forced format. GNDStk uses the "file magic number," not the file name, to determine file type automatically. The file magic number really means the first byte, or bytes, -of the file. XML files always begin with a ``<`` character. HDF files (not -supported yet) begin with ASCII 137 and a few other specific bytes. If the -first byte is neither of those values, then GNDStk assumes JSON format. +of the file. XML files always begin with a ``<`` character. HDF5 files begin +with ASCII 137 and a few other specific bytes. If the first byte is neither +of those values, then GNDStk assumes JSON format. A nice thing about using the file magic number, not the file name, is that it works for ``std::istream``, for which a "file name" isn't even available. @@ -325,7 +323,7 @@ then GNDStk will write file ``pu239.xml`` in JSON format, as you asked for in the second argument, but will warn that the file extension is inconsistent with the format you asked for. -What if the file name extension isn't given, or isn't recognized, *and* a format +What if the file extension isn't given, or isn't recognized, *and* a format isn't forced with a second argument? That is, what if we wrote, for example, ``pu239.write("pu239")``? In that case, ``write`` writes the ``Tree`` into a simple output format that we created largely for debugging purposes. You @@ -406,7 +404,7 @@ Several remarks are in order here. The comparison operator for ``Tree`` compares the two GNDS trees in an *order-agnostic* manner. GNDS fundamentally provides data in two places: nodes (think XML "elements") in its overall tree structure, and metadata (think XML -"attributes"). The GNDS standard does not, however, consider ordering to be +attributes). The GNDS standard does not, however, consider ordering to be important. One tree node's child nodes or metadata, anywhere or everywhere throughout the entire tree structure, could be reordered arbitrarily, but if each remains equivalent -- in the same respect that we consider two mathematical @@ -492,14 +490,31 @@ with what XML is able to represent. the node. For example, in HDF5 the attribute ``nodeIndex`` could be added to each child in a group. -For (1), GNDStk does the first suggested action: it groups all of a node's -attributes under a child node called ``attributes``. We consider that to be -cleaner than using an ``_attr`` suffix. - -For (2), GNDStk does exactly as illustrated: multiple elements of the same name -are suffixed with ``0``, ``1``, etc. And, then, a JSON name/value pair with the -name ``nodeName``, as suggested, is created in order to preserve the original -*unsuffixed* element's name. +For (1), GNDStk does largely the first suggested action (which we think is +somewhat cleaner than using an ``_attr`` suffix), but with a slight twist, +along with our preferred terminology of ``metadata`` in place of ``attributes``. +It groups a node's metadata -- attributes -- under a child node +called ``#metadata``. + +The ``#`` prefix is something we use in node names throughout GNDStk, +if and where +the nodes so named represent special things -- with special meaning, and needing +special treatment. The extra character allows special nodes to be identified +easily, in both the GNDStk code base itself or in files produced by GNDStk. +Moreover, one could imagine that a future GNDS version might -- just might -- +have a normal node with the name ``metadata``, or with some other name that +we might wish to use for a special purpose. If and where such situations occur, +our use of a special prefix character allows for an unambiguous interpretation. +(As an aside: in principle, we'd have preferred to use the S-like dollar sign, +``$``, to inside S for "special" node. Unfortunately, ``$`` has a particular +meaning in the C++ regular-expression library. As such, ``$`` is unsuitable +for use in identifying special nodes, as our various node-finding capabilities +support the use of regular expressions.) + +For (2), GNDStk does as suggested, except again with the ``#`` terminology as +described above, and an all-lowercase name. Multiple elements of the same name +are suffixed with ``0``, ``1``, etc. Then, a JSON name/value pair with the +name ``#nodename`` is created. Its value preserves the original element's name. For (3), GNDStk does nothing in particular right now. Our understanding of GNDS is that it's designed so that elements -- nodes -- can appear in any order. @@ -509,7 +524,7 @@ GNDS file that we've been using for our examples: .. literalinclude:: tutorial/xml-axes-fragment.xml :language: xml -Those ``axis`` child nodes already contain a 0-based ``index`` attribute, so +Those ``axis`` child nodes already contain a 0-based ``index`` metadatum, so perhaps the specification's admonishment #3 is something we can consider to have been satisfied already by whomever has created an existing, valid GNDS file (so that no further treatment is required); or something that *we* must satisfy if @@ -549,8 +564,8 @@ node. (Valid GNDS top-level nodes, per the standard, are ``reactionSuite``, about it for now. Naturally, GNDStk reverses the modifications when we *read* from a JSON file -into our internal format. Specifically: values in an ``attributes`` block are -transformed into metadata in the enclosing node, and values from ``nodeName`` +into our internal format. Specifically: values in a ``#metadata`` block are +transformed into metadata in the enclosing node, and values from ``#nodename`` name/value pairs replace index-suffixed names. At this time, GNDStk provides no other options, such as the ``_attr`` suffix @@ -560,7 +575,7 @@ We're not aware, at the time of this writing, of the existence any official JSON-format GNDS files. If and when such files come into existence, and if such files use a different scheme than we do for addressing the issues described above, then we'll provide capabilities at least for reading those -files, and perhaps for writing them in that manner as well. +files, and perhaps for writing files in that manner as well. @@ -770,7 +785,7 @@ the top of the ``n-094_Pu_239.xml`` GNDS file: :language: xml Here, an outer ``evaluated`` node (XML "element") contains four metadata -key/value pairs (XML "attributes") and two child elements. The first child +key/value pairs (XML attributes) and two child elements. The first child element, ``temperature``, contains two metadata pairs but no further child nodes. The second child element, ``projectileEnergyDomain``, contains three metadata pairs but no further child nodes. diff --git a/docs/ref-core.rst b/docs/ref-core.rst index 76058e2da..a427144bd 100644 --- a/docs/ref-core.rst +++ b/docs/ref-core.rst @@ -28,5 +28,5 @@ Child ======================================== ======================================== -KeywordTup +KeyTuple ======================================== diff --git a/docs/tutorial/employees.json b/docs/tutorial/employees.json index 37bb8442b..98371f024 100644 --- a/docs/tutorial/employees.json +++ b/docs/tutorial/employees.json @@ -2,30 +2,30 @@ "employees": { "employee0": { "name": { - "attributes": { + "#metadata": { "first": "Doc", "last": "Jones" } }, - "nodeName": "employee" + "#nodename": "employee" }, "employee1": { "name": { - "attributes": { + "#metadata": { "first": "Grumpy", "last": "Smith" } }, - "nodeName": "employee" + "#nodename": "employee" }, "employee2": { "name": { - "attributes": { + "#metadata": { "first": "Happy", "last": "Earp" } }, - "nodeName": "employee" + "#nodename": "employee" } } -} \ No newline at end of file +} diff --git a/docs/tutorial/file-types.hpp b/docs/tutorial/file-types.hpp index df64dc575..1106d833b 100644 --- a/docs/tutorial/file-types.hpp +++ b/docs/tutorial/file-types.hpp @@ -1,6 +1,6 @@ enum class FileType { - null, // Default, automagick, etc. - tree, // <== DON't use this for reading; just writing + guess, // Default, automagick, etc. + debug, // <== DON't use this for reading; just writing // Generally use one of these: xml, XML = xml, json, JSON = json, diff --git a/python/runtests.sh b/python/runtests.sh index c94247071..00d375d4e 100755 --- a/python/runtests.sh +++ b/python/runtests.sh @@ -3,6 +3,6 @@ # this script copies the dynamic library for the GNDStk python module # and runs all the unit tests it can find -rm GNDStk.*.so -cp ../build/GNDStk.*.so . +rm GNDStk*.so +cp ../build/GNDStk*.so . python -m unittest discover -v -p "Test*" diff --git a/python/src/core/Node.python.cpp b/python/src/core/Node.python.cpp index ff2e7f377..05a6d677a 100644 --- a/python/src/core/Node.python.cpp +++ b/python/src/core/Node.python.cpp @@ -13,7 +13,7 @@ namespace core { void wrapNode( python::module& module ) { // type aliases - using Component = njoy::GNDStk::core::Node; + using Component = njoy::GNDStk::Node; using ConstRefComponent = std::reference_wrapper< const Component >; // create the core component diff --git a/python/src/definitions.hpp b/python/src/definitions.hpp index 230bd1d99..8e9b91e7a 100644 --- a/python/src/definitions.hpp +++ b/python/src/definitions.hpp @@ -37,7 +37,7 @@ void addStandardComponentDefinitions( PythonClass& component ) { "from_string", [] ( const std::string& string ) -> Component { - using namespace njoy::GNDStk::core; + using namespace njoy::GNDStk; Node node; node << string; @@ -45,7 +45,7 @@ void addStandardComponentDefinitions( PythonClass& component ) { return Component( node ); }, python::arg( "string" ), - "Read the component from an XML or json string\n\n" + "Read the component from an XML or JSON string\n\n" "An exception is raised if something goes wrong while reading the\n" "component\n\n" "Arguments:\n" @@ -56,7 +56,7 @@ void addStandardComponentDefinitions( PythonClass& component ) { "to_xml_string", [] ( const Component& self ) -> std::string { - using namespace njoy::GNDStk::core; + using namespace njoy::GNDStk; std::ostringstream out; XML( Node( self ) ).write( out, false ); @@ -72,7 +72,7 @@ void addStandardComponentDefinitions( PythonClass& component ) { "to_xml_file", [] ( const Component& self, const std::string& fileName ) { - using namespace njoy::GNDStk::core; + using namespace njoy::GNDStk; XML( Node( self ) ).write( fileName ); }, diff --git a/python/src/v1.9/containers.python.cpp b/python/src/v1.9/containers.python.cpp index 31ab9e593..a53851541 100644 --- a/python/src/v1.9/containers.python.cpp +++ b/python/src/v1.9/containers.python.cpp @@ -12,8 +12,8 @@ namespace python_v1_9 { // containers declarations namespace python_containers { - void wrapAxis(python::module &); void wrapLink(python::module &); + void wrapAxis(python::module &); void wrapValues(python::module &); void wrapGrid(python::module &); void wrapAxes(python::module &); @@ -31,8 +31,8 @@ void wrapContainers(python::module &module) ); // wrap containers components - python_containers::wrapAxis(submodule); python_containers::wrapLink(submodule); + python_containers::wrapAxis(submodule); python_containers::wrapValues(submodule); python_containers::wrapGrid(submodule); python_containers::wrapAxes(submodule); diff --git a/python/src/v1.9/containers/Axes.python.cpp b/python/src/v1.9/containers/Axes.python.cpp index b3bebd4f9..5ecb7fe23 100644 --- a/python/src/v1.9/containers/Axes.python.cpp +++ b/python/src/v1.9/containers/Axes.python.cpp @@ -54,7 +54,8 @@ void wrapAxes(python::module &module) ) .def_property_readonly( "axis_grid", - python::overload_cast<>(&Component::axis_grid), + (const std::vector &(Component::*)() const) + &Component::axis_grid, Component::documentation("axis_grid").data() ) ; diff --git a/python/src/v1.9/containers/Grid.python.cpp b/python/src/v1.9/containers/Grid.python.cpp index e8556d74e..4fc7dad78 100644 --- a/python/src/v1.9/containers/Grid.python.cpp +++ b/python/src/v1.9/containers/Grid.python.cpp @@ -25,8 +25,8 @@ void wrapGrid(python::module &module) // type aliases using Component = containers::Grid; using link_values_t = std::variant< - containers::Link, - containers::Values + containers::Values, + containers::Link >; // create the component @@ -80,16 +80,16 @@ void wrapGrid(python::module &module) &Component::unit, Component::documentation("unit").data() ) - .def_property_readonly( - "link", - python::overload_cast<>(&Component::link), - Component::documentation("link").data() - ) .def_property_readonly( "values", python::overload_cast<>(&Component::values), Component::documentation("values").data() ) + .def_property_readonly( + "link", + python::overload_cast<>(&Component::link), + Component::documentation("link").data() + ) .def_property_readonly( "link_values", python::overload_cast<>(&Component::link_values), diff --git a/python/src/v1.9/containers/Regions1d.python.cpp b/python/src/v1.9/containers/Regions1d.python.cpp index 35ab3052f..37df3134f 100644 --- a/python/src/v1.9/containers/Regions1d.python.cpp +++ b/python/src/v1.9/containers/Regions1d.python.cpp @@ -38,13 +38,13 @@ void wrapRegions1d(python::module &module) python::init< const std::optional &, const std::optional &, - const std::vector &, - const std::optional & + const std::optional &, + const std::vector & >(), python::arg("label") = std::nullopt, python::arg("outer_domain_value") = std::nullopt, - python::arg("xys1d"), python::arg("axes") = std::nullopt, + python::arg("xys1d"), Component::documentation("constructor").data() ) .def_property_readonly( @@ -57,16 +57,17 @@ void wrapRegions1d(python::module &module) &Component::outerDomainValue, Component::documentation("outer_domain_value").data() ) - .def_property_readonly( - "xys1d", - python::overload_cast<>(&Component::XYs1d), - Component::documentation("xys1d").data() - ) .def_property_readonly( "axes", python::overload_cast<>(&Component::axes), Component::documentation("axes").data() ) + .def_property_readonly( + "xys1d", + (const std::vector &(Component::*)() const) + &Component::XYs1d, + Component::documentation("xys1d").data() + ) ; // add standard component definitions diff --git a/python/src/v1.9/containers/Values.python.cpp b/python/src/v1.9/containers/Values.python.cpp index b9c28e406..9c9a1c58c 100644 --- a/python/src/v1.9/containers/Values.python.cpp +++ b/python/src/v1.9/containers/Values.python.cpp @@ -36,13 +36,13 @@ void wrapValues(python::module &module) component .def( python::init< + const std::optional &, const std::optional &, - const std::optional &, - const std::optional & + const std::optional & >(), - python::arg("length") = std::nullopt, - python::arg("start") = std::nullopt, python::arg("value_type") = std::nullopt, + python::arg("start") = std::nullopt, + python::arg("length") = std::nullopt, Component::documentation("constructor").data() ) .def( @@ -67,9 +67,9 @@ void wrapValues(python::module &module) Component::documentation("constructor").data() ) .def_property_readonly( - "length", - &Component::length, - Component::documentation("length").data() + "value_type", + [](const Component &self) { return self.valueType().value(); }, + Component::documentation("value_type").data() ) .def_property_readonly( "start", @@ -77,9 +77,9 @@ void wrapValues(python::module &module) Component::documentation("start").data() ) .def_property_readonly( - "value_type", - [](const Component &self) { return self.valueType().value(); }, - Component::documentation("value_type").data() + "length", + &Component::length, + Component::documentation("length").data() ) .def_property_readonly( "ints", diff --git a/python/src/v1.9/transport/CrossSection.python.cpp b/python/src/v1.9/transport/CrossSection.python.cpp index 4bb4c39c2..0bfccc711 100644 --- a/python/src/v1.9/transport/CrossSection.python.cpp +++ b/python/src/v1.9/transport/CrossSection.python.cpp @@ -47,7 +47,8 @@ void wrapCrossSection(python::module &module) ) .def_property_readonly( "xys1d_regions1d", - python::overload_cast<>(&Component::XYs1d_regions1d), + (const std::vector &(Component::*)() const) + &Component::XYs1d_regions1d, Component::documentation("xys1d_regions1d").data() ) ; diff --git a/python/src/v1.9/transport/ReactionSuite.python.cpp b/python/src/v1.9/transport/ReactionSuite.python.cpp index 664310fc2..13282c115 100644 --- a/python/src/v1.9/transport/ReactionSuite.python.cpp +++ b/python/src/v1.9/transport/ReactionSuite.python.cpp @@ -38,18 +38,18 @@ void wrapReactionSuite(python::module &module) python::init< const std::string &, const std::string &, - const std::optional &, const std::string &, const enums::Frame &, const std::string &, + const std::optional &, const std::optional & >(), python::arg("evaluation"), python::arg("format"), - python::arg("interaction") = std::nullopt, python::arg("projectile"), python::arg("projectile_frame"), python::arg("target"), + python::arg("interaction") = std::nullopt, python::arg("reactions") = std::nullopt, Component::documentation("constructor").data() ) @@ -63,11 +63,6 @@ void wrapReactionSuite(python::module &module) &Component::format, Component::documentation("format").data() ) - .def_property_readonly( - "interaction", - &Component::interaction, - Component::documentation("interaction").data() - ) .def_property_readonly( "projectile", &Component::projectile, @@ -83,28 +78,16 @@ void wrapReactionSuite(python::module &module) &Component::target, Component::documentation("target").data() ) + .def_property_readonly( + "interaction", + &Component::interaction, + Component::documentation("interaction").data() + ) .def_property_readonly( "reactions", python::overload_cast<>(&Component::reactions), Component::documentation("reactions").data() ) - .def_static( - - "from_file", - [] ( const std::string& filename ) -> Component { - - using namespace njoy::GNDStk::core; - Tree tree( filename ); - - return Component( tree( child::reactionSuite ) ); - }, - python::arg( "filename" ), - "Read a reaction suite from an XML or json file\n\n" - "An exception is raised if something goes wrong while reading the\n" - "component\n\n" - "Arguments:\n" - " filename the name of the file" - ) ; // add standard component definitions diff --git a/python/src/v1.9/transport/Reactions.python.cpp b/python/src/v1.9/transport/Reactions.python.cpp index a32c28b59..d3ed77bed 100644 --- a/python/src/v1.9/transport/Reactions.python.cpp +++ b/python/src/v1.9/transport/Reactions.python.cpp @@ -43,7 +43,8 @@ void wrapReactions(python::module &module) ) .def_property_readonly( "reaction", - python::overload_cast<>(&Component::reaction), + (const std::vector &(Component::*)() const) + &Component::reaction, Component::documentation("reaction").data() ) ; diff --git a/python/test/Test_GNDStk_GridStyle.pyc b/python/test/Test_GNDStk_GridStyle.pyc new file mode 100644 index 000000000..e5734f548 Binary files /dev/null and b/python/test/Test_GNDStk_GridStyle.pyc differ diff --git a/python/test/Test_GNDStk_Interpolation.pyc b/python/test/Test_GNDStk_Interpolation.pyc new file mode 100644 index 000000000..feefb9231 Binary files /dev/null and b/python/test/Test_GNDStk_Interpolation.pyc differ diff --git a/python/test/__init__.pyc b/python/test/__init__.pyc new file mode 100644 index 000000000..b65ba59b5 Binary files /dev/null and b/python/test/__init__.pyc differ diff --git a/python/test/core/Test_GNDStk_core_Node.pyc b/python/test/core/Test_GNDStk_core_Node.pyc new file mode 100644 index 000000000..e48dd2c5e Binary files /dev/null and b/python/test/core/Test_GNDStk_core_Node.pyc differ diff --git a/python/test/core/__init__.pyc b/python/test/core/__init__.pyc new file mode 100644 index 000000000..f09dbaae2 Binary files /dev/null and b/python/test/core/__init__.pyc differ diff --git a/python/test/v1_9/__init__.pyc b/python/test/v1_9/__init__.pyc new file mode 100644 index 000000000..fdd90207b Binary files /dev/null and b/python/test/v1_9/__init__.pyc differ diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.py b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.py index 4969f1ff9..3e6a11a66 100644 --- a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.py +++ b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.py @@ -9,7 +9,7 @@ class Test_GNDStk_v1_9_containers_Axis( unittest.TestCase ) : """Unit test for the Section class.""" - chunk = ( '\n' ) + chunk = ( '' ) wrong = ( '' ) def test_component( self ) : diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.pyc b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.pyc new file mode 100644 index 000000000..6e0eb65db Binary files /dev/null and b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Axis.pyc differ diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.py b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.py index 133fdd77a..db6933174 100644 --- a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.py +++ b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.py @@ -12,14 +12,14 @@ class Test_GNDStk_v1_9_containers_Grid( unittest.TestCase ) : """Unit test for the Section class.""" chunk = ( '\n' - ' 1e-05 2e+07\n' - '\n' ) + ' 1e-05 2e+07\n' + '' ) chunkWithLink = ( '\n' ' \n' - '\n' ) + '' ) wrong = ( '\n' - ' 1e-05 2e+07\n' - '\n' ) + ' 1e-05 2e+07\n' + '' ) def test_component( self ) : diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.pyc b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.pyc new file mode 100644 index 000000000..be8526172 Binary files /dev/null and b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Grid.pyc differ diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.py b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.py index 9e28cc6ac..ad607c36f 100644 --- a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.py +++ b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.py @@ -9,8 +9,8 @@ class Test_GNDStk_v1_9_containers_Link( unittest.TestCase ) : """Unit test for the Section class.""" - chunk = ( '\n' ) - wrong = ( '\n' ) + chunk = ( '' ) + wrong = ( '' ) def test_component( self ) : diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.pyc b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.pyc new file mode 100644 index 000000000..d96a2d7be Binary files /dev/null and b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Link.pyc differ diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.py b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.py index 117ea1178..435bffffe 100644 --- a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.py +++ b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.py @@ -9,10 +9,10 @@ class Test_GNDStk_v1_9_containers_Values( unittest.TestCase ) : """Unit test for the Section class.""" - chunk_doubles = ( '2500 8.9172 2550 8.9155\n' ) - chunk_ints = ( '2500 9 2550 9\n' ) - chunk_strings = ( '2500 8.9172 2550 8.9155\n' ) - wrong = ( '2500 8.9172 2550 8.9155\n' ) + chunk_doubles = ( '2500 8.9172 2550 8.9155' ) + chunk_ints = ( '2500 9 2550 9' ) + chunk_strings = ( '2500 8.9172 2550 8.9155' ) + wrong = ( '2500 8.9172 2550 8.9155' ) def test_component( self ) : diff --git a/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.pyc b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.pyc new file mode 100644 index 000000000..3124295ed Binary files /dev/null and b/python/test/v1_9/containers/Test_GNDStk_v1_9_containers_Values.pyc differ diff --git a/python/test/v1_9/containers/__init__.pyc b/python/test/v1_9/containers/__init__.pyc new file mode 100644 index 000000000..56255e4e3 Binary files /dev/null and b/python/test/v1_9/containers/__init__.pyc differ diff --git a/src/GNDStk.hpp b/src/GNDStk.hpp index c665be5ae..cd505cecc 100644 --- a/src/GNDStk.hpp +++ b/src/GNDStk.hpp @@ -8,6 +8,8 @@ #include "pugixml.hpp" #include "nlohmann/json.hpp" +#include +#include #include "Log.hpp" @@ -26,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,90 +58,46 @@ namespace njoy { namespace GNDStk { -// basic +// Basic #include "GNDStk/utility.hpp" #include "GNDStk/precision.hpp" #include "GNDStk/enums.hpp" -// external-library wrappers +// External-library wrappers #include "GNDStk/XML.hpp" #include "GNDStk/JSON.hpp" +#include "GNDStk/HDF5.hpp" -// string/Node to/from type +// std::string/Node to/from type #include "GNDStk/string2type.hpp" #include "GNDStk/type2string.hpp" // Meta, Child, and related -#include "GNDStk/convert_t.hpp" #include "GNDStk/Meta.hpp" #include "GNDStk/Child.hpp" -#include "GNDStk/keyword.hpp" #include "GNDStk/or.hpp" -// optional, with default +// Like std::optional, but with a default #include "GNDStk/Defaulted.hpp" -// sets of Meta/Child -#include "GNDStk/basic.hpp" -#include "GNDStk/misc.hpp" - -// Tree: primary constructs +// Main classes #include "GNDStk/Node.hpp" #include "GNDStk/Tree.hpp" -// fixme This really belongs with basic.hpp and misc.hpp above, but I had to -// move it here due to some ordering issues that arose when I de-templated -// Node and Tree. We'll deal with this later; it's an internal issue, not -// something that will affect users in any manner. -#include "GNDStk/common.hpp" - // Node to/from type #include "GNDStk/node2type.hpp" #include "GNDStk/type2node.hpp" -// xml/json/tree conversions +// Node/XML/JSON/HDF5 conversions #include "GNDStk/convert.hpp" -// fixme See above fixme -namespace basic { using namespace common; } -namespace misc { using namespace common; } - // Miscellaneous support constructs for Standard Interface classes #include "GNDStk/Support.hpp" +#include "GNDStk/Lookup.hpp" // Base classes for primary Standard Interface data classes -#include "GNDStk/BodyText.hpp" +#include "GNDStk/BlockData.hpp" #include "GNDStk/Component.hpp" - -// ------------------------ -// GNDStk "core interface" -// ------------------------ - -/* -In a user code, writing this: - - using namespace njoy::GNDStk::core; - -gives the same effect as writing this: - - using namespace njoy::GNDStk; - using namespace njoy::GNDStk::basic; - -Meaning: We consider our "core interface" to consist of everything in GNDStk:: -proper, plus our basic:: set of Meta and Child objects. Those are the ones with - type, so that they return metadata and nodes in their original tree form. -Note that basic:: itself brings in Meta and Child objects from its own nested -meta:: and child:: namespaces. Those are separate because there's a small amount -of overlap between allowable GNDS metadatum names and node names. With this -scheme, if a name you wish to use isn't one of the overlapping names, just use -it. If it is, then prefix with meta:: or child:: as necessary. -*/ - -namespace core { - using namespace GNDStk; - using namespace basic; -} - } // namespace GNDStk } // namespace njoy diff --git a/src/GNDStk/BodyText.hpp b/src/GNDStk/BlockData.hpp similarity index 61% rename from src/GNDStk/BodyText.hpp rename to src/GNDStk/BlockData.hpp index 7b963fd0c..2e4bfe3e6 100644 --- a/src/GNDStk/BodyText.hpp +++ b/src/GNDStk/BlockData.hpp @@ -2,20 +2,20 @@ // Printing-related colors. // todo Eventually, this probably belongs in a more context-agnostic // location, such as GNDStk's utility.hpp file or something like it. -#include "GNDStk/BodyText/src/colors.hpp" +#include "GNDStk/BlockData/src/colors.hpp" // Miscellaneous helper constructs. -#include "GNDStk/BodyText/src/detail.hpp" +#include "GNDStk/BlockData/src/detail.hpp" // ----------------------------------------------------------------------------- -// BodyText -// The case is specialized and has the fun stuff. This one needs -// just a bit of content, in order to facilitate uniform treatment of BodyText. +// BlockData +// The case is specialized and has the fun stuff. This one needs +// just a bit of content, in order to facilitate uniform treatment of BlockData. // ----------------------------------------------------------------------------- -template -class BodyText { +template +class BlockData { public: using VariantOfVectors = std::variant; using VariantOfScalars = std::variant; @@ -26,32 +26,32 @@ class BodyText { // ----------------------------------------------------------------------------- -// BodyText +// BlockData // // Designed to be flexible, smart, and safe. Does lots of checks, and, for the -// DATA == void case, can essentially re-form itself depending on what type of -// data someone tries to extract. +// DATATYPE == void case, can essentially re-form itself depending on what type +// of data someone tries to extract. // -// For efficiency in the DATA == void case, an application might want to copy -// to its own vector (e.g. auto myvec = mybodytext.get>()) +// For efficiency in the DATATYPE == void case, an application may want to copy +// to its own vector (e.g. auto myvec = myblockdata.get>()) // in order to do work on (or with) the vector there, before copying it back. // ----------------------------------------------------------------------------- -template -class BodyText { +template +class BlockData { public: - #include "GNDStk/BodyText/src/types.hpp" + #include "GNDStk/BlockData/src/types.hpp" // For convenience in various SFINAE and if-constexpr constructs - static inline constexpr bool runtime = detail::isVoid; + static inline constexpr bool runtime = detail::isVoid; template struct is_supported { static inline constexpr bool value = ( runtime && detail::isAlternative) || (!runtime && ( - std::is_constructible_v || - std::is_convertible_v + std::is_constructible_v || + std::is_convertible_v )); }; template @@ -69,17 +69,17 @@ class BodyText { std::string rawstring; // Vector of . + // *** This will be used if, and only if, DATATYPE == void. // Mutable, so that we can defer processing of the raw string into // a vector until, and unless, a caller *asks* for the vector. - // This will be used if, and only if, DATA == void. mutable VariantOfVectors variant; - // Vector of - // This will be used if, and only if, DATA != void. + // Vector of + // *** This will be used if, and only if, DATATYPE != void. // data_t is used in a few places where, without it, we'd create compilation // errors by using "void" in invalid ways. The "int" below is arbitrary - - // essentially a placeholder; the following is only used when !runtime. - using data_t = std::conditional_t; + // basically a placeholder - because the following is used only if !runtime. + using data_t = std::conditional_t; mutable std::vector vector; public: @@ -87,23 +87,23 @@ class BodyText { // Parameters that affect interpretation of the raw string: // struct vars { length, start, valueType } // Includes public getters and setters for those. - // We won't use valueType if DATA != void. - #include "GNDStk/BodyText/src/params.hpp" + // We won't use valueType if DATATYPE != void. + #include "GNDStk/BlockData/src/params.hpp" // trim - // Flag: should the conversion of BodyText data back into textual data, + // Flag: should the conversion of BlockData data back into textual data, // in a Node, trim zeros from the start and end of the output? mutable bool trim = true; // Getters and setters for the raw string: - #include "GNDStk/BodyText/src/string.hpp" + #include "GNDStk/BlockData/src/string.hpp" // active() Active active() const { return act; } // clear() // Clears the vector, or the active vector alternative in the variant. - BodyText &clear() + BlockData &clear() { if constexpr (runtime) std::visit([](auto &&alt) { alt.clear(); }, variant); @@ -117,7 +117,7 @@ class BodyText { // size() // Returns the size of the vector, or of the active vector alternative in // the variant. Depending on what someone may or may not have done with the - // current BodyText object, size() might or might not reflect the values of + // current BlockData object, size() might or might not reflect the values of // length and/or start, or reflect the current contents of the raw string. std::size_t size() const { @@ -128,21 +128,32 @@ class BodyText { } // Various vector get() functions, and the type-specific doubles() etc. - #include "GNDStk/BodyText/src/get.hpp" + #include "GNDStk/BlockData/src/get.hpp" // Read/write data, from/to a Node - #include "GNDStk/BodyText/src/fromNode.hpp" - #include "GNDStk/BodyText/src/toNode.hpp" + #include "GNDStk/BlockData/src/fromNode.hpp" + #include "GNDStk/BlockData/src/toNode.hpp" - // Write to ostream - // Not to be confused with the process of writing data to a Node - #include "GNDStk/BodyText/src/write.hpp" + // Print to ostream + #include "GNDStk/BlockData/src/print.hpp" - // Pull/push length/start/valueType from/to derived-class struct content - #include "GNDStk/BodyText/src/sync.hpp" + // Pull/push length/start/valueType from/to derived-class struct Content + #include "GNDStk/BlockData/src/sync.hpp" // Assignment // From string or vector; the former == calling our raw string setter - #include "GNDStk/BodyText/src/assign.hpp" + #include "GNDStk/BlockData/src/assign.hpp" + + // Conversion to vector + // *** Available if, and only if, DATATYPE != void. + template< + class T = DATATYPE, + class = std::enable_if_t> + > + operator std::vector() const + { + // get(), not vector; get() handles properly if the string is active + return get(); + } -}; // class BodyText +}; // class BlockData diff --git a/src/GNDStk/BodyText/src/assign.hpp b/src/GNDStk/BlockData/src/assign.hpp similarity index 83% rename from src/GNDStk/BodyText/src/assign.hpp rename to src/GNDStk/BlockData/src/assign.hpp index b1b975822..c809b3a80 100644 --- a/src/GNDStk/BodyText/src/assign.hpp +++ b/src/GNDStk/BlockData/src/assign.hpp @@ -4,7 +4,7 @@ // Same effect as the string(new string) setter // ----------------------------------------------------------------------------- -BodyText &operator=(const std::string &str) +BlockData &operator=(const std::string &str) { return string(str); } @@ -17,15 +17,15 @@ BodyText &operator=(const std::string &str) /* DISCUSSION -Elsewhere, a BodyText object can be made from a GNDS node. From GNDS, we get +Elsewhere, a BlockData object can be made from a GNDS node. From GNDS, we get a text string (copied to the rawstring field), from which a vector of values can be created on an as-needed basis. A GNDS node might also give us any of length, start, and valueType, which, when pulling data from the Node, we'll use if they're there, or otherwise assume to be our defaults. -Here, we're allowing for an assignment BodyText = vector. For this assignment, +Here, we're allowing for an assignment BlockData = vector. For this assignment, the caller should send the full, complete vector of values that's appropriate -for the GNDS Node whose data this BodyText object is intended to represent. +for the GNDS Node whose data this BlockData object is intended to represent. Specifically: the vector should contain whatever leading and/or trailing 0s the full data vector is supposed to have. The length and start values are @@ -40,14 +40,14 @@ assigning here.) As for valueType, this function attempts to guess it from the vector's element type, and sets it to "", the empty string, if we don't recognize that type. -If a vector that's assigned from, here, is still in play when this BodyText's +If a vector that's assigned from, here, is still in play when this BlockData's data are written to a Node (see the toNode() function), then toNode() will recompute length and start automatically, based on the vector's beginning and ending content, if the "trim" flag is set. See toNode() for more information. */ template -std::enable_if_t, BodyText &> +std::enable_if_t, BlockData &> operator=(const std::vector &vec) { // set the raw string to "", because it's no longer considered meaningful @@ -56,18 +56,18 @@ operator=(const std::vector &vec) // length, start, valueType length(vec.size()); start(0); - valueType(detail::MapTypeString::value[0]); + valueType(detail::Type2Names::value[0]); // assign vector if constexpr (runtime) variant = vec; - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) vector = vec; else { vector.clear(); vector.reserve(vec.size()); for (const T &element : vec) - vector.push_back(DATA(element)); + vector.push_back(DATATYPE(element)); } act = Active::vector; diff --git a/src/GNDStk/BodyText/src/colors.hpp b/src/GNDStk/BlockData/src/colors.hpp similarity index 98% rename from src/GNDStk/BodyText/src/colors.hpp rename to src/GNDStk/BlockData/src/colors.hpp index f8850fde7..0f0c0affb 100644 --- a/src/GNDStk/BodyText/src/colors.hpp +++ b/src/GNDStk/BlockData/src/colors.hpp @@ -80,7 +80,7 @@ inline std::string bracket = plain::yellow; inline std::string optional = plain::cyan; inline std::string defaulted = plain::blue; -// Values in nodes with "body text" +// Values in nodes with block data inline std::string value = plain::white; // Comments diff --git a/src/GNDStk/BodyText/src/detail.hpp b/src/GNDStk/BlockData/src/detail.hpp similarity index 68% rename from src/GNDStk/BodyText/src/detail.hpp rename to src/GNDStk/BlockData/src/detail.hpp index dd5053e9e..9e52b0f2e 100644 --- a/src/GNDStk/BodyText/src/detail.hpp +++ b/src/GNDStk/BlockData/src/detail.hpp @@ -32,67 +32,60 @@ using decays_t = typename decays::type; // ----------------------------------------------------------------------------- // ------------------------ -// Helpers +// has_index // ------------------------ -// has_length -template -struct has_length - : std::false_type { }; - -template -struct has_length - : std::true_type { }; - -// has_start -template -struct has_start - : std::false_type { }; - -template -struct has_start - : std::true_type { }; - -// has_valueType -template -struct has_valueType - : std::false_type { }; - -template -struct has_valueType - : std::true_type { }; - -// has_index template struct has_index : std::false_type { }; template -struct has_index +struct has_index< + T, + decltype( + (void) + // Just using T{}.index() on the next line, like we do with other has_* + // classes above, can lead to an ambiguity between this specialization + // and the std::variant specialization below, arising from the fact that + // std::variant has an index() function. Hence the std::conditional_t. + std::conditional_t::value,void,T>{}.index(), + 0 + ) +> : std::true_type { }; +// for variant template struct has_index> { - // for variant: does any alternative have index? + // does any alternative have index? static constexpr bool value = (has_index::value || ...); }; +// ------------------------ // has_label +// ------------------------ + template struct has_label : std::false_type { }; template -struct has_label +struct has_label< + T, + // std::variant doesn't have a label(), like it has an index(), but we'll + // do the same thing here, for has_label, as we do above for has_index. + // It's harmless, and if std::variant is ever given a label() function... + decltype((void)std::conditional_t::value,void,T>{}.label(),0) +> : std::true_type { }; +// for variant template struct has_label> { // for variant: does any alternative have label? static constexpr bool value = (has_label::value || ...); }; - // ------------------------ // Prefer these. // They apply std::decay, @@ -100,15 +93,9 @@ struct has_label> { // ------------------------ template -inline constexpr bool hasLength = has_length >::value; -template -inline constexpr bool hasStart = has_start >::value; +inline constexpr bool hasIndex = has_index>::value; template -inline constexpr bool hasValueType = has_valueType>::value; -template -inline constexpr bool hasIndex = has_index >::value; -template -inline constexpr bool hasLabel = has_label >::value; +inline constexpr bool hasLabel = has_label>::value; @@ -167,4 +154,30 @@ auto getBounds(const std::vector &vec) return bnd; } + + +// ----------------------------------------------------------------------------- +// colorize_*(text) +// ----------------------------------------------------------------------------- + +#define gndstkPaste(one,two) one ## two +#define gndstkColorFun(part) \ + inline std::string gndstkPaste(colorize_,part)(const std::string &text) \ + { \ + return GNDStk::color && colors::part != "" \ + ? colors::part + text + colors::reset \ + : text; \ + } + + // colorize_label() etc. + gndstkColorFun(label) + gndstkColorFun(colon) + gndstkColorFun(component) + gndstkColorFun(brace) + gndstkColorFun(bracket) + gndstkColorFun(comment) + +#undef gndstkColorFun +#undef gndstkPaste + } // namespace detail diff --git a/src/GNDStk/BlockData/src/fromNode.hpp b/src/GNDStk/BlockData/src/fromNode.hpp new file mode 100644 index 000000000..d23d9b5c0 --- /dev/null +++ b/src/GNDStk/BlockData/src/fromNode.hpp @@ -0,0 +1,39 @@ + +// ----------------------------------------------------------------------------- +// BlockData::fromNode(Node) +// ----------------------------------------------------------------------------- + +void fromNode(const Node &node) +{ + // length, start, and valueType might be present in the Node, but we won't + // fetch any of them here. Elsewhere, the current BlockData object should + // have its length, start, and valueType pulled from those respective values + // in an object of a class derived from Component, which in turn derives from + // BlockData. That object's content will have been pulled from the same Node. + // Here, we just get the Node's values: "plain character data" in XML terms. + + bool found = false; + rawstring = node.pcdata(found); + + if (!found) { + rawstring = ""; + + // Warning, re: why are we in BlockData if there's no block + // data? Perhaps the Node has a non-default length and/or start, so that + // the values are all supposed to be...zero. Until and unless we discover + // otherwise, however, we doubt that that would be the case, and will + // consider a Node's lack of plain character data, in the present context, + // to be something that merits a warning. + log::warning( + "Component marked as having block data, a.k.a. XML \"pcdata\" " + "(plain\ncharacter data), " + "but no such content was found in the GNDS node." + ); + log::member("BlockData::fromNode(Node, with name \"{}\")", node.name); + } + + // Above, we set the raw string. The following reflects this, so that the + // vector, or a vector in the variant, will be rebuilt from the raw string + // if and when a caller asks for it. + act = Active::string; +} diff --git a/src/GNDStk/BodyText/src/get.hpp b/src/GNDStk/BlockData/src/get.hpp similarity index 79% rename from src/GNDStk/BodyText/src/get.hpp rename to src/GNDStk/BlockData/src/get.hpp index c2ff03d81..65e71300b 100644 --- a/src/GNDStk/BodyText/src/get.hpp +++ b/src/GNDStk/BlockData/src/get.hpp @@ -5,7 +5,7 @@ /* ------------------------ -When DATA == void +When DATATYPE == void ------------------------ Case 1 @@ -42,28 +42,28 @@ Type-specific getters with specific names: For example, name == doubles when T == double. ------------------------ -When DATA != void +When DATATYPE != void ------------------------ Case 1 Return reference to [const] vector: get> const get> -T must == DATA. +T must == DATATYPE. Case 2 Return reference to [const] T: get(n) const get(n) -T must == DATA. +T must == DATATYPE. Case 3 -Return reference to [const] vector +Return reference to [const] vector get() const get() Case 4 -Return reference to [const] DATA: +Return reference to [const] DATATYPE: get(n) const operator[](n) const get(n) @@ -71,13 +71,14 @@ Return reference to [const] DATA: Case 5 Type-specific getters with a specific name: - const std::vector &name() const - std::vector &name() - const DATA &name(n) const - DATA &name(n) -For example, name == doubles if DATA == double. Unlike in the DATA == void case, -we won't have this set of functions for each of name == doubles, name == ints, -name == strings, etc., but only for the name that's appropriate for type DATA. + const std::vector &name() const + std::vector &name() + const DATATYPE &name(n) const + DATATYPE &name(n) +For example, name == doubles if DATATYPE == double. Unlike in the DATATYPE == +void case, we won't have this set of functions for each of name == doubles, +name == ints, name == strings, etc., but only for the name that's appropriate +for type DATATYPE. */ @@ -107,7 +108,7 @@ If active == vector: If the variant already contains a vector: Return it; we're done. - *** Under the correct and normal use of BodyText, *** + *** Under the correct and normal use of BlockData, *** *** this simple action will probably be the most common. *** Else: @@ -117,7 +118,7 @@ If active == vector: In the active == vector case, length, start, and valueType aren't considered to be relevant, and play no role. We consider those values to be meaningful -ONLY in relation to BodyText's raw string, and we deal with them here only +ONLY in relation to BlockData's raw string, and we deal with them here only if and when we make the vector from the raw string. That way, callers can access, manipulate, and even completely change the @@ -144,7 +145,7 @@ vector in the variant. Note that because the variant was declared to be mutable, we were indeed able to rebuild the vector if doing so was necessary. But we'll still return a *const* reference in that case, because the present object is conceptually const, and a caller shouldn't therefore be allowed to -modify the vector outside of BodyText's machinery. +modify the vector outside of BlockData's machinery. Of course we also have a non-const version, for a non-const *this. */ @@ -154,7 +155,7 @@ Of course we also have a non-const version, for a non-const *this. template std::enable_if_t< ( runtime && detail::isAlternative) || - (!runtime && std::is_same_v>), + (!runtime && std::is_same_v>), const VECTOR & > get() const { @@ -168,7 +169,7 @@ std::enable_if_t< if (active() == Active::string) { static const std::string context_rebuilding = - "BodyText::get>(), remade from raw string"; + "BlockData::get>(), remade from raw string"; // Completely rebuild the vector from the raw string, making use of // length, start, and valueType. @@ -177,7 +178,7 @@ std::enable_if_t< // We'll print a warning if that vector type appears to conflict with // valueType. Regardless, we'll return what the caller requested. Note // that valueType == "" is acceptable with any element type. - if (valueType() != "" && !detail::MapTypeString::find(valueType())) { + if (valueType() != "" && !detail::Type2Names::find(valueType())) { log::warning( "Vector element type may be inconsistent with valueType \"{}\";\n" "we'll create the requested std::vector<> anyway", @@ -261,8 +262,8 @@ std::enable_if_t< // and a call get>() was made, meaning that the caller // wants a vector. // - // BodyText is intended to store just one vector - one that represents - // values in a GNDS node that has "body text." We don't, and shouldn't, + // BlockData is intended to store just one vector - one that represents + // values in a GNDS node that has block data. We don't, and shouldn't, // try to juggle multiple vectors of different types. Therefore, we'll // attempt to convert the existing vector to one of the requested type, // then place the new vector into the variant (replacing the old one.) @@ -274,7 +275,7 @@ std::enable_if_t< log::info( "Re-forming vector of one type into vector of another type;\n" "was this intentional?"); - log::member("BodyText::get>()"); + log::member("BlockData::get>()"); // Initialize a new vector that will soon replace the old one VECTOR newVector; @@ -308,7 +309,7 @@ std::enable_if_t< template std::enable_if_t< ( runtime && detail::isAlternative) || - (!runtime && std::is_same_v>), + (!runtime && std::is_same_v>), VECTOR & > get() { @@ -321,18 +322,19 @@ std::enable_if_t< // 2. get(n) // ----------------------------------------------------------------------------- -// For DATA == void (so that we have a variants>): +// For DATATYPE == void (so that we have a variants>): // These trigger a complete rebuild of the vector, if it isn't already of type // vector for the given T. This is intentional, in order to provide maximum // flexibility. However, be aware of it, for the sake of efficiency! In general, -// when using a BodyText object, we recommend sticking with one underlying type. +// when using a BlockData object, we recommend sticking with one underlying +// type, not dynamically changing from one type to another. -// For DATA != void (so that we have a vector): -// T == DATA is required, so that returning an element of the vector will -// return a reference to T. (A constructibility/convertibility requirement that -// we have in other BodyText-related code thus needs to be more stringent here. -// We can't just be able to make a T from a DATA. Those must in fact be the same -// type, because we return a reference.) +// For DATATYPE != void (so that we have a vector): +// T == DATATYPE is required, so that returning an element of the +// vector will return a reference to T. (A constructibility/ +// convertibility requirement that we have in other BlockData-related code thus +// needs to be more stringent here. We can't just be able to make a T from a +// DATATYPE. They must in fact be the same type, because we return a reference.) // For both of the above cases: // If the string (not the variant or the vector) is active, then a rebuild from @@ -341,7 +343,7 @@ std::enable_if_t< // const template std::enable_if_t< - supported && (runtime || std::is_same_v), + supported && (runtime || std::is_same_v), const T & > get(const std::size_t n) const @@ -349,7 +351,7 @@ get(const std::size_t n) const try { return get>()[n]; } catch (...) { - log::member("BodyText::get({})", n); + log::member("BlockData::get({})", n); throw; } } @@ -357,7 +359,7 @@ get(const std::size_t n) const // non-const template std::enable_if_t< - supported && (runtime || std::is_same_v), + supported && (runtime || std::is_same_v), T & > get(const std::size_t n) @@ -369,21 +371,25 @@ get(const std::size_t n) // ----------------------------------------------------------------------------- // 3. get() -// If DATA == void, returns a variants>. -// If DATA != void, returns a vector<>. +// If DATATYPE == void, returns a variants>. +// If DATATYPE != void, returns a vector<>. // ----------------------------------------------------------------------------- // const std::conditional_t< runtime, const VariantOfVectors &, - const std::vector & + const std::vector & > get() const { if constexpr (runtime) { - detail::MapStringType( + detail::Names2Type( valueType(), - [this](auto &&t) { get>>(); } + [this](auto &&t) + { + // clang seems to need this-> explicitly to *not* emit a warning + this->get>>(); + } ); // We can't return the specific variant alternative that was just put // in place; it depended on a run-time check. So, we return the whole @@ -391,7 +397,7 @@ std::conditional_t< return variant; } else { // Simpler, but we do still need a get (in case the *string* is active). - get>(); + get>(); return vector; } } @@ -400,14 +406,14 @@ std::conditional_t< std::conditional_t< runtime, VariantOfVectors &, - std::vector & + std::vector & > get() { return const_cast< std::conditional_t< runtime, VariantOfVectors &, - std::vector & + std::vector & > >(std::as_const(*this).get()); } @@ -417,11 +423,11 @@ std::conditional_t< // ----------------------------------------------------------------------------- // 4. get(n) // -// If DATA == void, returns a variant (by value, because the returned -// object must be made on-the-fly from our variants>). +// If DATATYPE == void, returns a variant (by value, because the +// returned object must be made on-the-fly from our variants>). // -// If DATA != void, returns a scalar of type [const] DATA (by reference, because -// it's available directly in our vector). +// If DATATYPE != void, returns a scalar of type [const] DATATYPE (by reference, +// because it's available directly in our vector). // ----------------------------------------------------------------------------- // ------------------------ @@ -446,7 +452,7 @@ std::conditional_t< return vector[n]; } } catch (...) { - log::member("BodyText::get({})", n); + log::member("BlockData::get({})", n); throw; } } @@ -466,24 +472,24 @@ std::conditional_t< // non-const // ------------------------ -// If DATA == void: +// If DATATYPE == void: // Not needed, because the const versions return by value. // -// If DATA != void: -// Meaningful, because returns are by reference in this (DATA != void) case. +// If DATATYPE != void: +// Meaningful, because returns are by reference in this (DATATYPE != void) case. // So, we'll enable non-const versions for this case only. -// In case anyone wonders, D (not just DATA) is needed below because SFINAE -// applies when template argument *deduction* is taking place. DATA is already -// fixed, by context - we're in BodyText - and thus it isn't being -// deduced here. Templating these (otherwise non-template) functions with an -// argument that defaults to DATA, then using that argument in the SFINAE, is -// a simple trick that makes the SFINAE work as intended. As for VOID, it's -// necessary in order for the following to be unambiguous with the template -// versions of get(n) that are defined elsewhere in this file. +// In case anyone wonders, D (not just DATATYPE) is needed below because SFINAE +// applies when template argument *deduction* is taking place. DATATYPE is +// already fixed, by context - we're in BlockData - and thus it +// isn't being deduced here. Templating these (otherwise non-template) functions +// with an argument that defaults to DATATYPE, then using that argument in the +// SFINAE, is a simple trick that makes the SFINAE work as intended. As for +// VOID, it's necessary in order for the following to be unambiguous with the +// template versions of get(n) that are defined elsewhere in this file. // get(n) -template +template std::enable_if_t && !detail::isVoid, data_t &> get(const std::size_t n) { @@ -491,13 +497,13 @@ get(const std::size_t n) get(); return vector[n]; } catch (...) { - log::member("BodyText::get({})", n); + log::member("BlockData::get({})", n); throw; } } // operator[](n) -template +template std::enable_if_t, data_t &> operator[](const std::size_t n) { @@ -520,25 +526,25 @@ operator[](const std::size_t n) #define GNDSTK_MAKE_GETTER(name,TYPE) \ \ - template \ + template \ std::enable_if_t< \ detail::isVoid || \ std::is_same_v, const std::vector & \ > name() const { return get>(); } \ \ - template \ + template \ std::enable_if_t< \ detail::isVoid || \ std::is_same_v, std::vector & \ > name() { return get>(); } \ \ - template \ + template \ std::enable_if_t< \ detail::isVoid || \ std::is_same_v, const TYPE & \ > name(const std::size_t n) const { return get(n); } \ \ - template \ + template \ std::enable_if_t< \ detail::isVoid || \ std::is_same_v, TYPE & \ @@ -553,7 +559,7 @@ GNDSTK_MAKE_GETTER(longs, long) GNDSTK_MAKE_GETTER(longlongs, long long) GNDSTK_MAKE_GETTER(uchars, unsigned char) GNDSTK_MAKE_GETTER(ushorts, unsigned short) -GNDSTK_MAKE_GETTER(uints, unsigned int) +GNDSTK_MAKE_GETTER(uints, unsigned) GNDSTK_MAKE_GETTER(ulongs, unsigned long) GNDSTK_MAKE_GETTER(ulonglongs, unsigned long long) GNDSTK_MAKE_GETTER(floats, float) diff --git a/src/GNDStk/BodyText/src/params.hpp b/src/GNDStk/BlockData/src/params.hpp similarity index 76% rename from src/GNDStk/BodyText/src/params.hpp rename to src/GNDStk/BlockData/src/params.hpp index c545310f1..ad15c1534 100644 --- a/src/GNDStk/BodyText/src/params.hpp +++ b/src/GNDStk/BlockData/src/params.hpp @@ -12,7 +12,7 @@ Quoted [slightly edited] from the official JSON specification files for GNDS: values that are not stored. This attribute should only be used when the sum of start and the number of listed values do not add to the total number of data values. This should only happen when there are - trailing zeros not listed in the body text. + trailing zeros not listed in the block data. start Default: 0 @@ -31,37 +31,39 @@ our GNDS Standard Interface code autogeneration tool produces. private: -// toNode() works with a conceptually const object but may update these to be +// toNode() works with a conceptually const object, but may update these to be // consistent with vector data; so, mutable. -mutable struct { +struct { // Any of these might or might not have appeared in a particular node that - // had body text. For uniformity, we have them all here, and with defaults. - std::size_t length = 0; - std::size_t start = 0; - std::string valueType = ""; + // had block data. For uniformity, we have them all here, and with defaults. + mutable std::size_t length = 0; + mutable std::size_t start = 0; + mutable std::string valueType = ""; } vars; // ----------------------------------------------------------------------------- // Getters +// Note: we intentionally return by (non-const!) reference, because the values +// in question are mutable. // ----------------------------------------------------------------------------- public: // length -std::size_t length() const +std::size_t &length() const { return vars.length; } // start -std::size_t start() const +std::size_t &start() const { return vars.start; } // valueType -const std::string &valueType() const +std::string &valueType() const { return vars.valueType; } @@ -74,7 +76,7 @@ const std::string &valueType() const // ----------------------------------------------------------------------------- // length -BodyText &length(const std::optional &opt) +BlockData &length(const std::optional &opt) { if (opt.has_value()) vars.length = opt.value(); @@ -82,7 +84,7 @@ BodyText &length(const std::optional &opt) } // start -BodyText &start(const std::optional &opt) +BlockData &start(const std::optional &opt) { if (opt.has_value()) vars.start = opt.value(); @@ -90,7 +92,7 @@ BodyText &start(const std::optional &opt) } // valueType -BodyText &valueType(const std::optional &opt) +BlockData &valueType(const std::optional &opt) { if (opt.has_value()) vars.valueType = opt.value(); diff --git a/src/GNDStk/BlockData/src/print.hpp b/src/GNDStk/BlockData/src/print.hpp new file mode 100644 index 000000000..9a7eae7d6 --- /dev/null +++ b/src/GNDStk/BlockData/src/print.hpp @@ -0,0 +1,82 @@ + +// ----------------------------------------------------------------------------- +// print +// Used by Component's prettyprinting. +// ----------------------------------------------------------------------------- + +std::ostream &print(std::ostream &os, const int level) const +{ + // If empty, don't even print a newline + if ((active() == Active::string && rawstring == "") || + (active() == Active::vector && size() == 0)) + return os; + + // Coloring? + const bool coloring = GNDStk::color && GNDStk::colors::value != ""; + + // ------------------------ + // If string is active + // ------------------------ + + if (active() == Active::string) { + // Print the string exactly as-is, without our column formatting + // or any indentation; then also print a newline + return coloring + ? os << colors::value << rawstring << colors::reset << std::endl + : os << rawstring << std::endl; + } + + // ------------------------ + // If vector is active + // ------------------------ + + // Indentation (string, with some number of spaces) + const std::string indent(GNDStk::indent*level,' '); + + const auto printLambda = + [&os,&indent,coloring](auto &&alt) + { + using T = std::decay_t; + const std::size_t size = alt.size(); + const std::size_t end = (GNDStk::truncate < 0) + ? size + : std::min(size,std::size_t(GNDStk::truncate)); + + // Print, using our column formatting + for (std::size_t i = 0; i < end; ++i) { + const T &element = alt[i]; + + // value's whitespace prefix + i == 0 + ? os << indent // at the very beginning, or... + : GNDStk::columns <= 0 || + i % std::size_t(std::abs(GNDStk::columns)) != 0 + ? os << ' ' // still on the current line, or... + : os << '\n' << indent; // starting the next line + + // value + using namespace detail; + if (coloring) os << colors::value; + if constexpr (std::is_floating_point_v) + os << Precision{}.write(element); + else + os << element; + if (coloring) os << colors::reset; + }; + + // If applicable, print a message saying the data were truncated + if (end < size) { + if (end > 0) + os << '\n'; + os << indent << detail::colorize_comment( + "// truncated; total #values == " + std::to_string(size)); + } + }; + + if constexpr (runtime) + std::visit(printLambda,variant); + else + printLambda(vector); + + return os << std::endl; +} diff --git a/src/GNDStk/BodyText/src/string.hpp b/src/GNDStk/BlockData/src/string.hpp similarity index 94% rename from src/GNDStk/BodyText/src/string.hpp rename to src/GNDStk/BlockData/src/string.hpp index 6ffef6fca..7b40d34e3 100644 --- a/src/GNDStk/BodyText/src/string.hpp +++ b/src/GNDStk/BlockData/src/string.hpp @@ -16,7 +16,7 @@ const std::string &string() const // string(new string) // Builder pattern: return *this, so callers can use this function smoothly // in conjunction with the setters for length, start, and valueType. -BodyText &string(const std::string &str) +BlockData &string(const std::string &str) { clear(); // <== the vector, because it's no longer considered meaningful rawstring = str; diff --git a/src/GNDStk/BlockData/src/sync.hpp b/src/GNDStk/BlockData/src/sync.hpp new file mode 100644 index 000000000..f73166935 --- /dev/null +++ b/src/GNDStk/BlockData/src/sync.hpp @@ -0,0 +1,22 @@ + +// pullFromDerived(derived) +// Make this BlockData's length, start, and valueType be consistent with any or +// all such parameters that exist in the given object. Remember that this class, +// BlockData, is a base of Component, which is a base of some other class. +template +void pullFromDerived(const DERIVED &derived) +{ + length (derived.length ()); + start (derived.start ()); + valueType(derived.valueType()); +} + +// pushToDerived(derived) +// The reverse of the above. +template +void pushToDerived(DERIVED &derived) const +{ + derived.length () = length (); + derived.start () = start (); + derived.valueType() = valueType(); +} diff --git a/src/GNDStk/BodyText/src/toNode.hpp b/src/GNDStk/BlockData/src/toNode.hpp similarity index 76% rename from src/GNDStk/BodyText/src/toNode.hpp rename to src/GNDStk/BlockData/src/toNode.hpp index 3f9dde5dc..7dd5d233a 100644 --- a/src/GNDStk/BodyText/src/toNode.hpp +++ b/src/GNDStk/BlockData/src/toNode.hpp @@ -1,17 +1,16 @@ // ----------------------------------------------------------------------------- -// BodyText::toNode +// BlockData::toNode // This is called by Component's conversion-to-Node (not toNode()) function. // It's "toNode()" here, not a conversion, because we're simply writing text // that Component's full conversion-to-Node will place into the Node itself. // ----------------------------------------------------------------------------- -// Use either (1) the original raw string, or (2) the variant of vectors or the -// vector (depending on DATA ==/!= void), based on whether or not the string -// is active. length, start, and valueType might be computed too, in which case -// they're also changed in the derived class in order to keep things consistent. -template -void toNode(std::string &text, DERIVED &derived) const +// Use either (1) the original raw string, or (2) either the variant of vectors +// or the vector (depending on DATATYPE ==/!= void), based on whether or not the +// raw string is active. If a vector (not the raw string) is active, then we'll +// also compute length, start, and valueType. +void toNode(std::string &text) const { // Use the raw string? if (active() == Active::string) { @@ -22,11 +21,11 @@ void toNode(std::string &text, DERIVED &derived) const // Use the vector... const bool isStringVector = ( runtime && std::holds_alternative>(variant)) || - (!runtime && std::is_same_v); + (!runtime && std::is_same_v); if constexpr ( runtime || - (!runtime && std::is_same_v) + (!runtime && std::is_same_v) ) { // the run-time if's get() calls below won't // necessarily make sense without the above if-constexpr @@ -36,7 +35,7 @@ void toNode(std::string &text, DERIVED &derived) const (get(0) == "" || get(size()-1) == "") ) { log::warning( - "BodyText.toNode() called with BodyText " + "BlockData.toNode() called with BlockData " "trim flag == false, but active\n" "data are in a vector. Printing " "leading/trailing empty strings\n" @@ -51,16 +50,15 @@ void toNode(std::string &text, DERIVED &derived) const ? runtime ? std::visit([](auto &&vec) { return detail::getBounds(vec); }, variant) : detail::getBounds(vector) - : std::make_pair(size_t(0),size()); + : std::make_pair(std::size_t(0),size()); // Compute length, start, and valueType vars.length = size(); // independent of trim vars.start = bounds.first; // dependent on trim, per the bounds computation if constexpr (runtime) - vars.valueType = detail::visitMapTypeString(variant); + vars.valueType = detail::visitType2Names(variant); else - vars.valueType = detail::MapTypeString::value[0]; - pushToDerived(derived); + vars.valueType = detail::Type2Names::value[0]; // Values std::ostringstream oss; diff --git a/src/GNDStk/BodyText/src/types.hpp b/src/GNDStk/BlockData/src/types.hpp similarity index 96% rename from src/GNDStk/BodyText/src/types.hpp rename to src/GNDStk/BlockData/src/types.hpp index 3eca8c0e1..46f7c3502 100644 --- a/src/GNDStk/BodyText/src/types.hpp +++ b/src/GNDStk/BlockData/src/types.hpp @@ -21,7 +21,7 @@ using VariantOfVectors = std::variant< // unsigned integrals std::vector, std::vector, - std::vector, + std::vector, std::vector, std::vector, diff --git a/src/GNDStk/BodyText/test/BodyText.test.cpp b/src/GNDStk/BlockData/test/BlockData.test.cpp similarity index 76% rename from src/GNDStk/BodyText/test/BodyText.test.cpp rename to src/GNDStk/BlockData/test/BlockData.test.cpp index 09cb28cc8..ab5c35d60 100644 --- a/src/GNDStk/BodyText/test/BodyText.test.cpp +++ b/src/GNDStk/BlockData/test/BlockData.test.cpp @@ -4,22 +4,22 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- -// Scenario for DATA == void +// Scenario for DATATYPE == void // ----------------------------------------------------------------------------- -SCENARIO("Testing GNDStk BodyText with DATA == void") { - // Most BodyText functionality is tested in the individual test files. +SCENARIO("Testing GNDStk BlockData with DATATYPE == void") { + // Most BlockData functionality is tested in the individual test files. // There are just a few things we'll do here. - // Ensure that we can make const and non-const and BodyText - // objects. Note that BodyText has only a default constructor. + // Ensure that we can make const and non-const and BlockData + // objects. Note that BlockData has only a default constructor. - GIVEN("A const BodyText cbtextt") { - const BodyText cbtextt; + GIVEN("A const BlockData cbtextt") { + const BlockData cbtextt; THEN("It constructed correctly, and its data are as expected") { CHECK(cbtextt.length () == 0); CHECK(cbtextt.size () == 0); @@ -28,15 +28,15 @@ SCENARIO("Testing GNDStk BodyText with DATA == void") { } } - GIVEN("A const BodyText cbtextf") { - const BodyText cbtextf; + GIVEN("A const BlockData cbtextf") { + const BlockData cbtextf; THEN("It constructed correctly") { // no data for } } - GIVEN("A non-const BodyText nbtextt") { - BodyText nbtextt; + GIVEN("A non-const BlockData nbtextt") { + BlockData nbtextt; THEN("It constructed correctly, and its data are as expected") { CHECK(nbtextt.length () == 0); CHECK(nbtextt.size () == 0); @@ -45,21 +45,21 @@ SCENARIO("Testing GNDStk BodyText with DATA == void") { } } - GIVEN("A non-const BodyText nbtextf") { - BodyText nbtextf; + GIVEN("A non-const BlockData nbtextf") { + BlockData nbtextf; THEN("It constructed correctly") { // no data for } } // clear() and size() are defined (at the time of this writing) in the - // BodyText.hpp file itself, so we'll test them here. size() actually + // BlockData.hpp file itself, so we'll test them here. size() actually // was used in various tests, and thus was indirectly tested elsewhere. - GIVEN("A BodyText") { + GIVEN("A BlockData") { // clear WHEN("We test clear()") { - BodyText b; + BlockData b; // try int THEN("size() works correctly for vector") { @@ -88,7 +88,7 @@ SCENARIO("Testing GNDStk BodyText with DATA == void") { // size WHEN("We test size()") { - BodyText b; + BlockData b; // try int THEN("size() works correctly for vector") { @@ -125,13 +125,13 @@ SCENARIO("Testing GNDStk BodyText with DATA == void") { // ----------------------------------------------------------------------------- -// Scenario for DATA != void +// Scenario for DATATYPE != void // ----------------------------------------------------------------------------- -SCENARIO("Testing GNDStk BodyText with DATA != void") { +SCENARIO("Testing GNDStk BlockData with DATATYPE != void") { - GIVEN("A const BodyText cbtextt") { - const BodyText cbtextt; + GIVEN("A const BlockData cbtextt") { + const BlockData cbtextt; THEN("It constructed correctly, and its data are as expected") { CHECK(cbtextt.length () == 0); CHECK(cbtextt.size () == 0); @@ -140,15 +140,15 @@ SCENARIO("Testing GNDStk BodyText with DATA != void") { } } - GIVEN("A const BodyText cbtextf") { - const BodyText cbtextf; + GIVEN("A const BlockData cbtextf") { + const BlockData cbtextf; THEN("It constructed correctly") { // no data for } } - GIVEN("A non-const BodyText nbtextt") { - BodyText nbtextt; + GIVEN("A non-const BlockData nbtextt") { + BlockData nbtextt; THEN("It constructed correctly, and its data are as expected") { CHECK(nbtextt.length () == 0); CHECK(nbtextt.size () == 0); @@ -157,17 +157,17 @@ SCENARIO("Testing GNDStk BodyText with DATA != void") { } } - GIVEN("A non-const BodyText nbtextf") { - BodyText nbtextf; + GIVEN("A non-const BlockData nbtextf") { + BlockData nbtextf; THEN("It constructed correctly") { // no data for } } - GIVEN("A BodyText") { + GIVEN("A BlockData") { // clear WHEN("We test clear()") { - BodyText b; + BlockData b; THEN("size() works correctly") { b = std::vector{1,2,3,4,5}; CHECK(b.size() == 5); @@ -178,7 +178,7 @@ SCENARIO("Testing GNDStk BodyText with DATA != void") { // size WHEN("We test size()") { - BodyText b; + BlockData b; THEN("size() works correctly") { b = std::vector{"one","two","three","four","five"}; CHECK(b.size() == 5); diff --git a/src/GNDStk/BodyText/test/CMakeLists.txt b/src/GNDStk/BlockData/test/CMakeLists.txt similarity index 66% rename from src/GNDStk/BodyText/test/CMakeLists.txt rename to src/GNDStk/BlockData/test/CMakeLists.txt index 37cdf9076..a240f071b 100644 --- a/src/GNDStk/BodyText/test/CMakeLists.txt +++ b/src/GNDStk/BlockData/test/CMakeLists.txt @@ -1,7 +1,8 @@ -add_executable( GNDStk.BodyText.test - BodyText.test.cpp +add_executable( GNDStk.BlockData.test + BlockData.test.cpp assign.test.cpp + convert.test.cpp detail.test.cpp fromNode.test.cpp get.test.cpp @@ -10,8 +11,8 @@ add_executable( GNDStk.BodyText.test sync.test.cpp toNode.test.cpp types.test.cpp - write.test.cpp ) -target_compile_options( GNDStk.BodyText.test PRIVATE ${${PREFIX}_common_flags} + print.test.cpp ) +target_compile_options( GNDStk.BlockData.test PRIVATE ${${PREFIX}_common_flags} $<$:${${PREFIX}_strict_flags}>$<$: ${${PREFIX}_DEBUG_flags} $<$:${${PREFIX}_coverage_flags}>> @@ -21,5 +22,5 @@ $<$:${${PREFIX}_link_time_optimization_flags}> $<$:${${PREFIX}_nonportable_optimization_flags}>> ${CXX_appended_flags} ${GNDStk_appended_flags} ) -target_link_libraries( GNDStk.BodyText.test PUBLIC GNDStk ) -add_test( NAME GNDStk.BodyText COMMAND GNDStk.BodyText.test ) +target_link_libraries( GNDStk.BlockData.test PUBLIC GNDStk ) +add_test( NAME GNDStk.BlockData COMMAND GNDStk.BlockData.test ) diff --git a/src/GNDStk/BodyText/test/assign.test.cpp b/src/GNDStk/BlockData/test/assign.test.cpp similarity index 88% rename from src/GNDStk/BodyText/test/assign.test.cpp rename to src/GNDStk/BlockData/test/assign.test.cpp index 7326ae81d..8da3e023f 100644 --- a/src/GNDStk/BodyText/test/assign.test.cpp +++ b/src/GNDStk/BlockData/test/assign.test.cpp @@ -2,20 +2,20 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- -// Scenario for DATA == void +// Scenario for DATATYPE == void // ----------------------------------------------------------------------------- -SCENARIO("BodyText assignment operators") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData assignment operators") { + GIVEN("A default-constructed BlockData object") { // Default value of raw string is as expected WHEN("We examine the raw string") { THEN("It is as expected") { - BodyText b; + BlockData b; CHECK(b.string() == ""); } } @@ -23,7 +23,7 @@ SCENARIO("BodyText assignment operators") { // Assignment from string works WHEN("We assign from a string") { THEN("The raw string has the correct value, and vector size() == 0") { - BodyText b; + BlockData b; // to ensure it clears the vector below... b = std::vector(10); @@ -40,7 +40,7 @@ SCENARIO("BodyText assignment operators") { // Assignment from vector works WHEN("We assign from a vector") { THEN("The variant has the correct value, and raw string == \"\"") { - BodyText b; + BlockData b; // to ensure it clears the raw string etc. below... b = "foo bar"; @@ -70,7 +70,7 @@ SCENARIO("BodyText assignment operators") { // Assign from vector; should set valueType WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); @@ -83,7 +83,7 @@ SCENARIO("BodyText assignment operators") { // Assign from vector; should set valueType WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); @@ -96,7 +96,7 @@ SCENARIO("BodyText assignment operators") { // For now, non-{int,double} sets valueType == "" WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); @@ -111,16 +111,16 @@ SCENARIO("BodyText assignment operators") { // ----------------------------------------------------------------------------- -// Scenario for DATA != void +// Scenario for DATATYPE != void // ----------------------------------------------------------------------------- -SCENARIO("BodyText assignment operators") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData assignment operators") { + GIVEN("A default-constructed BlockData object") { // Default value of raw string is as expected WHEN("We examine the raw string") { THEN("It is as expected") { - BodyText b; + BlockData b; CHECK(b.string() == ""); } } @@ -128,7 +128,7 @@ SCENARIO("BodyText assignment operators") { // Assignment from string works WHEN("We assign from a string") { THEN("The raw string has the correct value, and vector size() == 0") { - BodyText b; + BlockData b; // to ensure it clears the vector below... b = std::vector(10); @@ -145,7 +145,7 @@ SCENARIO("BodyText assignment operators") { // Assignment from vector works WHEN("We assign from a vector") { THEN("The vector has the correct value, and raw string == \"\"") { - BodyText b; + BlockData b; // to ensure it clears the raw string etc. below... b = "foo bar"; @@ -175,7 +175,7 @@ SCENARIO("BodyText assignment operators") { // Assign from vector; should set valueType WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); @@ -188,7 +188,7 @@ SCENARIO("BodyText assignment operators") { // Assign from vector; should set valueType WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); @@ -201,7 +201,7 @@ SCENARIO("BodyText assignment operators") { // For now, non-{int,double} sets valueType == "" WHEN("We assign from a vector") { THEN("valueType is set correctly") { - BodyText b; + BlockData b; b.string("foo").valueType("unknown"); CHECK(b.valueType() == "unknown"); diff --git a/src/GNDStk/BlockData/test/convert.test.cpp b/src/GNDStk/BlockData/test/convert.test.cpp new file mode 100644 index 000000000..b41c3848c --- /dev/null +++ b/src/GNDStk/BlockData/test/convert.test.cpp @@ -0,0 +1,53 @@ + +#include "catch.hpp" +#include "GNDStk.hpp" + +using namespace njoy::GNDStk; + +SCENARIO("BlockData conversion to vector") { + GIVEN("A BlockData object") { + + { + using T = int; + BlockData b; + b.start(2).length(6).string("-12 34 -56"); + std::vector myVector = b; + CHECK(myVector.size() == 6); + CHECK(myVector[0] == 0); + CHECK(myVector[1] == 0); + CHECK(myVector[2] == -12); + CHECK(myVector[3] == 34); + CHECK(myVector[4] == -56); + CHECK(myVector[5] == 0); + } + + { + using T = double; + BlockData b; + b.start(2).length(6).string("1.2 3.4 5.6"); + std::vector myVector = b; + CHECK(myVector.size() == 6); + CHECK(myVector[0] == 0); + CHECK(myVector[1] == 0); + CHECK(myVector[2] == 1.2); + CHECK(myVector[3] == 3.4); + CHECK(myVector[4] == 5.6); + CHECK(myVector[5] == 0); + } + + { + using T = std::string; + BlockData b; + b.start(2).length(6).string("ab cd ef"); + std::vector myVector = b; + CHECK(myVector.size() == 6); + CHECK(myVector[0] == ""); + CHECK(myVector[1] == ""); + CHECK(myVector[2] == "ab"); + CHECK(myVector[3] == "cd"); + CHECK(myVector[4] == "ef"); + CHECK(myVector[5] == ""); + } + + } // GIVEN +} // SCENARIO diff --git a/src/GNDStk/BodyText/test/detail.test.cpp b/src/GNDStk/BlockData/test/detail.test.cpp similarity index 70% rename from src/GNDStk/BodyText/test/detail.test.cpp rename to src/GNDStk/BlockData/test/detail.test.cpp index 5083a4f2e..593de9122 100644 --- a/src/GNDStk/BodyText/test/detail.test.cpp +++ b/src/GNDStk/BlockData/test/detail.test.cpp @@ -2,14 +2,14 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; inline std::string bar = "bar"; // ----------------------------------------------------------------------------- // Scenario // ----------------------------------------------------------------------------- -SCENARIO("Testing various BodyText-related detail:: constructs") { +SCENARIO("Testing various BlockData-related detail:: constructs") { // ------------------------ // scalarize @@ -73,122 +73,6 @@ SCENARIO("Testing various BodyText-related detail:: constructs") { } // GIVEN - // ------------------------ - // hasLength, hasStart, - // hasValueType - // ------------------------ - - GIVEN("Testing detail::hasLength, hasStart, and hasValueType") { - WHEN("A struct's content has length, start, and valueType") { - struct { - struct { - int length; - const double start = 0; - const std::string &valueType = bar; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == true)); - CHECK((detail::hasStart == true)); - CHECK((detail::hasValueType == true)); - } - } - - WHEN("A struct's content has start and valueType") { - struct { - struct { - const double start = 0; - const std::string &valueType = bar; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == false)); - CHECK((detail::hasStart == true)); - CHECK((detail::hasValueType == true)); - } - } - - WHEN("A struct's content has length and valueType") { - struct { - struct { - int length; - const std::string &valueType = bar; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == true)); - CHECK((detail::hasStart == false)); - CHECK((detail::hasValueType == true)); - } - } - - WHEN("A struct's content has length and start") { - struct { - struct { - int length; - const double start = 0; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == true)); - CHECK((detail::hasStart == true)); - CHECK((detail::hasValueType == false)); - } - } - - WHEN("A struct's content has length") { - struct { - struct { - int length; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == true)); - CHECK((detail::hasStart == false)); - CHECK((detail::hasValueType == false)); - } - } - - WHEN("A struct's content has start") { - struct { - struct { - const double start = 0; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == false)); - CHECK((detail::hasStart == true)); - CHECK((detail::hasValueType == false)); - } - } - - WHEN("A struct's content has valueType") { - struct { - struct { - const std::string &valueType = bar; - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == false)); - CHECK((detail::hasStart == false)); - CHECK((detail::hasValueType == true)); - } - } - - WHEN("A struct's content has none of length, start, or valueType") { - struct { - struct { - } content; - } foo; - THEN("Our SFINAE helpers detect this") { - CHECK((detail::hasLength == false)); - CHECK((detail::hasStart == false)); - CHECK((detail::hasValueType == false)); - } - } - } // GIVEN - - // ------------------------ // element2element // ------------------------ diff --git a/src/GNDStk/BodyText/test/fromNode.test.cpp b/src/GNDStk/BlockData/test/fromNode.test.cpp similarity index 72% rename from src/GNDStk/BodyText/test/fromNode.test.cpp rename to src/GNDStk/BlockData/test/fromNode.test.cpp index 25e6c5059..dda1bc292 100644 --- a/src/GNDStk/BodyText/test/fromNode.test.cpp +++ b/src/GNDStk/BlockData/test/fromNode.test.cpp @@ -2,19 +2,19 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- -// Scenario for DATA == void +// Scenario for DATATYPE == void // ----------------------------------------------------------------------------- -SCENARIO("BodyText fromNode()") { +SCENARIO("BlockData fromNode()") { - GIVEN("A Node with no \"body text\"") { - WHEN("BodyText.fromNode(the node) is called") { - THEN("The BodyText's raw string is \"\", as expected") { - BodyText b; + GIVEN("A Node with no \"block data\"") { + WHEN("BlockData.fromNode(the node) is called") { + THEN("The BlockData's raw string is \"\", as expected") { + BlockData b; b.string("This string should be replaced"); CHECK(b.string() != ""); @@ -26,10 +26,10 @@ SCENARIO("BodyText fromNode()") { } } - GIVEN("A Node with some \"body text\"") { - WHEN("BodyText.fromNode(the node) is called") { - THEN("The BodyText's raw string equals the text from the Node") { - BodyText b; + GIVEN("A Node with some \"block data\"") { + WHEN("BlockData.fromNode(the node) is called") { + THEN("The BlockData's raw string equals the text from the Node") { + BlockData b; b.string("This string should be replaced"); CHECK(b.string() != ""); @@ -61,15 +61,15 @@ SCENARIO("BodyText fromNode()") { // ----------------------------------------------------------------------------- -// Scenario for DATA != void +// Scenario for DATATYPE != void // ----------------------------------------------------------------------------- -SCENARIO("BodyText fromNode()") { +SCENARIO("BlockData fromNode()") { - GIVEN("A Node with no \"body text\"") { - WHEN("BodyText.fromNode(the node) is called") { - THEN("The BodyText's raw string is \"\", as expected") { - BodyText b; + GIVEN("A Node with no \"block data\"") { + WHEN("BlockData.fromNode(the node) is called") { + THEN("The BlockData's raw string is \"\", as expected") { + BlockData b; b.string("This string should be replaced"); CHECK(b.string() != ""); @@ -81,10 +81,10 @@ SCENARIO("BodyText fromNode()") { } } - GIVEN("A Node with some \"body text\"") { - WHEN("BodyText.fromNode(the node) is called") { - THEN("The BodyText's raw string equals the text from the Node") { - BodyText b; + GIVEN("A Node with some \"block data\"") { + WHEN("BlockData.fromNode(the node) is called") { + THEN("The BlockData's raw string equals the text from the Node") { + BlockData b; b.string("This string should be replaced"); CHECK(b.string() != ""); diff --git a/src/GNDStk/BodyText/test/get.test.cpp b/src/GNDStk/BlockData/test/get.test.cpp similarity index 68% rename from src/GNDStk/BodyText/test/get.test.cpp rename to src/GNDStk/BlockData/test/get.test.cpp index 4179ce9af..375a4d0f3 100644 --- a/src/GNDStk/BodyText/test/get.test.cpp +++ b/src/GNDStk/BlockData/test/get.test.cpp @@ -2,7 +2,7 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; @@ -33,33 +33,33 @@ void scenario_get_vector() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); + { BlockData b; b.start(0).length(0).string(""); CHECK((b.template get() == ivec{})); } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(4).string(""); CHECK((b.template get() == ivec{{0,0,0,0}})); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK((b.template get() == ivec{{0,0,0,0,0}})); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK((b.template get() == ivec{{0,0,0,0,0,0}})); } // 1 element in string - { BodyText b; b.start(0).length(0).string("-12"); + { BlockData b; b.start(0).length(0).string("-12"); CHECK((b.template get() == ivec(1,-12))); } - { BodyText b; b.start(0).length(4).string("-12"); + { BlockData b; b.start(0).length(4).string("-12"); CHECK((b.template get() == ivec{{-12,0,0,0}})); } - { BodyText b; b.start(1).length(5).string("-12"); + { BlockData b; b.start(1).length(5).string("-12"); CHECK((b.template get() == ivec{{0,-12,0,0,0}})); } - { BodyText b; b.start(2).length(6).string("-12"); + { BlockData b; b.start(2).length(6).string("-12"); CHECK((b.template get() == ivec{{0,0,-12,0,0,0}})); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("-12 34 -56"); + { BlockData b; b.start(0).length(0).string("-12 34 -56"); CHECK((b.template get() == ivec{{-12,34,-56}})); } - { BodyText b; b.start(0).length(4).string("-12 34 -56"); + { BlockData b; b.start(0).length(4).string("-12 34 -56"); CHECK((b.template get() == ivec{{-12,34,-56,0}})); } - { BodyText b; b.start(1).length(5).string("-12 34 -56"); + { BlockData b; b.start(1).length(5).string("-12 34 -56"); CHECK((b.template get() == ivec{{0,-12,34,-56,0}})); } - { BodyText b; b.start(2).length(6).string("-12 34 -56"); + { BlockData b; b.start(2).length(6).string("-12 34 -56"); CHECK((b.template get() == ivec{{0,0,-12,34,-56,0}})); } // ------------------------ @@ -67,33 +67,33 @@ void scenario_get_vector() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); + { BlockData b; b.start(0).length(0).string(""); CHECK((b.template get() == fvec{})); } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(4).string(""); CHECK((b.template get() == fvec{{0,0,0,0}})); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK((b.template get() == fvec{{0,0,0,0,0}})); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK((b.template get() == fvec{{0,0,0,0,0,0}})); } // 1 element in string - { BodyText b; b.start(0).length(0).string("1.2"); + { BlockData b; b.start(0).length(0).string("1.2"); CHECK((b.template get() == fvec(1,1.2))); } - { BodyText b; b.start(0).length(4).string("1.2"); + { BlockData b; b.start(0).length(4).string("1.2"); CHECK((b.template get() == fvec{{1.2,0,0,0}})); } - { BodyText b; b.start(1).length(5).string("1.2"); + { BlockData b; b.start(1).length(5).string("1.2"); CHECK((b.template get() == fvec{{0,1.2,0,0,0}})); } - { BodyText b; b.start(2).length(6).string("1.2"); + { BlockData b; b.start(2).length(6).string("1.2"); CHECK((b.template get() == fvec{{0,0,1.2,0,0,0}})); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("1.2 3.4 5.6"); + { BlockData b; b.start(0).length(0).string("1.2 3.4 5.6"); CHECK((b.template get() == fvec{{1.2,3.4,5.6}})); } - { BodyText b; b.start(0).length(4).string("1.2 3.4 5.6"); + { BlockData b; b.start(0).length(4).string("1.2 3.4 5.6"); CHECK((b.template get() == fvec{{1.2,3.4,5.6,0}})); } - { BodyText b; b.start(1).length(5).string("1.2 3.4 5.6"); + { BlockData b; b.start(1).length(5).string("1.2 3.4 5.6"); CHECK((b.template get() == fvec{{0,1.2,3.4,5.6,0}})); } - { BodyText b; b.start(2).length(6).string("1.2 3.4 5.6"); + { BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); CHECK((b.template get() == fvec{{0,0,1.2,3.4,5.6,0}})); } // ------------------------ @@ -101,33 +101,33 @@ void scenario_get_vector() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); + { BlockData b; b.start(0).length(0).string(""); CHECK((b.template get() == svec{})); } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(4).string(""); CHECK((b.template get() == svec{{"","","",""}})); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK((b.template get() == svec{{"","","","",""}})); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK((b.template get() == svec{{"","","","","",""}})); } // 1 element in string - { BodyText b; b.start(0).length(0).string("ab"); + { BlockData b; b.start(0).length(0).string("ab"); CHECK((b.template get() == svec(1,"ab"))); } - { BodyText b; b.start(0).length(4).string("ab"); + { BlockData b; b.start(0).length(4).string("ab"); CHECK((b.template get() == svec{{"ab","","",""}})); } - { BodyText b; b.start(1).length(5).string("ab"); + { BlockData b; b.start(1).length(5).string("ab"); CHECK((b.template get() == svec{{"","ab","","",""}})); } - { BodyText b; b.start(2).length(6).string("ab"); + { BlockData b; b.start(2).length(6).string("ab"); CHECK((b.template get() == svec{{"","","ab","","",""}})); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("ab cd ef"); + { BlockData b; b.start(0).length(0).string("ab cd ef"); CHECK((b.template get() == svec{{"ab","cd","ef"}})); } - { BodyText b; b.start(0).length(4).string("ab cd ef"); + { BlockData b; b.start(0).length(4).string("ab cd ef"); CHECK((b.template get() == svec{{"ab","cd","ef",""}})); } - { BodyText b; b.start(1).length(5).string("ab cd ef"); + { BlockData b; b.start(1).length(5).string("ab cd ef"); CHECK((b.template get() == svec{{"","ab","cd","ef",""}})); } - { BodyText b; b.start(2).length(6).string("ab cd ef"); + { BlockData b; b.start(2).length(6).string("ab cd ef"); CHECK((b.template get() == svec{{"","","ab","cd","ef",""}})); } // ------------------------ @@ -135,46 +135,46 @@ void scenario_get_vector() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); + { BlockData b; b.start(0).length(0).string(""); CHECK((b.template get() == uvec{})); } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(4).string(""); CHECK((b.template get() == uvec{{0,0,0,0}})); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK((b.template get() == uvec{{0,0,0,0,0}})); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK((b.template get() == uvec{{0,0,0,0,0,0}})); } // 1 element in string - { BodyText b; b.start(0).length(0).string("12"); + { BlockData b; b.start(0).length(0).string("12"); CHECK((b.template get() == uvec(1,12))); } - { BodyText b; b.start(0).length(4).string("12"); + { BlockData b; b.start(0).length(4).string("12"); CHECK((b.template get() == uvec{{12,0,0,0}})); } - { BodyText b; b.start(1).length(5).string("12"); + { BlockData b; b.start(1).length(5).string("12"); CHECK((b.template get() == uvec{{0,12,0,0,0}})); } - { BodyText b; b.start(2).length(6).string("12"); + { BlockData b; b.start(2).length(6).string("12"); CHECK((b.template get() == uvec{{0,0,12,0,0,0}})); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("12 34 56"); + { BlockData b; b.start(0).length(0).string("12 34 56"); CHECK((b.template get() == uvec{{12,34,56}})); } - { BodyText b; b.start(0).length(4).string("12 34 56"); + { BlockData b; b.start(0).length(4).string("12 34 56"); CHECK((b.template get() == uvec{{12,34,56,0}})); } - { BodyText b; b.start(1).length(5).string("12 34 56"); + { BlockData b; b.start(1).length(5).string("12 34 56"); CHECK((b.template get() == uvec{{0,12,34,56,0}})); } - { BodyText b; b.start(2).length(6).string("12 34 56"); + { BlockData b; b.start(2).length(6).string("12 34 56"); CHECK((b.template get() == uvec{{0,0,12,34,56,0}})); } } -// For BodyText -SCENARIO("BodyText get()") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get()") { + GIVEN("A BlockData object") { scenario_get_vector(); } } -// For BodyText -SCENARIO("BodyText get()") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get()") { + GIVEN("A BlockData object") { scenario_get_vector(); } } @@ -194,32 +194,32 @@ void scenario_get_template_n() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); /* no elements */ } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(0).string(""); } + { BlockData b; b.start(0).length(4).string(""); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK(b.template get(3) == 0); } // 1 element in string - { BodyText b; b.start(0).length(0).string("-12"); + { BlockData b; b.start(0).length(0).string("-12"); CHECK(b.template get(0) == -12); } - { BodyText b; b.start(0).length(4).string("-12"); + { BlockData b; b.start(0).length(4).string("-12"); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string("-12"); + { BlockData b; b.start(1).length(5).string("-12"); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string("-12"); + { BlockData b; b.start(2).length(6).string("-12"); CHECK(b.template get(3) == 0); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("-12 34 -56"); + { BlockData b; b.start(0).length(0).string("-12 34 -56"); CHECK(b.template get(0) == -12); } - { BodyText b; b.start(0).length(4).string("-12 34 -56"); + { BlockData b; b.start(0).length(4).string("-12 34 -56"); CHECK(b.template get(1) == 34); } - { BodyText b; b.start(1).length(5).string("-12 34 -56"); + { BlockData b; b.start(1).length(5).string("-12 34 -56"); CHECK(b.template get(2) == 34); } - { BodyText b; b.start(2).length(6).string("-12 34 -56"); + { BlockData b; b.start(2).length(6).string("-12 34 -56"); CHECK(b.template get(3) == 34); } // ------------------------ @@ -227,32 +227,32 @@ void scenario_get_template_n() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); /* no elements */ } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(0).string(""); } + { BlockData b; b.start(0).length(4).string(""); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK(b.template get(3) == 0); } // 1 element in string - { BodyText b; b.start(0).length(0).string("1.2"); + { BlockData b; b.start(0).length(0).string("1.2"); CHECK(b.template get(0) == 1.2); } - { BodyText b; b.start(0).length(4).string("1.2"); + { BlockData b; b.start(0).length(4).string("1.2"); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string("1.2"); + { BlockData b; b.start(1).length(5).string("1.2"); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string("1.2"); + { BlockData b; b.start(2).length(6).string("1.2"); CHECK(b.template get(3) == 0); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("1.2 3.4 5.6"); + { BlockData b; b.start(0).length(0).string("1.2 3.4 5.6"); CHECK(b.template get(0) == 1.2); } - { BodyText b; b.start(0).length(4).string("1.2 3.4 5.6"); + { BlockData b; b.start(0).length(4).string("1.2 3.4 5.6"); CHECK(b.template get(1) == 3.4); } - { BodyText b; b.start(1).length(5).string("1.2 3.4 5.6"); + { BlockData b; b.start(1).length(5).string("1.2 3.4 5.6"); CHECK(b.template get(2) == 3.4); } - { BodyText b; b.start(2).length(6).string("1.2 3.4 5.6"); + { BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); CHECK(b.template get(3) == 3.4); } // ------------------------ @@ -260,32 +260,32 @@ void scenario_get_template_n() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); /* no elements */ } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(0).string(""); } + { BlockData b; b.start(0).length(4).string(""); CHECK(b.template get(1) == ""); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK(b.template get(2) == ""); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK(b.template get(3) == ""); } // 1 element in string - { BodyText b; b.start(0).length(0).string("ab"); + { BlockData b; b.start(0).length(0).string("ab"); CHECK(b.template get(0) == "ab"); } - { BodyText b; b.start(0).length(4).string("ab"); + { BlockData b; b.start(0).length(4).string("ab"); CHECK(b.template get(1) == ""); } - { BodyText b; b.start(1).length(5).string("ab"); + { BlockData b; b.start(1).length(5).string("ab"); CHECK(b.template get(2) == ""); } - { BodyText b; b.start(2).length(6).string("ab"); + { BlockData b; b.start(2).length(6).string("ab"); CHECK(b.template get(3) == ""); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("ab cd ef"); + { BlockData b; b.start(0).length(0).string("ab cd ef"); CHECK(b.template get(0) == "ab"); } - { BodyText b; b.start(0).length(4).string("ab cd ef"); + { BlockData b; b.start(0).length(4).string("ab cd ef"); CHECK(b.template get(1) == "cd"); } - { BodyText b; b.start(1).length(5).string("ab cd ef"); + { BlockData b; b.start(1).length(5).string("ab cd ef"); CHECK(b.template get(2) == "cd"); } - { BodyText b; b.start(2).length(6).string("ab cd ef"); + { BlockData b; b.start(2).length(6).string("ab cd ef"); CHECK(b.template get(3) == "cd"); } // ------------------------ @@ -293,45 +293,45 @@ void scenario_get_template_n() // ------------------------ // 0 elements in string - { BodyText b; b.start(0).length(0).string(""); /* no elements */ } - { BodyText b; b.start(0).length(4).string(""); + { BlockData b; b.start(0).length(0).string(""); } + { BlockData b; b.start(0).length(4).string(""); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string(""); + { BlockData b; b.start(1).length(5).string(""); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string(""); + { BlockData b; b.start(2).length(6).string(""); CHECK(b.template get(3) == 0); } // 1 element in string - { BodyText b; b.start(0).length(0).string("12"); + { BlockData b; b.start(0).length(0).string("12"); CHECK(b.template get(0) == 12); } - { BodyText b; b.start(0).length(4).string("12"); + { BlockData b; b.start(0).length(4).string("12"); CHECK(b.template get(1) == 0); } - { BodyText b; b.start(1).length(5).string("12"); + { BlockData b; b.start(1).length(5).string("12"); CHECK(b.template get(2) == 0); } - { BodyText b; b.start(2).length(6).string("12"); + { BlockData b; b.start(2).length(6).string("12"); CHECK(b.template get(3) == 0); } // 3 elements in string - { BodyText b; b.start(0).length(0).string("12 34 56"); + { BlockData b; b.start(0).length(0).string("12 34 56"); CHECK(b.template get(0) == 12); } - { BodyText b; b.start(0).length(4).string("12 34 56"); + { BlockData b; b.start(0).length(4).string("12 34 56"); CHECK(b.template get(1) == 34); } - { BodyText b; b.start(1).length(5).string("12 34 56"); + { BlockData b; b.start(1).length(5).string("12 34 56"); CHECK(b.template get(2) == 34); } - { BodyText b; b.start(2).length(6).string("12 34 56"); + { BlockData b; b.start(2).length(6).string("12 34 56"); CHECK(b.template get(3) == 34); } } -// For BodyText -SCENARIO("BodyText get(n)") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get(n)") { + GIVEN("A BlockData object") { scenario_get_template_n(); } } -// For BodyText -SCENARIO("BodyText get(n)") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get(n)") { + GIVEN("A BlockData object") { scenario_get_template_n(); } } @@ -342,15 +342,15 @@ SCENARIO("BodyText get(n)") { // 3. Scenario: get() // ----------------------------------------------------------------------------- -// For BodyText -SCENARIO("BodyText get()") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get()") { + GIVEN("A BlockData object") { using ivec = std::vector; using fvec = std::vector; using svec = std::vector; - BodyText b; + BlockData b; b.start(2).length(6).string("-12 34 -56"); b.valueType("Integer32"); @@ -377,28 +377,28 @@ SCENARIO("BodyText get()") { } // SCENARIO -// For BodyText -SCENARIO("BodyText get()") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get()") { + GIVEN("A BlockData object") { using ivec = std::vector; using fvec = std::vector; using svec = std::vector; { - BodyText b; + BlockData b; b.start(2).length(6).string("-12 34 -56"); CHECK((b.get() == ivec{{0,0,-12,34,-56,0}})); } { - BodyText b; + BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); CHECK((b.get() == fvec{{0,0,1.2,3.4,5.6,0}})); } { - BodyText b; + BlockData b; b.start(2).length(6).string("ab cd ef"); CHECK((b.get() == svec{{"","","ab","cd","ef",""}})); } @@ -412,11 +412,11 @@ SCENARIO("BodyText get()") { // 4. Scenario: get(n) // ----------------------------------------------------------------------------- -// For BodyText -SCENARIO("BodyText get(n)") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get(n)") { + GIVEN("A BlockData object") { - BodyText b; + BlockData b; // ------------------------ // get(n) form @@ -514,16 +514,16 @@ SCENARIO("BodyText get(n)") { } // SCENARIO -// For BodyText -SCENARIO("BodyText get(n)") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData get(n)") { + GIVEN("A BlockData object") { // ------------------------ // get(n) form // ------------------------ { - BodyText b; + BlockData b; b.start(2).length(6).string("-12 34 -56"); CHECK(( b.get(0) == 0 )); CHECK(( b.get(1) == 0 )); @@ -534,7 +534,7 @@ SCENARIO("BodyText get(n)") { } { - BodyText b; + BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); CHECK(( b.get(0) == 0 )); CHECK(( b.get(1) == 0 )); @@ -545,7 +545,7 @@ SCENARIO("BodyText get(n)") { } { - BodyText b; + BlockData b; b.start(2).length(8).string("ab cd ef 123 4.5"); CHECK(( b.get(0) == "" )); CHECK(( b.get(1) == "" )); @@ -562,7 +562,7 @@ SCENARIO("BodyText get(n)") { // ------------------------ { - BodyText b; + BlockData b; b.start(2).length(6).string("-12 34 -56"); CHECK(( b[0] == 0 )); CHECK(( b[1] == 0 )); @@ -573,7 +573,7 @@ SCENARIO("BodyText get(n)") { } { - BodyText b; + BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); CHECK(( b[0] == 0 )); CHECK(( b[1] == 0 )); @@ -584,7 +584,7 @@ SCENARIO("BodyText get(n)") { } { - BodyText b; + BlockData b; b.start(2).length(6).string("ab cd ef"); CHECK(( b[0] == "" )); CHECK(( b[1] == "" )); @@ -608,7 +608,7 @@ template void scenario_get_named() { { - BodyText b; + BlockData b; b.start(2).length(6).string("-12 34 -56"); auto result = b.ints(); @@ -631,10 +631,10 @@ void scenario_get_named() } { - BodyText b; + BlockData b; b.start(2).length(6).string("1.2 3.4 5.6"); - const BodyText &bconst = b; // ensure it works with const + const BlockData &bconst = b; // ensure it works with const const auto result = bconst.doubles(); CHECK((std::is_same_v>)); @@ -655,7 +655,7 @@ void scenario_get_named() } { - BodyText b; + BlockData b; b.start(2).length(6).string("ab cd ef"); const auto &result = b.strings(); @@ -678,16 +678,18 @@ void scenario_get_named() } } -// For BodyText -SCENARIO("BodyText type-specific get functions: doubles() etc.") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData type-specific get functions: " + "doubles() etc.") { + GIVEN("A BlockData object") { scenario_get_named(); } } -// For BodyText -SCENARIO("BodyText type-specific get functions: doubles() etc.") { - GIVEN("A BodyText object") { +// For BlockData +SCENARIO("BlockData type-specific get functions: " + "doubles() etc.") { + GIVEN("A BlockData object") { scenario_get_named(); } } diff --git a/src/GNDStk/BodyText/test/params.test.cpp b/src/GNDStk/BlockData/test/params.test.cpp similarity index 81% rename from src/GNDStk/BodyText/test/params.test.cpp rename to src/GNDStk/BlockData/test/params.test.cpp index 7e43e3e32..7f6df6682 100644 --- a/src/GNDStk/BodyText/test/params.test.cpp +++ b/src/GNDStk/BlockData/test/params.test.cpp @@ -2,20 +2,20 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- // Helper // ----------------------------------------------------------------------------- -template +template void scenario_params() { // Default values of parameters are as expected WHEN("We examine the default length, start, and valueType") { THEN("They are as expected") { - BodyText b; + BlockData b; CHECK(b.length() == 0); CHECK(b.start() == 0); CHECK(b.valueType() == ""); @@ -25,17 +25,17 @@ void scenario_params() // length setter/getter works WHEN("We set length, then get and verify") { THEN("It works for a plain value") { - BodyText b; + BlockData b; b.length(12); CHECK(b.length() == 12); } THEN("It works for optional-with-value") { - BodyText b; + BlockData b; b.length(std::optional(34)); CHECK(b.length() == 34); } THEN("It works for optional-without-value (remains unchanged)") { - BodyText b; + BlockData b; b.length(56); b.length(std::optional(std::nullopt)); CHECK(b.length() == 56); @@ -45,17 +45,17 @@ void scenario_params() // start setter/getter works WHEN("We set start, then get and verify") { THEN("It works for a plain value") { - BodyText b; + BlockData b; b.start(11); CHECK(b.start() == 11); } THEN("It works for optional-with-value") { - BodyText b; + BlockData b; b.start(std::optional(13)); CHECK(b.start() == 13); } THEN("It works for optional-without-value (remains unchanged)") { - BodyText b; + BlockData b; b.start(17); b.start(std::optional(std::nullopt)); CHECK(b.start() == 17); @@ -65,17 +65,17 @@ void scenario_params() // valueType setter/getter works WHEN("We set valueType, then get and verify") { THEN("It works for a plain value") { - BodyText b; + BlockData b; b.valueType("unknown"); CHECK(b.valueType() == "unknown"); } THEN("It works for optional-with-value") { - BodyText b; + BlockData b; b.valueType(std::optional("Integer32")); CHECK(b.valueType() == "Integer32"); } THEN("It works for optional-without-value (remains unchanged)") { - BodyText b; + BlockData b; b.valueType("Float64"); b.valueType(std::optional(std::nullopt)); CHECK(b.valueType() == "Float64"); @@ -85,7 +85,7 @@ void scenario_params() // Combo of the above, using builder-pattern nature of the setters WHEN("We set length/start/valueType together, then get and verify") { THEN("It works for a plain value") { - BodyText b; + BlockData b; b.length(1) .start(2) .valueType("a"); @@ -94,7 +94,7 @@ void scenario_params() CHECK(b.valueType() == "a"); } THEN("It works for optional-with-value") { - BodyText b; + BlockData b; b.length(std::optional(3)) .start(std::optional(4)) .valueType(std::optional("b")); @@ -103,7 +103,7 @@ void scenario_params() CHECK(b.valueType() == "b"); } THEN("It works for optional-without-value (remains unchanged)") { - BodyText b; + BlockData b; b.length(100).start(200).valueType("c"); b.length(std::optional(std::nullopt)) .start(std::optional(std::nullopt)) @@ -120,14 +120,14 @@ void scenario_params() // Scenarios // ----------------------------------------------------------------------------- -SCENARIO("BodyText length/start/valueType") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData length/start/valueType") { + GIVEN("A default-constructed BlockData object") { scenario_params(); } } -SCENARIO("BodyText length/start/valueType") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData length/start/valueType") { + GIVEN("A default-constructed BlockData object") { scenario_params(); } } diff --git a/src/GNDStk/BlockData/test/print.test.cpp b/src/GNDStk/BlockData/test/print.test.cpp new file mode 100644 index 000000000..5cc03e890 --- /dev/null +++ b/src/GNDStk/BlockData/test/print.test.cpp @@ -0,0 +1,437 @@ + +#include "catch.hpp" +#include "GNDStk.hpp" + +using namespace njoy::GNDStk; + + +// ----------------------------------------------------------------------------- +// Scenario: raw string is active +// ----------------------------------------------------------------------------- + +// Helper: scenario_print_string_active +template +void scenario_print_string_active() +{ + // string is active, but empty + GIVEN("A BlockData with an empty raw string") { + WHEN("BlockData.print() is called") { + THEN("Nothing is printed") { + BlockData b; + b.string(""); + + // with no indentation + std::ostringstream oss; + b.print(oss,0); + CHECK(oss.str() == ""); + + // the same (nothing is printed) even if indentation is nonzero + oss.str(""); + b.print(oss,2); + CHECK(oss.str() == ""); + } + } + } + + // string is active, and contains values + GIVEN("A BlockData with a non-empty raw string") { + WHEN("BlockData.print() is called") { + THEN("The raw string and a newline are printed") { + BlockData b; + b.string("foo bar baz"); + + // with no indentation + std::ostringstream oss; + b.print(oss,0); + CHECK(oss.str() == "foo bar baz\n"); + + // the same, even if indentation is nonzero; indentation isn't + // applied when the raw string (as opposed to the ) is active + oss.str(""); + b.print(oss,2); + CHECK(oss.str() == "foo bar baz\n"); + } + } + } +} + +// For DATATYPE == void +SCENARIO("BlockData print(), when the raw string is active") +{ + scenario_print_string_active(); +} + +// For DATATYPE == double +SCENARIO("BlockData print(), when the raw string is active") +{ + scenario_print_string_active(); +} + + +// ----------------------------------------------------------------------------- +// Scenario: vector is active +// ----------------------------------------------------------------------------- + +SCENARIO("BlockData print(), when a vector is active") +{ + // vector is active, but empty + GIVEN("A BlockData with an empty vector") { + WHEN("BlockData.print() is called") { + THEN("Nothing is printed") { + BlockData b; + b = std::vector{}; + + // with no indentation + std::ostringstream oss; + b.print(oss,0); + CHECK(oss.str() == ""); + + // the same (nothing is printed) even if indentation is nonzero + oss.str(""); + b.print(oss,2); + CHECK(oss.str() == ""); + } + } + } + + // vector is active, and contains values + GIVEN("A BlockData with a non-empty vector") { + WHEN("BlockData.print() is called") { + THEN("The vector and a newline are printed") { + BlockData b; + b = std::vector{{2, 3, 5, 7, 11, 13, 17, 19, 21, 23}}; + std::ostringstream oss; + + // Cases: + // indent: 0, 3 (number of spaces per indentation level) + // columns: 0, 1, 2, 5, 10, 11 (note that 10 == vector size) + // level: 0, 1, 2 (indentation level) + // Note: columns <= 0 means unlimited: so, all values on one line. + // Lots of cases, but we want to check that our prettyprinting + // functionality works perfectly, and doesn't do anything that's + // unexpected around "boundaries" like columns==10 with 10 values. + + oss.str(""); indent = 0; columns = 0; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 0; b.print(oss,1); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 0; b.print(oss,2); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 1; b.print(oss,0); + CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); + + oss.str(""); indent = 0; columns = 1; b.print(oss,1); + CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); + + oss.str(""); indent = 0; columns = 1; b.print(oss,2); + CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); + + oss.str(""); indent = 0; columns = 2; b.print(oss,0); + CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); + + oss.str(""); indent = 0; columns = 2; b.print(oss,1); + CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); + + oss.str(""); indent = 0; columns = 2; b.print(oss,2); + CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); + + oss.str(""); indent = 0; columns = 5; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 5; b.print(oss,1); + CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 5; b.print(oss,2); + CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 10; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 10; b.print(oss,1); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 10; b.print(oss,2); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 11; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 11; b.print(oss,1); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 0; columns = 11; b.print(oss,2); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 0; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 0; b.print(oss,1); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 0; b.print(oss,2); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 1; b.print(oss,0); + CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); + + oss.str(""); indent = 3; columns = 1; b.print(oss,1); + CHECK(oss.str() == + " 2\n 3\n 5\n 7\n 11\n" + " 13\n 17\n 19\n 21\n 23\n"); + + oss.str(""); indent = 3; columns = 1; b.print(oss,2); + CHECK(oss.str() == + " 2\n 3\n 5\n 7\n 11\n" + " 13\n 17\n 19\n 21\n 23\n"); + + oss.str(""); indent = 3; columns = 2; b.print(oss,0); + CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); + + oss.str(""); indent = 3; columns = 2; b.print(oss,1); + CHECK( + oss.str() == + " 2 3\n 5 7\n 11 13\n 17 19\n 21 23\n" + ); + + oss.str(""); indent = 3; columns = 2; b.print(oss,2); + CHECK( + oss.str() == + " 2 3\n 5 7\n 11 13\n 17 19\n 21 23\n" + ); + + oss.str(""); indent = 3; columns = 5; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 5; b.print(oss,1); + CHECK(oss.str() == " 2 3 5 7 11\n 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 5; b.print(oss,2); + CHECK(oss.str() == " 2 3 5 7 11\n 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 10; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 10; b.print(oss,1); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 10; b.print(oss,2); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 11; b.print(oss,0); + CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 11; b.print(oss,1); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + + oss.str(""); indent = 3; columns = 11; b.print(oss,2); + CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); + } + } + } +} + + + +// ----------------------------------------------------------------------------- +// Scenario: vector is active; test GNDStk::truncate +// ----------------------------------------------------------------------------- + +// Helper: test_truncate +template +void test_truncate( + const BlockData &b, + const int indent, + const std::size_t columns, + const int level, + const long truncate, + const std::string &want +) { + njoy::GNDStk::indent = indent; + njoy::GNDStk::columns = columns; + njoy::GNDStk::truncate = truncate; + + std::ostringstream oss; + b.print(oss,level); + + std::cout << "test_truncate:" << std::endl; + std::cout << oss.str() << std::endl; + + CHECK(oss.str() == want); +} + +SCENARIO("BlockData print(), vector, trying GNDStk::truncate") +{ + // vector is active, but empty + GIVEN("A BlockData with an empty vector") { + WHEN("BlockData.print() is called") { + THEN("Nothing is printed") { + BlockData b; + b = std::vector{}; + + using njoy::GNDStk::truncate; + for (truncate = -10; truncate <= 10; ++truncate) { + // with no indentation + std::ostringstream oss; + b.print(oss,0); + CHECK(oss.str() == ""); + + // the same (nothing is printed) even if indentation is nonzero + oss.str(""); + b.print(oss,2); + CHECK(oss.str() == ""); + } + } + } + } + + // vector is active, and contains values + GIVEN("A BlockData with a non-empty vector") { + WHEN("BlockData.print() is called") { + THEN("The vector and a newline are printed") { + BlockData b; + b = std::vector{{2.3, 5.7, 11.13, 17.19, 21.23}}; + + // Cases: + // indent: 3 (number of spaces per indentation level) + // columns: 0, 2, 3 (0 means unlimited) + // level: 0, 1, 2 (indentation level) + // truncate: -1, 0, 1, 2, 3 (-1 means none; so, print all values) + // Lots of cases; we want prettyprinting to be perfect. + + // Integral parameters below are: indent, columns, level, truncate + test_truncate(b, 3, 0, 0, -1, + "2.3 5.7 11.13 17.19 21.23\n"); + test_truncate(b, 3, 0, 0, +0, + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 0, +1, + "2.3\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 0, +2, + "2.3 5.7\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 0, +3, + "2.3 5.7 11.13\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 1, -1, + " 2.3 5.7 11.13 17.19 21.23\n"); + test_truncate(b, 3, 0, 1, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 1, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 1, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 1, +3, + " 2.3 5.7 11.13\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 2, -1, + " 2.3 5.7 11.13 17.19 21.23\n"); + test_truncate(b, 3, 0, 2, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 2, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 2, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 0, 2, +3, + " 2.3 5.7 11.13\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 0, -1, + "2.3 5.7\n" + "11.13 17.19\n" + "21.23\n"); + test_truncate(b, 3, 2, 0, +0, + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 0, +1, + "2.3\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 0, +2, + "2.3 5.7\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 0, +3, + "2.3 5.7\n" + "11.13\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 1, -1, + " 2.3 5.7\n" + " 11.13 17.19\n" + " 21.23\n"); + test_truncate(b, 3, 2, 1, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 1, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 1, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 1, +3, + " 2.3 5.7\n" + " 11.13\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 2, -1, + " 2.3 5.7\n" + " 11.13 17.19\n" + " 21.23\n"); + test_truncate(b, 3, 2, 2, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 2, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 2, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 2, 2, +3, + " 2.3 5.7\n" + " 11.13\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 0, -1, + "2.3 5.7 11.13\n" + "17.19 21.23\n"); + test_truncate(b, 3, 3, 0, +0, + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 0, +1, + "2.3\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 0, +2, + "2.3 5.7\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 0, +3, + "2.3 5.7 11.13\n" + "// truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 1, -1, + " 2.3 5.7 11.13\n" + " 17.19 21.23\n"); + test_truncate(b, 3, 3, 1, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 1, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 1, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 1, +3, + " 2.3 5.7 11.13\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 2, -1, + " 2.3 5.7 11.13\n" + " 17.19 21.23\n"); + test_truncate(b, 3, 3, 2, +0, + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 2, +1, + " 2.3\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 2, +2, + " 2.3 5.7\n" + " // truncated; total #values == 5\n"); + test_truncate(b, 3, 3, 2, +3, + " 2.3 5.7 11.13\n" + " // truncated; total #values == 5\n"); + } + } + } +} diff --git a/src/GNDStk/BodyText/test/string.test.cpp b/src/GNDStk/BlockData/test/string.test.cpp similarity index 79% rename from src/GNDStk/BodyText/test/string.test.cpp rename to src/GNDStk/BlockData/test/string.test.cpp index 549b38041..fb8e8ed39 100644 --- a/src/GNDStk/BodyText/test/string.test.cpp +++ b/src/GNDStk/BlockData/test/string.test.cpp @@ -2,20 +2,20 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- // Helper // ----------------------------------------------------------------------------- -template +template void scenario_string() { // Default value of raw string is as expected WHEN("We examine the raw string") { THEN("It is as expected") { - BodyText b; + BlockData b; CHECK(b.string() == ""); } } @@ -23,7 +23,7 @@ void scenario_string() // Raw string setter/getter works WHEN("We set the raw string") { THEN("It has the correct value, and vector size() == 0 too") { - BodyText b; + BlockData b; // to ensure it clears below... b = std::vector(10); @@ -40,7 +40,7 @@ void scenario_string() // Test in conjunction with length, start, and valueType WHEN("We set string, length, start, and valueType together") { THEN("All values check out") { - BodyText b; + BlockData b; b.string("3 4 5 6").length(10).start(2).valueType("Integer32"); CHECK(b.length() == 10); @@ -56,14 +56,14 @@ void scenario_string() // Scenarios // ----------------------------------------------------------------------------- -SCENARIO("BodyText string()") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData string()") { + GIVEN("A default-constructed BlockData object") { scenario_string(); } } -SCENARIO("BodyText string()") { - GIVEN("A default-constructed BodyText object") { +SCENARIO("BlockData string()") { + GIVEN("A default-constructed BlockData object") { scenario_string(); } } diff --git a/src/GNDStk/BlockData/test/sync.test.cpp b/src/GNDStk/BlockData/test/sync.test.cpp new file mode 100644 index 000000000..9a088d851 --- /dev/null +++ b/src/GNDStk/BlockData/test/sync.test.cpp @@ -0,0 +1,345 @@ + +#include "catch.hpp" +#include "GNDStk.hpp" + +using namespace njoy::GNDStk; + + +// ----------------------------------------------------------------------------- +// Scenario: pull +// Content == any of {length,start,valueType} +// ----------------------------------------------------------------------------- + +// Helper +template +void scenario_pull() +{ + WHEN("pullFromDerived() is called") { + // none of length, start, valueType + THEN("Push to Content{} works") { + struct : public BlockData { + struct { + } Content; + } derived; + BlockData &b = derived; + b.length(100).start(200).valueType("300"); + b.pullFromDerived(derived); // should do nothing here + CHECK(b.length() == 100); + CHECK(b.start() == 200); + CHECK(b.valueType() == "300"); + } + + // length only + THEN("Push to Content{length} works") { + struct : public BlockData { + struct { + int length = 10; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + } derived; + BlockData &b = derived; + b.length(11).start(12).valueType("13"); + b.pullFromDerived(derived); + CHECK(b.length() == 10); + CHECK(b.start() == 12); + CHECK(b.valueType() == "13"); + } + + // start only + THEN("Push to Content{start} works") { + struct : public BlockData { + struct { + int start = 14; + } Content; + const int &start() const { return Content.start; } + int &start() { return Content.start; } + } derived; + BlockData &b = derived; + b.length(15).start(16).valueType("17"); + b.pullFromDerived(derived); + CHECK(b.length() == 15); + CHECK(b.start() == 14); + CHECK(b.valueType() == "17"); + } + + // valueType only + THEN("Push to Content{valueType} works") { + struct : public BlockData { + struct { + std::string valueType = "18"; + } Content; + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(19).start(20).valueType("21"); + b.pullFromDerived(derived); + CHECK(b.length() == 19); + CHECK(b.start() == 20); + CHECK(b.valueType() == "18"); + } + + // all but length + THEN("Push to Content{start,valueType} works") { + struct : public BlockData { + struct { + int start = 22; + std::string valueType = "23"; + } Content; + const int &start() const { return Content.start; } + int &start() { return Content.start; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(24).start(25).valueType("26"); + b.pullFromDerived(derived); + CHECK(b.length() == 24); + CHECK(b.start() == 22); + CHECK(b.valueType() == "23"); + } + + // all but start + THEN("Push to Content{length,valueType} works") { + struct : public BlockData { + struct { + int length = 27; + std::string valueType = "28"; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(29).start(30).valueType("31"); + b.pullFromDerived(derived); + CHECK(b.length() == 27); + CHECK(b.start() == 30); + CHECK(b.valueType() == "28"); + } + + // all but valueType + THEN("Push to Content{length,start} works") { + struct : public BlockData { + struct { + int length = 32; + int start = 33; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const int &start() const { return Content.start; } + int &start() { return Content.start; } + } derived; + BlockData &b = derived; + b.length(34).start(35).valueType("36"); + b.pullFromDerived(derived); + CHECK(b.length() == 32); + CHECK(b.start() == 33); + CHECK(b.valueType() == "36"); + } + + // all three + THEN("Push to Content{length,start,valueType} works") { + struct : public BlockData { + struct { + int length = 37; + int start = 38; + std::string valueType = "39"; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const int &start() const { return Content.start; } + int &start() { return Content.start; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(40).start(41).valueType("42"); + b.pullFromDerived(derived); + CHECK(b.length() == 37); + CHECK(b.start() == 38); + CHECK(b.valueType() == "39"); + } + } +} + + +SCENARIO("BlockData pull from Content") { + GIVEN("A BlockData object") { + scenario_pull(); + } +} + +SCENARIO("BlockData pull from Content") { + GIVEN("A BlockData object") { + scenario_pull(); + } +} + + +// ----------------------------------------------------------------------------- +// Scenario: push +// Content == any of {length,start,valueType} +// ----------------------------------------------------------------------------- + +// Helper +template +void scenario_push() +{ + WHEN("pushToDerived() is called") { + // none of length, start, valueType + THEN("Push to Content{} works") { + struct : public BlockData { + struct { + int ignored = 123456; // not length, start, or valueType + } Content; + const int &ignored() const { return Content.ignored; } + int &ignored() { return Content.ignored; } + } derived; + BlockData &b = derived; + b.length(0).start(0).valueType("0"); + b.pushToDerived(derived); // should do nothing here + CHECK(derived.ignored() == 123456); + } + + // length only + THEN("Push to Content{length} works") { + struct : public BlockData { + struct { + int length = 10; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + } derived; + BlockData &b = derived; + b.length(11).start(12).valueType("13"); + b.pushToDerived(derived); + CHECK(derived.length() == 11); + } + + // start only + THEN("Push to Content{start} works") { + struct : public BlockData { + struct { + int start = 14; + } Content; + const int &start() const { return Content.start; } + int &start() { return Content.start; } + } derived; + BlockData &b = derived; + b.length(15).start(16).valueType("17"); + b.pushToDerived(derived); + CHECK(derived.start() == 16); + } + + // valueType only + THEN("Push to Content{valueType} works") { + struct : public BlockData { + struct { + std::string valueType = "18"; + } Content; + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(19).start(20).valueType("21"); + b.pushToDerived(derived); + CHECK(derived.valueType() == "21"); + } + + // all but length + THEN("Push to Content{start,valueType} works") { + struct : public BlockData { + struct { + int start = 22; + std::string valueType = "23"; + } Content; + const int &start() const { return Content.start; } + int &start() { return Content.start; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(24).start(25).valueType("26"); + b.pushToDerived(derived); + CHECK(derived.start() == 25); + CHECK(derived.valueType() == "26"); + } + + // all but start + THEN("Push to Content{length,valueType} works") { + struct : public BlockData { + struct { + int length = 27; + std::string valueType = "28"; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(29).start(30).valueType("31"); + b.pushToDerived(derived); + CHECK(derived.length() == 29); + CHECK(derived.valueType() == "31"); + } + + // all but valueType + THEN("Push to Content{length,start} works") { + struct : public BlockData { + struct { + int length = 32; + int start = 33; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const int &start() const { return Content.start; } + int &start() { return Content.start; } + } derived; + BlockData &b = derived; + b.length(34).start(35).valueType("36"); + b.pushToDerived(derived); + CHECK(derived.length() == 34); + CHECK(derived.start() == 35); + } + + // all three + THEN("Push to Content{length,start,valueType} works") { + struct : public BlockData { + struct { + int length = 37; + int start = 38; + std::string valueType = "39"; + } Content; + const int &length() const { return Content.length; } + int &length() { return Content.length; } + const int &start() const { return Content.start; } + int &start() { return Content.start; } + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + } derived; + BlockData &b = derived; + b.length(40).start(41).valueType("42"); + b.pushToDerived(derived); + CHECK(derived.length() == 40); + CHECK(derived.start() == 41); + CHECK(derived.valueType() == "42"); + } + } +} + + +SCENARIO("BlockData push to Content") { + GIVEN("A BlockData object") { + scenario_push(); + } +} + +SCENARIO("BlockData push to Content") { + GIVEN("A BlockData object") { + scenario_push(); + } +} diff --git a/src/GNDStk/BodyText/test/toNode.test.cpp b/src/GNDStk/BlockData/test/toNode.test.cpp similarity index 50% rename from src/GNDStk/BodyText/test/toNode.test.cpp rename to src/GNDStk/BlockData/test/toNode.test.cpp index c54fb43ad..6bd63314a 100644 --- a/src/GNDStk/BodyText/test/toNode.test.cpp +++ b/src/GNDStk/BlockData/test/toNode.test.cpp @@ -2,7 +2,7 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- @@ -11,67 +11,68 @@ using namespace njoy::GNDStk::core; // Tests use either void for each template parameter, or int, double, // std::string, and char, in that order. In the former case, we're testing -// toNode() for the generic BodyText<...,void>. In the latter case, we're -// testing toNode() for non-generic BodyText. +// toNode() for the generic BlockData<...,void>. In the latter case, we're +// testing toNode() for non-generic BlockData. template void scenario_toNode() { - // Default-constructed BodyText - GIVEN("A default-constructed BodyText") { + // Default-constructed BlockData + GIVEN("A default-constructed BlockData") { WHEN("toNode() is called") { THEN("The computed text string is empty") { - const BodyText b; - std::string text = "abc"; - struct { + struct : public BlockData { struct { - } content; + } Content; } derived; + BlockData &b = derived; + // w/trim == true (shouldn't matter here; applies to vector) b.trim = true; - b.toNode(text,derived); + b.toNode(text); CHECK(text == ""); // w/trim == false (shouldn't matter here; applies to vector) b.trim = false; - b.toNode(text,derived); + b.toNode(text); CHECK(text == ""); } } } - // BodyText, after being given a particular raw string and parameters - GIVEN("A BodyText, with given raw string and parameters") { + // BlockData, after being given a particular raw string and parameters + GIVEN("A BlockData, with given raw string and parameters") { WHEN("toNode() is called") { THEN("The computed text string is as expected, " "and the parameters remain as given" ) { - BodyText b; - b.string("0 12 34 56 0 0") - .start(100).length(200).valueType("hello"); - - std::string text = "abc"; - struct { + struct : public BlockData { struct { - } content; + } Content; } derived; + BlockData &b = derived; + + b.string("0 12 34 56 0 0") + .start(100).length(200).valueType("hello"); // Someone who sets the raw string directly (as opposed to using // a vector) is stating that they want *exactly* that raw string, - // including any 0s or anything else. To have BodyText's trim flag + // including any 0s or anything else. To have BlockData's trim flag // be relevant, use a vector. // w/trim == true (shouldn't matter here; applies to vector) + std::string text = "abc"; b.trim = true; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "0 12 34 56 0 0"); CHECK(b.start() == 100); CHECK(b.length() == 200); CHECK(b.valueType() == "hello"); // w/trim == false (shouldn't matter here; applies to vector) + text = "abc"; b.trim = false; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "0 12 34 56 0 0"); CHECK(b.start() == 100); CHECK(b.length() == 200); @@ -80,36 +81,37 @@ void scenario_toNode() } } - // BodyText, after being given a particular vector - GIVEN("A BodyText, assigned from a particular vector") { + // BlockData, after being given a particular vector + GIVEN("A BlockData, assigned from a particular vector") { WHEN("toNode() is called") { THEN("The computed text string is as expected, " "and the parameters were computed properly" ) { - BodyText b; + struct : public BlockData { + struct { + } Content; + } derived; + BlockData &b = derived; + // what's set here should be replaced upon assignment from vector b.string("a b c").start(10).length(20).valueType("foobar"); // assign from vector b = std::vector{{0, 0, 12, 34, 56, 78, 0, 0, 0, 0, 0}}; - std::string text = "this should be replaced"; - struct { - struct { - } content; - } derived; - // w/trim == true + std::string text = "this should be replaced"; b.trim = true; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "12 34 56 78"); CHECK(b.start() == 2); CHECK(b.length() == 11); CHECK(b.valueType() == "Integer32"); // w/trim == false + text = "this should be replaced"; b.trim = false; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "0 0 12 34 56 78 0 0 0 0 0"); CHECK(b.start() == 0); CHECK(b.length() == 11); @@ -118,36 +120,37 @@ void scenario_toNode() } } - // BodyText, after being given a particular vector - GIVEN("A BodyText, assigned from a particular vector") { + // BlockData, after being given a particular vector + GIVEN("A BlockData, assigned from a particular vector") { WHEN("toNode() is called") { THEN("The computed text string is as expected, " "and the parameters were computed properly" ) { - BodyText b; + struct : public BlockData { + struct { + } Content; + } derived; + BlockData &b = derived; + // what's set here should be replaced upon assignment from vector b.string("d e f").start(100).length(200).valueType("foobar"); // assign from vector b = std::vector{{0, 0, 0, 1.234, 5.678, 0, 0 }}; - std::string text = "this should be replaced"; - struct { - struct { - } content; - } derived; - // w/trim == true + std::string text = "this should be replaced"; b.trim = true; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "1.234 5.678"); CHECK(b.start() == 3); CHECK(b.length() == 7); CHECK(b.valueType() == "Float64"); // w/trim == false + text = "this should be replaced"; b.trim = false; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "0 0 0 1.234 5.678 0 0"); CHECK(b.start() == 0); CHECK(b.length() == 7); @@ -156,30 +159,30 @@ void scenario_toNode() } } - // BodyText, after being given a particular vector + // BlockData, after being given a particular vector // A key point here is to ensure that ""s (string "zeros") are properly // trimmed at the beginning and end. - GIVEN("A BodyText, assigned from a particular vector") { + GIVEN("A BlockData, assigned from a particular vector") { WHEN("toNode() is called") { THEN("The computed text string is as expected, " "and the parameters were computed properly" ) { - BodyText b; + struct : public BlockData { + struct { + } Content; + } derived; + BlockData &b = derived; + // what's set here should be replaced upon assignment from vector b.string("d e f").start(100).length(200).valueType("foobar"); // assign from vector b = std::vector{{"","","","foo","bar","baz","",""}}; - std::string text = "this should be replaced"; - struct { - struct { - } content; - } derived; - // w/trim == true + std::string text = "this should be replaced"; b.trim = true; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "foo bar baz"); CHECK(b.start() == 3); CHECK(b.length() == 8); @@ -190,8 +193,9 @@ void scenario_toNode() // were true. If it didn't, we'd end up with, well, leading and // trailing *empty* strings, which, well, amount to leading and // trailing nothing. + text = "this should be replaced"; b.trim = false; - b.toNode(text,derived); + b.toNode(text); CHECK(text == "foo bar baz"); CHECK(b.start() == 3); CHECK(b.length() == 8); @@ -200,14 +204,19 @@ void scenario_toNode() } } - // BodyText, after being given a particular vector + // BlockData, after being given a particular vector // For T something other than int, double, and std::string - GIVEN("A BodyText, assigned from a particular vector") { + GIVEN("A BlockData, assigned from a particular vector") { WHEN("toNode() is called") { THEN("The computed text string is as expected, " "and the parameters were computed properly" ) { - BodyText b; + struct : public BlockData { + struct { + } Content; + } derived; + BlockData &b = derived; + // what's set here should be replaced upon assignment from vector b.string("x y z").start(100).length(200).valueType("foobar"); @@ -215,12 +224,7 @@ void scenario_toNode() b = std::vector{{0,0,0,0,0,'a','b','c','d',0}}; std::string text = "this should be replaced"; - struct { - struct { - } content; - } derived; - - b.toNode(text,derived); + b.toNode(text); CHECK(text == "a b c d"); CHECK(b.start() == 5); CHECK(b.length() == 10); @@ -228,129 +232,6 @@ void scenario_toNode() } } } - - // Test various configurations of content{} when calling toNode(). Basically, - // these test whether toNode properly updates whichever of length, start, and - // valueType are in .content of toNode()'s second argument. - GIVEN("A BodyText, with vector") { - WHEN("toNode() is called") { - - // none of length, start, valueType - THEN("Push to content{} works") { - struct { - struct { - int ignored = 12345; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - // toNode doesn't care about what's *not* length/start/valueType... - CHECK(derived.content.ignored == 12345); // same as before toNode() - } - - // length only - THEN("Push to content{length} works") { - struct { - struct { - int length = 0; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.length == 8); - } - - // start only - THEN("Push to content{start} works") { - struct { - struct { - int start = 0; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.start == 2); - } - - // valueType only - THEN("Push to content{valueType} works") { - struct { - struct { - std::string valueType = ""; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.valueType == "Integer32"); - } - - // all but length - THEN("Push to content{start,valueType} works") { - struct { - struct { - int start = 0; - std::string valueType = ""; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.start == 2); - CHECK(derived.content.valueType == "Integer32"); - } - - // all but start - THEN("Push to content{length,valueType} works") { - struct { - struct { - int length = 0; - std::string valueType = ""; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.length == 8); - CHECK(derived.content.valueType == "Integer32"); - } - - // all but valueType - THEN("Push to content{length,start} works") { - struct { - struct { - int length = 0; - int start = 0; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.length == 8); - CHECK(derived.content.start == 2); - } - - // all three - THEN("Push to content{length,start,valueType} works") { - struct { - struct { - int length = 0; - int start = 0; - std::string valueType = ""; - } content; - } derived; - BodyText b; std::string text; - b = std::vector{{0,0,10,20,30,0,0,0}}; - b.toNode(text,derived); - CHECK(derived.content.length == 8); - CHECK(derived.content.start == 2); - CHECK(derived.content.valueType == "Integer32"); - } - } - } } @@ -358,10 +239,10 @@ void scenario_toNode() // Scenario // ----------------------------------------------------------------------------- -SCENARIO("BodyText toNode()") { +SCENARIO("BlockData toNode()") { scenario_toNode(); } -SCENARIO("BodyText toNode()") { +SCENARIO("BlockData toNode()") { scenario_toNode(); } diff --git a/src/GNDStk/BodyText/test/types.test.cpp b/src/GNDStk/BlockData/test/types.test.cpp similarity index 69% rename from src/GNDStk/BodyText/test/types.test.cpp rename to src/GNDStk/BlockData/test/types.test.cpp index 57274301f..ffbee513b 100644 --- a/src/GNDStk/BodyText/test/types.test.cpp +++ b/src/GNDStk/BlockData/test/types.test.cpp @@ -2,115 +2,115 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- // Scenario // ----------------------------------------------------------------------------- -SCENARIO("BodyText data types") { +SCENARIO("BlockData data types") { GIVEN("std::vector for certain specific Ts") { - WHEN("Via BodyText, we make variants of vectors and of scalars") { + WHEN("Via BlockData, we make variants of vectors and of scalars") { // vector type - using vv = BodyText::VariantOfVectors; + using vv = BlockData::VariantOfVectors; THEN("The variant-of-vector size should be correct") { CHECK(std::variant_size_v == 15); } vv vectors; // scalar type - using vs = BodyText::VariantOfScalars; + using vs = BlockData::VariantOfScalars; THEN("The variant-of-scalar size should be correct") { CHECK(std::variant_size_v == 15); } vs scalars; - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,"a"); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == "a"); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,'b'); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 'b'); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-100); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -100); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-200); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -200); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-300); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -300); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-400); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -400); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-500); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -500); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,100); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 100); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,200); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 200); } - THEN("Transformation to vector, and access, work") { - vectors = std::vector(10,300); - scalars = std::get>(vectors)[0]; - CHECK(std::get(scalars) == 300); + THEN("Transforming to vector, and access, work") { + vectors = std::vector(10,300); + scalars = std::get>(vectors)[0]; + CHECK(std::get(scalars) == 300); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,400); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 400); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,500); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 500); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-1.2f); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -1.2f); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,3.4); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == 3.4); } - THEN("Transformation to vector, and access, work") { + THEN("Transforming to vector, and access, work") { vectors = std::vector(10,-5.6); scalars = std::get>(vectors)[0]; CHECK(std::get(scalars) == -5.6); diff --git a/src/GNDStk/BodyText/src/fromNode.hpp b/src/GNDStk/BodyText/src/fromNode.hpp deleted file mode 100644 index c54b50027..000000000 --- a/src/GNDStk/BodyText/src/fromNode.hpp +++ /dev/null @@ -1,39 +0,0 @@ - -// ----------------------------------------------------------------------------- -// BodyText::fromNode(Node) -// ----------------------------------------------------------------------------- - -void fromNode(const Node &node) -{ - // length, start, and valueType might be present in the Node, but we won't - // fetch any of them here. Elsewhere, the current BodyText object should have - // its length, start, and valueType pulled from those respective values in - // an object of a class derived from Component (which in turn derives from - // BodyText). That object's content will have been pulled from the same Node. - // Here, we just get the Node's values: "plain character data" in XML terms. - - bool found = false; - rawstring = node.pcdata(found); - - if (!found) { - rawstring = ""; - - // Warning, re: why are we in BodyText if there's no body text? - // Perhaps it's possible that the Node has a non-default length and/or - // start, so that the values are all supposed to be...zero. Until and - // unless we discover otherwise, however, we doubt that that would be - // the case, and will consider a Node's lack of plain character data, - // in the present context, to be something that merits a warning. - log::warning( - "Component marked as having \"body text\", a.k.a. XML \"pcdata\" " - "(plain\ncharacter data), " - "but no such content was found in the GNDS node." - ); - log::member("BodyText::fromNode(Node, with name \"{}\")", node.name); - } - - // Above, we set the raw string. The following reflects this, so that the - // vector, or a vector in the variant, will be rebuilt from the raw string - // if and when a caller asks for it. - act = Active::string; -} diff --git a/src/GNDStk/BodyText/src/sync.hpp b/src/GNDStk/BodyText/src/sync.hpp deleted file mode 100644 index 98fa02830..000000000 --- a/src/GNDStk/BodyText/src/sync.hpp +++ /dev/null @@ -1,28 +0,0 @@ - -// pullFromDerived(derived) -// Make this BodyText's length, start, and valueType be consistent with any or -// all such parameters that exist in the given object. Remember that this class, -// BodyText, is a base of Component, which is a base of some other class. -template -void pullFromDerived(const T &obj) -{ - if constexpr (detail::hasLength) - length(obj.content.length); - if constexpr (detail::hasStart) - start(obj.content.start); - if constexpr (detail::hasValueType) - valueType(obj.content.valueType); -} - -// pushToDerived(derived) -// The reverse of the above. -template -void pushToDerived(T &obj) const -{ - if constexpr (detail::hasLength) - obj.content.length = length(); - if constexpr (detail::hasStart) - obj.content.start = start(); - if constexpr (detail::hasValueType) - obj.content.valueType = valueType(); -} diff --git a/src/GNDStk/BodyText/src/write.hpp b/src/GNDStk/BodyText/src/write.hpp deleted file mode 100644 index 98dbb4a64..000000000 --- a/src/GNDStk/BodyText/src/write.hpp +++ /dev/null @@ -1,72 +0,0 @@ - -// ----------------------------------------------------------------------------- -// write -// To an ostream (not to a Node; that a different thing) -// ----------------------------------------------------------------------------- - -std::ostream &write(std::ostream &os, const int level) const -{ - // If empty, don't even write a newline - if ((active() == Active::string && rawstring == "") || - (active() == Active::vector && size() == 0)) - return os; - - // ------------------------ - // If string is active - // ------------------------ - - if (active() == Active::string) { - // write the string exactly as-is, without our column formatting - // or any indentation; then also write a newline - GNDStk::color && GNDStk::colors::value != "" - ? os << colors::value << rawstring << colors::reset - : os << rawstring; - return os << std::endl; - } - - // ------------------------ - // If vector is active - // ------------------------ - - // Indentation (string, with some number of spaces) - const auto indent = std::string(GNDStk::indent*level,' '); - - const auto writeLambda = - [&os,&indent](auto &&alt) - { - std::size_t count = 0; - using T = std::decay_t; - - // use our column formatting - for (auto &element : alt) { - count == 0 - ? os << indent - : GNDStk::across == 0 || count % GNDStk::across != 0 - ? os << ' ' - : os << '\n' << indent; - - if (GNDStk::color && GNDStk::colors::value != "") - os << colors::value; - - if constexpr (std::is_floating_point_v) - os << detail::Precision< - detail::PrecisionContext::data, - T - >{}.write(element); - else - os << element; - - if (GNDStk::color && GNDStk::colors::value != "") - os << colors::reset; - - count++; - }; - }; - - if constexpr (runtime) - std::visit(writeLambda,variant); - else - writeLambda(vector); - - return os << std::endl; -} diff --git a/src/GNDStk/BodyText/test/sync.test.cpp b/src/GNDStk/BodyText/test/sync.test.cpp deleted file mode 100644 index 24df290c7..000000000 --- a/src/GNDStk/BodyText/test/sync.test.cpp +++ /dev/null @@ -1,295 +0,0 @@ - -#include "catch.hpp" -#include "GNDStk.hpp" - -using namespace njoy::GNDStk::core; - - -// ----------------------------------------------------------------------------- -// Scenario: pull -// content == any of {length,start,valueType} -// ----------------------------------------------------------------------------- - -// Helper -template -void scenario_pull() -{ - WHEN("pullFromDerived() is called") { - // none of length, start, valueType - THEN("Push to content{} works") { - const struct { - struct { - } content; - } derived; - BodyText b; - b.length(100).start(200).valueType("300"); - b.pullFromDerived(derived); // should do nothing here - CHECK(b.length() == 100); - CHECK(b.start() == 200); - CHECK(b.valueType() == "300"); - } - - // length only - THEN("Push to content{length} works") { - const struct { - struct { - int length = 10; - } content; - } derived; - BodyText b; - b.length(11).start(12).valueType("13"); - b.pullFromDerived(derived); - CHECK(b.length() == 10); - CHECK(b.start() == 12); - CHECK(b.valueType() == "13"); - } - - // start only - THEN("Push to content{start} works") { - const struct { - struct { - int start = 14; - } content; - } derived; - BodyText b; - b.length(15).start(16).valueType("17"); - b.pullFromDerived(derived); - CHECK(b.length() == 15); - CHECK(b.start() == 14); - CHECK(b.valueType() == "17"); - } - - // valueType only - THEN("Push to content{valueType} works") { - const struct { - struct { - std::string valueType = "18"; - } content; - } derived; - BodyText b; - b.length(19).start(20).valueType("21"); - b.pullFromDerived(derived); - CHECK(b.length() == 19); - CHECK(b.start() == 20); - CHECK(b.valueType() == "18"); - } - - // all but length - THEN("Push to content{start,valueType} works") { - const struct { - struct { - int start = 22; - std::string valueType = "23"; - } content; - } derived; - BodyText b; - b.length(24).start(25).valueType("26"); - b.pullFromDerived(derived); - CHECK(b.length() == 24); - CHECK(b.start() == 22); - CHECK(b.valueType() == "23"); - } - - // all but start - THEN("Push to content{length,valueType} works") { - const struct { - struct { - int length = 27; - std::string valueType = "28"; - } content; - } derived; - BodyText b; - b.length(29).start(30).valueType("31"); - b.pullFromDerived(derived); - CHECK(b.length() == 27); - CHECK(b.start() == 30); - CHECK(b.valueType() == "28"); - } - - // all but valueType - THEN("Push to content{length,start} works") { - const struct { - struct { - int length = 32; - int start = 33; - } content; - } derived; - BodyText b; - b.length(34).start(35).valueType("36"); - b.pullFromDerived(derived); - CHECK(b.length() == 32); - CHECK(b.start() == 33); - CHECK(b.valueType() == "36"); - } - - // all three - THEN("Push to content{length,start,valueType} works") { - const struct { - struct { - int length = 37; - int start = 38; - std::string valueType = "39"; - } content; - } derived; - BodyText b; - b.length(40).start(41).valueType("42"); - b.pullFromDerived(derived); - CHECK(b.length() == 37); - CHECK(b.start() == 38); - CHECK(b.valueType() == "39"); - } - } -} - - -SCENARIO("BodyText pull from content") { - GIVEN("A BodyText object") { - scenario_pull(); - } -} - -SCENARIO("BodyText pull from content") { - GIVEN("A BodyText object") { - scenario_pull(); - } -} - - -// ----------------------------------------------------------------------------- -// Scenario: push -// content == any of {length,start,valueType} -// ----------------------------------------------------------------------------- - -// Helper -template -void scenario_push() -{ - WHEN("pushToDerived() is called") { - // none of length, start, valueType - THEN("Push to content{} works") { - struct { - struct { - int ignored = 123456; // not length, start, or valueType - } content; - } derived; - BodyText b; - b.length(0).start(0).valueType("0"); - b.pushToDerived(derived); // should do nothing here - CHECK(derived.content.ignored == 123456); - } - - // length only - THEN("Push to content{length} works") { - struct { - struct { - int length = 10; - } content; - } derived; - BodyText b; - b.length(11).start(12).valueType("13"); - b.pushToDerived(derived); - CHECK(derived.content.length == 11); - } - - // start only - THEN("Push to content{start} works") { - struct { - struct { - int start = 14; - } content; - } derived; - BodyText b; - b.length(15).start(16).valueType("17"); - b.pushToDerived(derived); - CHECK(derived.content.start == 16); - } - - // valueType only - THEN("Push to content{valueType} works") { - struct { - struct { - std::string valueType = "18"; - } content; - } derived; - BodyText b; - b.length(19).start(20).valueType("21"); - b.pushToDerived(derived); - CHECK(derived.content.valueType == "21"); - } - - // all but length - THEN("Push to content{start,valueType} works") { - struct { - struct { - int start = 22; - std::string valueType = "23"; - } content; - } derived; - BodyText b; - b.length(24).start(25).valueType("26"); - b.pushToDerived(derived); - CHECK(derived.content.start == 25); - CHECK(derived.content.valueType == "26"); - } - - // all but start - THEN("Push to content{length,valueType} works") { - struct { - struct { - int length = 27; - std::string valueType = "28"; - } content; - } derived; - BodyText b; - b.length(29).start(30).valueType("31"); - b.pushToDerived(derived); - CHECK(derived.content.length == 29); - CHECK(derived.content.valueType == "31"); - } - - // all but valueType - THEN("Push to content{length,start} works") { - struct { - struct { - int length = 32; - int start = 33; - } content; - } derived; - BodyText b; - b.length(34).start(35).valueType("36"); - b.pushToDerived(derived); - CHECK(derived.content.length == 34); - CHECK(derived.content.start == 35); - } - - // all three - THEN("Push to content{length,start,valueType} works") { - struct { - struct { - int length = 37; - int start = 38; - std::string valueType = "39"; - } content; - } derived; - BodyText b; - b.length(40).start(41).valueType("42"); - b.pushToDerived(derived); - CHECK(derived.content.length == 40); - CHECK(derived.content.start == 41); - CHECK(derived.content.valueType == "42"); - } - } -} - - -SCENARIO("BodyText push to content") { - GIVEN("A BodyText object") { - scenario_push(); - } -} - -SCENARIO("BodyText push to content") { - GIVEN("A BodyText object") { - scenario_push(); - } -} diff --git a/src/GNDStk/BodyText/test/write.test.cpp b/src/GNDStk/BodyText/test/write.test.cpp deleted file mode 100644 index ac0095b27..000000000 --- a/src/GNDStk/BodyText/test/write.test.cpp +++ /dev/null @@ -1,226 +0,0 @@ - -#include "catch.hpp" -#include "GNDStk.hpp" - -using namespace njoy::GNDStk::core; - - -// ----------------------------------------------------------------------------- -// Scenario: raw string -// ----------------------------------------------------------------------------- - -// Helper -template -void scenario_write_string_active() -{ - GIVEN("A BodyText with an empty raw string") { - WHEN("BodyText.write() is called") { - THEN("Nothing is printed") { - BodyText b; - b = std::vector{{'a','b','c'}}; - b.string(""); // should make string (not vector) active - std::ostringstream oss; - b.write(oss,0); - CHECK(oss.str() == ""); - - // same (nothing printed) if indentation is non-0 - b.write(oss,2); - CHECK(oss.str() == ""); - } - } - } - - GIVEN("A BodyText with a non-empty raw string") { - WHEN("BodyText.write() is called") { - THEN("The raw string and a newline are printed") { - BodyText b; - b = std::vector{{'a','b','c'}}; - b.string("foo bar"); // should make string (not vector) active - - std::ostringstream oss; - b.write(oss,0); - CHECK(oss.str() == "foo bar\n"); - - // indentation isn't applied when the raw string is active - oss.str(""); - b.write(oss,2); - CHECK(oss.str() == "foo bar\n"); - } - } - } -} - -// For DATA == void -SCENARIO("BodyText write(), when the raw string is active") { - scenario_write_string_active(); -} - -// For DATA != void -SCENARIO("BodyText write(), when the raw string is active") { - scenario_write_string_active(); -} - - -// ----------------------------------------------------------------------------- -// Scenario: vector -// ----------------------------------------------------------------------------- - -// Helper -template -void scenario_write_vector_active() -{ - GIVEN("A BodyText with an empty vector") { - WHEN("BodyText.write() is called") { - THEN("Nothing is printed") { - BodyText b; - b.string("should be ignored"); // because vector is forthcoming... - b = std::vector{}; - std::ostringstream oss; - b.write(oss,0); - CHECK(oss.str() == ""); - - // same (nothing printed) if indentation is non-0 - b.write(oss,2); - CHECK(oss.str() == ""); - } - } - } - - GIVEN("A BodyText with a non-empty vector") { - WHEN("BodyText.write() is called") { - THEN("The vector and a newline are printed") { - BodyText b; - b.string("should be ignored"); // because vector is forthcoming... - b = std::vector{{2,3,5,7,11,13,17,19,21,23}}; - std::ostringstream oss; - - // Cases: - // indent: 0, 3 (number of spaces per indentation level) - // across: 0, 1, 2, 5, 10, 11 (note that 10 == vector size) - // level: 0, 1, 2 (indentation level) - // Note: across == 0 ==> unlimited. - // Lots of cases, but we want to check that our pretty-printing - // functionality works perfectly, and doesn't do anything that's - // unexpected around "boundaries" like across==10 with 10 values. - - oss.str(""); indent = 0; across = 0; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 0; b.write(oss,1); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 0; b.write(oss,2); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 1; b.write(oss,0); - CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); - - oss.str(""); indent = 0; across = 1; b.write(oss,1); - CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); - - oss.str(""); indent = 0; across = 1; b.write(oss,2); - CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); - - oss.str(""); indent = 0; across = 2; b.write(oss,0); - CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); - - oss.str(""); indent = 0; across = 2; b.write(oss,1); - CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); - - oss.str(""); indent = 0; across = 2; b.write(oss,2); - CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); - - oss.str(""); indent = 0; across = 5; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 5; b.write(oss,1); - CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 5; b.write(oss,2); - CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 10; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 10; b.write(oss,1); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 10; b.write(oss,2); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 11; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 11; b.write(oss,1); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 0; across = 11; b.write(oss,2); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 0; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 0; b.write(oss,1); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 0; b.write(oss,2); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 1; b.write(oss,0); - CHECK(oss.str() == "2\n3\n5\n7\n11\n13\n17\n19\n21\n23\n"); - - oss.str(""); indent = 3; across = 1; b.write(oss,1); - CHECK(oss.str() == " 2\n 3\n 5\n 7\n 11\n 13\n 17\n 19\n 21\n 23\n"); - - oss.str(""); indent = 3; across = 1; b.write(oss,2); - CHECK(oss.str() == " 2\n 3\n 5\n 7\n 11\n 13\n 17\n 19\n 21\n 23\n"); - - oss.str(""); indent = 3; across = 2; b.write(oss,0); - CHECK(oss.str() == "2 3\n5 7\n11 13\n17 19\n21 23\n"); - - oss.str(""); indent = 3; across = 2; b.write(oss,1); - CHECK(oss.str() == " 2 3\n 5 7\n 11 13\n 17 19\n 21 23\n"); - - oss.str(""); indent = 3; across = 2; b.write(oss,2); - CHECK(oss.str() == " 2 3\n 5 7\n 11 13\n 17 19\n 21 23\n"); - - oss.str(""); indent = 3; across = 5; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11\n13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 5; b.write(oss,1); - CHECK(oss.str() == " 2 3 5 7 11\n 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 5; b.write(oss,2); - CHECK(oss.str() == " 2 3 5 7 11\n 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 10; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 10; b.write(oss,1); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 10; b.write(oss,2); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 11; b.write(oss,0); - CHECK(oss.str() == "2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 11; b.write(oss,1); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - - oss.str(""); indent = 3; across = 11; b.write(oss,2); - CHECK(oss.str() == " 2 3 5 7 11 13 17 19 21 23\n"); - } - } - } -} - -// For DATA == void -SCENARIO("BodyText write(), when a vector is active") { - scenario_write_vector_active(); -} - -// For DATA != void -SCENARIO("BodyText write(), when a vector is active") { - scenario_write_vector_active(); -} diff --git a/src/GNDStk/Child.hpp b/src/GNDStk/Child.hpp index 4cb0bc77c..a221670fa 100644 --- a/src/GNDStk/Child.hpp +++ b/src/GNDStk/Child.hpp @@ -10,9 +10,9 @@ TYPE - The type to which GNDStk should convert a Node that's extracted from a Tree - with the Child object. If TYPE is void, then GNDStk uses Node - the child - node, in its original form in the tree. + The type to which GNDStk should convert a Node that's extracted, via our + query system, with the Child object. If TYPE is void, then GNDStk uses + type Node - the child node in its original form. ALLOW @@ -29,13 +29,13 @@ ALLOW In other words: there are (or can be) any number of nodes within an enclosing context (here, ). ALLOW is a template parameter because - it affects the *type* that's pulled from the Tree when the Child object - is used for a query. For example, + it affects the *type* that's extracted when the Child object is used for a + query. For example, tree(...,axes,axis) gives back a container of axis objects, not a single axis object, because - our Child axis keyword has ALLOW == Allow::any. Note that axes, not to be + our Child axis object has ALLOW == Allow::any. Note that axes, not to be confused with axis, has ALLOW == Allow::one because it's expected just once. CONVERTER @@ -57,7 +57,7 @@ FILTER template< class TYPE = void, // default means current Node type Allow ALLOW = Allow::one, // one, or any number allowed? - class CONVERTER = typename detail::default_converter::type, + class CONVERTER = detail::default_converter_t, class FILTER = detail::noFilter > class Child { @@ -72,12 +72,6 @@ class Child { const TYPE object; CONVERTER converter; // optional custom converter; needs operator() FILTER filter; // optional custom filter; needs operator() -private: - // allowable as top-level? - // We make this private, with a setter and a getter, so that the setter - // can register the name as "allowable as top-level" if we set to true. - bool canBeTopLevel; -public: // ------------------------ // constructors @@ -87,36 +81,14 @@ class Child { // name, type // name, type, converter // name, type, converter, filter - // name, type, converter, filter, top explicit Child( const std::string &n, - const TYPE &t = TYPE{}, - const CONVERTER &c = CONVERTER{}, - const FILTER &f = FILTER{}, - const bool canbetop = false + const TYPE &t = detail::static_const(), + const CONVERTER &c = detail::static_const(), + const FILTER &f = detail::static_const() ) : name(n), object(t), converter(c), filter(f) - { - top(canbetop); - } - - // ------------------------ - // top(): allowable - // as a top-level node? - // ------------------------ - - // top() - bool top() const - { - return canBeTopLevel; - } - - // top(bool) - void top(const bool t) - { - if (t) detail::AllowedTop.insert(name); - canBeTopLevel = t; - } + { } // ------------------------ // simple functions @@ -128,7 +100,7 @@ class Child { auto basic() const { return Child( - name, filter, canBeTopLevel // converter not possible here + name, filter // converter not possible here ); } @@ -137,7 +109,7 @@ class Child { auto one() const { return Child( - name, object, converter, filter, canBeTopLevel + name, object, converter, filter ); } @@ -146,7 +118,7 @@ class Child { auto many() const { return Child( - name, object, converter, filter, canBeTopLevel + name, object, converter, filter ); } }; @@ -173,10 +145,6 @@ class Child { // name, filter std::string name; FILTER filter; // optional custom filter; needs operator() -private: - // allowable as top-level? - bool canBeTopLevel; -public: // ------------------------ // constructors @@ -184,34 +152,12 @@ class Child { // name // name, filter - // name, filter, top explicit Child( const std::string &n, - const FILTER &f = FILTER{}, - const bool t = false + const FILTER &f = detail::static_const() ) : name(n), filter(f) - { - top(t); - } - - // ------------------------ - // top(): allowable - // as a top-level node? - // ------------------------ - - // top() - bool top() const - { - return canBeTopLevel; - } - - // top(bool) - void top(const bool t) - { - if (t) detail::AllowedTop.insert(name); - canBeTopLevel = t; - } + { } // ------------------------ // simple functions @@ -222,21 +168,21 @@ class Child { // we're already void; this is here for consistency with the general case. auto basic() const { - return Child(name,filter,canBeTopLevel); + return Child(name,filter); } // one() // Produce an equivalent Child, but formulated as Allow::one auto one() const { - return Child(name,filter,canBeTopLevel); + return Child(name,filter); } // many() // Produce an equivalent Child, but formulated as Allow::many auto many() const { - return Child(name,filter,canBeTopLevel); + return Child(name,filter); } }; @@ -246,13 +192,12 @@ class Child { // Macro // ----------------------------------------------------------------------------- -// For Child building. This macro doesn't handle the optional "top-level" -// flag, the converter, or the filter; we don't believe those will be needed -// very often. If you do need to provide one or both, construct a Child -// in some other way than by using this macro. +// For Child building. This macro doesn't handle the converter or the filter; +// we don't believe those will be needed very often. If you do need to provide +// one or both, construct a Child in some other way than by using this macro. #define GNDSTK_MAKE_CHILD(TYPE,name,ALLOW) \ - inline const Child name(#name) + inline const njoy::GNDStk::Child name(#name) // Note: we don't #undef this after we use it within GNDStk, as we might // normally do, because users might find it handy. diff --git a/src/GNDStk/Child/src/operator.hpp b/src/GNDStk/Child/src/operator.hpp index 0bbe2c677..9fca8d255 100644 --- a/src/GNDStk/Child/src/operator.hpp +++ b/src/GNDStk/Child/src/operator.hpp @@ -16,42 +16,6 @@ inline auto operator-(const Child &kwd) -// ----------------------------------------------------------------------------- -// operator~: Allow as top-level -// operator!: Disallow as top-level -// -// We don't expect much use of these, but someone may occasionally find the -// first (more likely) or the second (less likely) to be helpful. The unary -// operators that we chose for these purposes seemed like the best, given a -// limited selection. One could think: (T)ilde for (T)op; Not for Not. -// ----------------------------------------------------------------------------- - -// operator~ -template -inline auto operator~(const Child &kwd) -{ - auto ret = kwd; - ret.top(true); - return ret; -} - -// operator! -// fixme This switches off the canBeTopLevel flag in an individual Child, -// but we actually use the namespace-scope set AllowedTop when we -// determine if a particular name is allowed as a top-level node. So, turning -// of a Child's previously-true top-level designator does not, at the moment, -// have any meaningful effect anywhere. We'll look at this more carefully -// sometime. For now, this just isn't a super important issue. -template -inline auto operator!(const Child &kwd) -{ - auto ret = kwd; - ret.top(false); - return ret; -} - - - // ----------------------------------------------------------------------------- // T/Child // Change type to T @@ -68,8 +32,7 @@ inline auto operator/( kwd.name, object, kwd.converter, - kwd.filter, - kwd.top() + kwd.filter ); } @@ -79,13 +42,12 @@ inline auto operator/( const T &object, const Child &kwd ) { - using CONVERTER = typename detail::default_converter::type; + using CONVERTER = detail::default_converter_t; return Child( kwd.name, object, CONVERTER{}, // because the input Child didn't have one - kwd.filter, - kwd.top() + kwd.filter ); } @@ -174,8 +136,7 @@ inline Child< kwd.name, kwd.object, converter, // the new one; not kwd.converter! - kwd.filter, - kwd.top() + kwd.filter ); } @@ -210,13 +171,12 @@ inline auto operator--( const Child &kwd, const int ) { - using C = typename detail::default_converter::type; + using C = detail::default_converter_t; return Child( kwd.name, kwd.object, C{}, - kwd.filter, - kwd.top() + kwd.filter ); } @@ -267,8 +227,7 @@ inline auto operator+( kwd.name, kwd.object, kwd.converter, - filter, // the new one - kwd.top() + filter // the new one ); } @@ -280,8 +239,7 @@ inline auto operator+( ) { return Child( kwd.name, - filter, // the new one - kwd.top() + filter // the new one ); } @@ -305,9 +263,7 @@ inline auto operator||( // both names, space-separated; this gets special treatment elsewhere a.name + " " + b.name, // need a filter; use the first Child's - a.filter, - // if either is top-level enabled - a.top() || b.top() + a.filter ); } @@ -329,8 +285,6 @@ inline auto operator||( // both names, space-separated; this gets special treatment elsewhere a.name + " " + b.name, // need an object, converter, and filter; use the first Child's - a.object, a.converter, a.filter, - // if either is top-level enabled - a.top() || b.top() + a.object, a.converter, a.filter ); } diff --git a/src/GNDStk/Child/test/Child.test.cpp b/src/GNDStk/Child/test/Child.test.cpp index ac43846b9..c0de1b37e 100644 --- a/src/GNDStk/Child/test/Child.test.cpp +++ b/src/GNDStk/Child/test/Child.test.cpp @@ -24,28 +24,24 @@ SCENARIO("Testing GNDStk Child") { const Child foo("foo"); CHECK(foo.name == "foo"); - CHECK(!foo.top()); } WHEN("Constructed with (name,converter)") { const Child foo("foo", 0.0, converter{}); CHECK(foo.name == "foo"); - CHECK(!foo.top()); } WHEN("Constructed with (name,converter,filter)") { const Child foo("foo", 0.0, converter{}, filter); CHECK(foo.name == "foo"); - CHECK(!foo.top()); } WHEN("Constructed with (name,converter,filter,top)") { const Child - foo("foo", 0.0, converter{}, filter, true); + foo("foo", 0.0, converter{}, filter); CHECK(foo.name == "foo"); - CHECK(foo.top()); } } @@ -55,21 +51,18 @@ SCENARIO("Testing GNDStk Child") { const Child foo("foo"); CHECK(foo.name == "foo"); - CHECK(!foo.top()); } WHEN("Constructed with (name,filter)") { const Child foo("foo", filter); CHECK(foo.name == "foo"); - CHECK(!foo.top()); } WHEN("Constructed with (name,filter,top)") { const Child - foo("foo", filter, true); + foo("foo", filter); CHECK(foo.name == "foo"); - CHECK(foo.top()); } } } diff --git a/src/GNDStk/Child/test/operator.test.cpp b/src/GNDStk/Child/test/operator.test.cpp index 1ec2af774..af7646875 100644 --- a/src/GNDStk/Child/test/operator.test.cpp +++ b/src/GNDStk/Child/test/operator.test.cpp @@ -128,45 +128,6 @@ SCENARIO("Testing GNDStk Child operators") { } } - // ------------------------ - // ~Child - // !Child - // top() - // top(bool) - // ------------------------ - - GIVEN("Some Child objects") { - const Child foo("foo"); - const Child bar("bar"); - Child one("one"); - one.top(true); - Child two("two"); - two.top(true); - - CHECK(!foo.top()); - CHECK(!bar.top()); - CHECK(one.top()); - CHECK(two.top()); - - WHEN("We apply ~Child") { - THEN("Top-level is enabled") { - CHECK((~foo).top()); - CHECK((~bar).top()); - CHECK((~one).top()); - CHECK((~two).top()); - } - } - - WHEN("We apply !Child") { - THEN("Top-level is disabled") { - CHECK(!(!foo).top()); - CHECK(!(!bar).top()); - CHECK(!(!one).top()); - CHECK(!(!two).top()); - } - } - } - // ------------------------ // type/Child // ------------------------ diff --git a/src/GNDStk/Component.hpp b/src/GNDStk/Component.hpp index 942acea86..b313340fc 100644 --- a/src/GNDStk/Component.hpp +++ b/src/GNDStk/Component.hpp @@ -13,16 +13,21 @@ using helpMap = std::map; // Component // ----------------------------------------------------------------------------- -template -class Component : public BodyText +template +class Component : public BlockData { // For convenience - using body = BodyText; - using typename body::VariantOfVectors; - using typename body::VariantOfScalars; + using BLOCKDATA = BlockData; + using typename BLOCKDATA::VariantOfVectors; + using typename BLOCKDATA::VariantOfScalars; + static const auto &Keys() + { + static const auto value = makeKeyTuple(DERIVED::KEYS()); + return value; + } // Links to fields in the object of the derived class. I can't find a way - // to do this in a decltype(DERIVED::keys())-aware manner, because DERIVED + // to do this in a decltype(DERIVED::KEYS())-aware manner, because DERIVED // is generally an incomplete type *here* - outside of Component's member // functions. So, we'll do it the old-fashioned way. std::vector links; @@ -35,12 +40,12 @@ class Component : public BodyText // Copy and move *assignments* have the right behavior, however. Component &operator=(const Component &other) { - body::operator=(other); + BLOCKDATA::operator=(other); return *this; } Component &operator=(Component &&other) { - body::operator=(std::move(other)); + BLOCKDATA::operator=(std::move(other)); return *this; } @@ -51,22 +56,35 @@ class Component : public BodyText // See comments in finish.hpp #include "GNDStk/Component/src/finish.hpp" - // Intermediaries between derived-class getters, and getter functions - // in detail::. These shorten the code in the derived classes. + // Helpers for derived-class getters/setters. + // These shorten the code in the derived classes. #include "GNDStk/Component/src/getter.hpp" + #include "GNDStk/Component/src/setter.hpp" // Fallback for documentation() if DERIVED doesn't have help static inline helpMap help; public: + #include "GNDStk/Component/src/read.hpp" + #include "GNDStk/Component/src/write.hpp" + #include "GNDStk/Component/src/print.hpp" #include "GNDStk/Component/src/fromNode.hpp" #include "GNDStk/Component/src/sort.hpp" #include "GNDStk/Component/src/toNode.hpp" // conversion to Node - #include "GNDStk/Component/src/write.hpp" - // You can (but don't need to) override the following in DERIVED - static std::string namespaceName() { return ""; } + // You can (but need not) override the following in DERIVED + static std::string NAMESPACE() { return ""; } + + // baseBlockData + // Convenient access to the BlockData base class + BLOCKDATA &baseBlockData() { return *this; } + const BLOCKDATA &baseBlockData() const { return *this; } + + // baseComponent + // Convenient access to the Component base class (of the derived class) + Component &baseComponent() { return *this; } + const Component &baseComponent() const { return *this; } // derived // Convenient access to the derived class @@ -80,15 +98,35 @@ class Component : public BodyText { try { return DERIVED::help.at(subject); - } - catch ( ... ) { + } catch ( ... ) { return "No help information is available"; } } - // Component << std::string - // Meaning: read the string's content (currently XML or JSON) into an object - // of the Component's DERIVED class. Uses Node's << std::string capability. + // has + // Usable in C++ "compile-time if" (a.k.a. "if constexpr") statements + template< + class EXTRACTOR, class THIS = DERIVED, + class = decltype(std::declval()(THIS{})) + > + static constexpr bool has(const Lookup &) + { + return true; + } + + template< + class EXTRACTOR, bool F, + class = std::enable_if_t + > + static constexpr bool has(const Lookup &) + { + return false; + } + + static std::string CLASS() { return DERIVED::CLASS(); } + + // Component << string + // Like Node << string, but for Component's derived class. void operator<<(const std::string &str) { try { @@ -96,7 +134,19 @@ class Component : public BodyText node << str; derived() = DERIVED(node); } catch (...) { - log::function(std::string(DERIVED::className()) + " << string"); + log::function("{} << string", CLASS()); + throw; + } + } + + // Component >> string + // Like Node >> string, but for Component's derived class. + void operator>>(std::string &str) const + { + try { + Node(*this) >> str; + } catch (...) { + log::function("{} >> string", CLASS()); throw; } } @@ -105,13 +155,33 @@ class Component : public BodyText // ----------------------------------------------------------------------------- -// ostream << Component +// Stream I/O // ----------------------------------------------------------------------------- -template +// operator>> +template +std::istream &operator>>( + std::istream &is, + Component &comp +) { + try { + return comp.read(is); + } catch (...) { + log::function("istream >> {}", comp.CLASS()); + throw; + } +} + +// operator<< +template std::ostream &operator<<( std::ostream &os, - const Component &obj + const Component &comp ) { - return obj.write(os); + try { + return comp.print(os,0); + } catch (...) { + log::function("ostream << {}", comp.CLASS()); + throw; + } } diff --git a/src/GNDStk/Component/src/ctor.hpp b/src/GNDStk/Component/src/ctor.hpp index f289a5058..7e6d24233 100644 --- a/src/GNDStk/Component/src/ctor.hpp +++ b/src/GNDStk/Component/src/ctor.hpp @@ -8,39 +8,24 @@ friend DERIVED; // ctor: fields template -Component(const body &other, ARGS &...args) : body(other) +Component(const BLOCKDATA &other, ARGS &...args) : BLOCKDATA(other) { - // static_assert needs string literal - #define pairing_error \ - "The number and/or types of the fields sent to Component's " \ - "constructor is inconsistent with the query result implied " \ - "by the derived class' keys()" - // I'd have preferred to achieve the following check by using SFINAE // in the constructor's signature, but couldn't find a way to do that // without again running into the issue of DERIVED being incomplete. + // Type that a multi-query with DERIVED::KEYS() will produce. + using multi_t = detail::decays_t; + // The parameters that are sent to this constructor must EXACTLY reflect - // what we'd get from a DERIVED::keys() multi-query. - if constexpr (std::is_same_v>) { - // keys is "empty" (std::tuple<>); that's OK, as long as ARGS is too - static_assert( - std::is_same_v, std::tuple<>>, - pairing_error - ); - } else { - // keys are *not* empty, so... - // The following is the *type* that a multi-query with DERIVED::keys() - // will produce. - using multi_t = - detail::decays_t; - static_assert( - std::is_same_v, multi_t>, - pairing_error - ); - // Create links - (links.push_back(&args), ...); - } + // what we'd get from a DERIVED::KEYS() multi-query. + static_assert( + std::is_same_v, multi_t>, + "The number and/or types of the fields sent to Component's " + "constructor is inconsistent with the query result implied " + "by the KEYS() function in the derived class" + ); - #undef pairing_error + // Create links + (links.push_back(&args), ...); } diff --git a/src/GNDStk/Component/src/detail-getter.hpp b/src/GNDStk/Component/src/detail-getter.hpp new file mode 100644 index 000000000..76ac4cfcb --- /dev/null +++ b/src/GNDStk/Component/src/detail-getter.hpp @@ -0,0 +1,559 @@ + +// ----------------------------------------------------------------------------- +// Some helper classes +// ----------------------------------------------------------------------------- + +// ------------------------ +// isLookup +// ------------------------ + +// general +template +struct isLookup + : public std::false_type +{ }; + +// for Lookup +template +struct isLookup> + : public std::true_type +{ }; + +// ------------------------ +// isLookupRefReturn +// ------------------------ + +// general +template +struct isLookupRefReturn + : public std::false_type +{ }; + +// for Lookup, with TYPE != void wanted +template +struct isLookupRefReturn> +{ + static inline constexpr bool value = !isVoid; +}; + +// ------------------------ +// isSearchKey +// isSearchKeyRefReturn +// ------------------------ + +// Type is one of: +// - convertible to std::size_t, for use as an index +// - convertible to std::string, for use as a label +// - of type Lookup<...> +template +using isSearchKey = std::enable_if_t< + std::is_convertible_v || + std::is_convertible_v || + isLookup::value +>; + +// Like above, but allowing only a Lookup that triggers a reference return +template +using isSearchKeyRefReturn = std::enable_if_t< + std::is_convertible_v || + std::is_convertible_v || + isLookupRefReturn::value +>; + +// ------------------------ +// firstOrOnly +// ------------------------ + +// general +template +struct firstOrOnly { + using type = T; +}; + +// for variant +template +struct firstOrOnly> { + using type = T; +}; + +// ------------------------ +// has_field +// Compare with has_index, +// as defined elsewhere +// ------------------------ + +// default +template +struct has_field + : std::false_type { }; + +// general +template +struct has_field< + EXTRACTOR, + T, + decltype( + (void)std::declval()( + std::conditional_t::value,void,T>{} + ), + 0 + ) +> + : std::true_type { }; + +// for variant +template +struct has_field< + EXTRACTOR, + std::variant +> { + // does any alternative have the field? + static constexpr bool value = (has_field::value || ...); +}; + + + +// ----------------------------------------------------------------------------- +// getter(vector, index, names...) +// Element of the vector that has .index() == index. +// Or, use C++ [index] if the element type doesn't have an .index() getter. +// ----------------------------------------------------------------------------- + +template +const T &getter( + const std::vector &vec, + const std::size_t &index, + // for the Component-derived class: names of namespace, class, relevant field + const std::string &nname, const std::string &cname, const std::string &fname +) { + static const std::string context = "getter {}::{}.{}({}) on vector"; + + try { + + if constexpr (hasIndex) { + // hasIndex + // T (or at least one of its alternatives, if T is a variant) has + // a metadatum called "index". In this case, this function's index + // parameter is interpreted to mean: find the object with an "index" + // metadatum that matches the parameter. Importantly, then, index + // in this case is ***NOT*** a C++ [index] index! + + // fixme Make this more efficient, e.g. by assuming that the vector's + // elements are sorted by index, so that the wanted value is probably + // at [index], even though a vector [index] is not the interpretation. + const T *object = nullptr; + + for (auto &elem : vec) { + const T *ptr = nullptr; + + if constexpr (isVariant::value) { + // T == variant + std::visit( + [&elem,&index,&ptr](auto &&alternative) + { + if constexpr (hasIndex) + if (alternative.index() == index) + ptr = &elem; + }, + elem + ); + } else { + // T != variant + if constexpr (hasIndex) + if (elem.index() == index) + ptr = &elem; + } + + if (ptr) { + if (object) { + log::warning( + "Element with metadatum \"index\" {} was already found " + "in the vector.\n" + "Keeping the first element that was found.", + index + ); + log::member(context, nname, cname, fname, index); + } else + object = ptr; + } + } // for + + if (object) + return *object; + + log::error( + "Element with metadatum index == {} was not found in the vector" + + std::string(vec.size() ? "." : ";\nin fact the vector is empty."), + index + ); + throw std::exception{}; + + } else { + // !hasIndex + // No "index" is anywhere to be found in T. Here, then, we interpret + // this function's index parameter to be a C++ vector [index]. + if (index < vec.size()) + return vec[index]; + + if (vec.size() == 0) + log::error( + "Index {} is out of range; vector is empty.", + index); + else + log::error( + "Index {} is out of range; vector has [0..{}].", + index, vec.size()-1); + + throw std::exception{}; + } + + } catch (...) { + // context + log::member(context, nname, cname, fname, index); + throw; + } +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, label, names...) +// Element of the vector that has .label() == label. +// Assumes that the element type has a .label() getter. +// ----------------------------------------------------------------------------- + +template +const T &getter( + const std::vector &vec, + const std::string &label, + const std::string &nname, const std::string &cname, const std::string &fname +) { + static const std::string context = "getter {}::{}.{}(\"{}\") on vector"; + + try { + const T *object = nullptr; + + for (auto &elem : vec) { + const T *ptr = nullptr; + + if constexpr (isVariant::value) { + // T == variant + std::visit( + [&elem,&label,&ptr](auto &&alternative) + { + if constexpr (hasLabel) + if (alternative.label() == label) + ptr = &elem; + }, + elem + ); + } else { + // T != variant + if constexpr (hasLabel) + if (elem.label() == label) + ptr = &elem; + } + + if (ptr) { + if (object) { + log::warning( + "Element with label \"{}\" was already found in the vector.\n" + "Keeping the first element that was found.", + label + ); + log::member(context, nname, cname, fname, label); + } else + object = ptr; + } + } // for + + if (object) + return *object; + + log::error( + "Element with metadatum label == \"{}\" was not found in the vector" + + std::string(vec.size() ? "." : ";\nin fact the vector is empty."), + label + ); + throw std::exception{}; + + } catch (...) { + // context + log::member(context, nname, cname, fname, label); + throw; + } +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, Lookup, names...) +// ----------------------------------------------------------------------------- + +template +bool getter( + const std::vector &vec, + const Lookup &look, + const std::string &nname, const std::string &cname, const std::string &fname +) { + try { + for (auto &elem : vec) + if constexpr (isVariant::value) { + // T == variant + if (std::visit( + [&look](auto &&alternative) + { + return look.extractor(alternative) == look.object; + }, + elem + )) + return true; + } else + // T != variant + if (look.extractor(elem) == look.object) + return true; + } catch (...) { + // context + log::member( + "getter {}::{}.{}(has({}({}))) on vector", + nname, cname, fname, look.name, look.object); + throw; + } + + return false; +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, Lookup, names...) +// ----------------------------------------------------------------------------- + +template +const T &getter( + const std::vector &vec, + const Lookup &look, + const std::string &nname, const std::string &cname, const std::string &fname +) { + static const std::string context = "getter {}::{}.{}({}({})) on vector"; + + try { + const T *object = nullptr; + + for (auto &elem : vec) { + const T *ptr = nullptr; + + if constexpr (isVariant::value) { + // T == variant + std::visit( + [&elem,&look,&ptr](auto &&alternative) + { + if (look.extractor(alternative) == look.object) + ptr = &elem; + }, + elem + ); + } else { + // T != variant + if (look.extractor(elem) == look.object) + ptr = &elem; + } + + if (ptr) { + if (object) { + log::warning( + "Element with {}({}) was already found in the vector.\n" + "Keeping the first element that was found.", + look.name, look.object + ); + log::member(context, nname, cname, fname, look.name, look.object); + } else + object = ptr; + } + } // for + + if (object) + return *object; + + log::error( + "Element with metadatum {} == {} was not found in the vector" + + std::string(vec.size() ? "." : ";\nin fact the vector is empty."), + look.name, look.object + ); + throw std::exception{}; + + } catch (...) { + // context + log::member(context, nname, cname, fname, look.name, look.object); + throw; + } +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, Lookup, names...) +// ----------------------------------------------------------------------------- + +template +bool getter( + const std::vector &, + const Lookup &, + const std::string &, const std::string &, const std::string & +) { + return has_field::value; +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, Lookup, names...) +// ----------------------------------------------------------------------------- + +template +auto getter( + const std::vector &vec, + const Lookup &look, + const std::string &nname, const std::string &cname, const std::string &fname +) { + std::vector::type{})) + >> ret; + + try { + for (auto &elem : vec) { + if constexpr (isVariant::value) { + // T == variant + std::visit( + [&look,&ret](auto &&alternative) + { + ret.push_back(look.extractor(alternative)); + }, + elem + ); + } else { + // T != variant + ret.push_back(look.extractor(elem)); + } + } // for + } catch (...) { + // context + log::member( + "getter {}::{}.{}({}) on vector", + nname, cname, fname, look.name); + throw; + } + + return ret; +} + + + +// ----------------------------------------------------------------------------- +// getter(optional, index/label/Lookup, names...) +// As earlier, but for optional data member. +// ----------------------------------------------------------------------------- + +template< + class T, class KEY, + class = isSearchKey +> +decltype(auto) getter( + const std::optional> &optvec, + const KEY &key, + const std::string &nname, const std::string &cname, const std::string &fname +) { + try { + // optional must have value + if (!optvec.has_value()) { + log::error("optional vector {} does not have a value", fname); + throw std::exception{}; + } + return getter(*optvec, key, nname, cname, fname); + } catch (...) { + // context + if constexpr (isLookup::value) { + // nname::cname.fname(field(value)) + if constexpr (!KEY::Has && !KEY::Void) + log::member("getter {}::{}.{}({}({})) on optional", + nname, cname, fname, key.name, key.object); + // nname::cname.fname(has(field(value))) + if constexpr ( KEY::Has && !KEY::Void) + log::member("getter {}::{}.{}(has({}({}))) on optional", + nname, cname, fname, key.name, key.object); + // nname::cname.fname(field) + if constexpr (!KEY::Has && KEY::Void) + log::member("getter {}::{}.{}({}) on optional", + nname, cname, fname, key.name); + // nname::cname.fname(has(field)) + if constexpr ( KEY::Has && KEY::Void) + log::member("getter {}::{}.{}(has({})) on optional", + nname, cname, fname, key.name); + } else { + log::member( + std::is_convertible_v + ? "getter {}::{}.{}({}) on optional" + : "getter {}::{}.{}(\"{}\") on optional", + nname, cname, fname, key); + } + throw; + } +} + + + +// ----------------------------------------------------------------------------- +// getter(variant, names...) +// ----------------------------------------------------------------------------- + +template< + class T, class... Ts, + class = std::enable_if_t>> +> +const T *getter( + const std::variant &var, + const std::string &nname, const std::string &cname, const std::string &fname +) { + try { + return std::holds_alternative(var) + ? &std::get(var) + : nullptr; + } catch (...) { + // context + log::member("getter {}::{}.{}() on variant", nname, cname, fname); + throw; + } +} + + + +// ----------------------------------------------------------------------------- +// getter(vector, index/label/Lookup, names...) +// ----------------------------------------------------------------------------- + +template< + class T, class KEY, class... Ts, + class = isSearchKey, + class = std::enable_if_t>> +> +const T *getter( + const std::vector> &vecvar, + const KEY &key, + const std::string &nname, const std::string &cname, const std::string &fname +) { + try { + return getter( + // no , so it calls getter(generic vector); it isn't recursive + getter(vecvar, key, nname, cname, fname), // scalar variant + nname, cname, fname + ); + } catch (...) { + // context + log::member( + std::is_convertible_v + ? "getter {}::{}.{}({}) on vector" + : "getter {}::{}.{}(\"{}\") on vector", + nname, cname, fname, key); + throw; + } +} diff --git a/src/GNDStk/Component/src/detail.hpp b/src/GNDStk/Component/src/detail.hpp index 05cf4322d..5594a9bb2 100644 --- a/src/GNDStk/Component/src/detail.hpp +++ b/src/GNDStk/Component/src/detail.hpp @@ -1,37 +1,10 @@ // Forward declaration, needed by some things later -template +template class Component; - namespace detail { -// ----------------------------------------------------------------------------- -// colorize_*(text) -// ----------------------------------------------------------------------------- - -#define gndstkPaste(one,two) one ## two -#define gndstkColorFun(part) \ - inline std::string gndstkPaste(colorize_,part)(const std::string &text) \ - { \ - return GNDStk::color && colors::part != "" \ - ? colors::part + text + colors::reset \ - : text; \ - } - - // colorize_label() etc. - gndstkColorFun(label) - gndstkColorFun(colon) - gndstkColorFun(component) - gndstkColorFun(brace) - gndstkColorFun(bracket) - gndstkColorFun(comment) - -#undef gndstkColorFun -#undef gndstkPaste - - - // ----------------------------------------------------------------------------- // Functions: miscellaneous // ----------------------------------------------------------------------------- @@ -91,10 +64,10 @@ inline std::string colorize( // ------------------------ inline std::string fullName( - const std::string &nsname, - const std::string &clname + const std::string &nname, // name of namespace + const std::string &cname // name of class ) { - return (nsname == "" ? "" : nsname + "::") + clname; + return (nname == "" ? "" : nname + "::") + cname; } @@ -110,57 +83,55 @@ inline void indentString( // ------------------------ -// hasWriteOneArg -// hasWriteTwoArg +// hasPrint* // ------------------------ // These are adapted from an answer here: // https://stackoverflow.com/questions/87372 -// class +// hasPrintOneArg template -class HasWriteOneArg +class HasPrintOneArg { template< class U, std::ostream &(U::*)(std::ostream &) const > struct SFINAE {}; - template static char test(SFINAE *); + template static char test(SFINAE *); template static long test(...); public: - static const bool has = sizeof(test(0)) == sizeof(char); + static constexpr bool has = sizeof(test(0)) == sizeof(char); }; -// variable - use this +// HasPrintTwoArg template -inline constexpr bool hasWriteOneArg = HasWriteOneArg::has; - -// class -template -class HasWriteTwoArg +class HasPrintTwoArg { template< class U, std::ostream &(U::*)(std::ostream &, const int) const > struct SFINAE {}; - template static char test(SFINAE *); + template static char test(SFINAE *); template static long test(...); public: - static const bool has = sizeof(test(0)) == sizeof(char); + static constexpr bool has = sizeof(test(0)) == sizeof(char); }; -// variable - use this +// Variable templates for the above; prefer these template -inline constexpr bool hasWriteTwoArg = HasWriteTwoArg::has; +inline constexpr bool hasPrintOneArg = HasPrintOneArg::has; + +template +inline constexpr bool hasPrintTwoArg = HasPrintTwoArg::has; // ----------------------------------------------------------------------------- -// writeComponentPart +// printComponentPart // ----------------------------------------------------------------------------- // Cases: @@ -170,33 +141,33 @@ inline constexpr bool hasWriteTwoArg = HasWriteTwoArg::has; // Defaulted // std::vector -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const std::string &str, const std::string &label, const std::size_t maxlen, const std::string &color = "" ); template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const T &value, const std::string &label, const std::size_t maxlen, const std::string &color = "" ); template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const std::optional &opt, const std::string &label, const std::size_t maxlen ); template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const Defaulted &def, const std::string &label, const std::size_t maxlen ); template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const std::vector &vec, const std::string &label, const std::size_t maxlen, const std::string &color = "" @@ -207,7 +178,7 @@ bool writeComponentPart( // for string // ------------------------ -inline bool writeComponentPart( +inline bool printComponentPart( std::ostream &os, const int level, const std::string &str, const std::string &label, const std::size_t maxlen, const std::string &color @@ -243,11 +214,11 @@ inline bool writeComponentPart( // ------------------------ // helper -// is_base_of_Component +// isDerivedFromComponent // Adapted from an answer here: // https://stackoverflow.com/questions/34672441 template -class is_base_of_Component { +class isDerivedFromComponent { template static constexpr std::true_type test(Component *); static constexpr std::false_type test(...); @@ -257,18 +228,21 @@ class is_base_of_Component { }; template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const T &value, const std::string &label, const std::size_t maxlen, const std::string &color ) { - if constexpr (is_base_of_Component::value) { - // T is derived from Component, and thus inherits a write() - value.write(os,level); + if constexpr (isDerivedFromComponent::value) { + // Suppress "unused parameter" warnings + (void)value; (void)maxlen; + (void)label; (void)color; + // T is derived from Component, and thus inherits a print() + value.baseComponent().print(os,level); } else { // T is any old type, not derived from Component if constexpr (std::is_floating_point_v) { - writeComponentPart( + printComponentPart( os, level, detail::Precision< detail::PrecisionContext::metadata, @@ -281,7 +255,7 @@ bool writeComponentPart( // if the printed value has internal newlines. std::string str; convert_t{}(value,str); - writeComponentPart(os, level, str, label, maxlen, color); + printComponentPart(os, level, str, label, maxlen, color); } } return true; @@ -293,17 +267,17 @@ bool writeComponentPart( // ------------------------ template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const std::optional &opt, const std::string &label, const std::size_t maxlen ) { if (opt.has_value()) - writeComponentPart( + printComponentPart( os, level, opt.value(), label, maxlen, colors::optional ); else if (comments) - writeComponentPart( + printComponentPart( os, level, colorize_comment("// optional; has no value"), label, maxlen, colors::optional ); @@ -318,19 +292,19 @@ bool writeComponentPart( // ------------------------ template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const Defaulted &def, const std::string &label, const std::size_t maxlen ) { if (def.has_value()) { - writeComponentPart( + printComponentPart( os, level, def.value(), label, maxlen, colors::defaulted ); } else if (comments) { std::string str; convert_t{}(def.get_default(),str); - writeComponentPart( + printComponentPart( os, level, colorize_comment("// defaulted; is its default (" + str + ")"), label, maxlen, colors::defaulted @@ -351,7 +325,7 @@ bool writeComponentPart( // ... // ] template -bool writeComponentPart( +bool printComponentPart( std::ostream &os, const int level, const std::vector &vec, const std::string &label, const std::size_t maxlen, const std::string &color @@ -368,7 +342,7 @@ bool writeComponentPart( ); for (auto &value : vec) { - writeComponentPart(os, level+1, value, "", 0); + printComponentPart(os, level+1, value, "", 0); os << '\n'; // between elements } @@ -382,330 +356,13 @@ bool writeComponentPart( -// ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // getter() // Various cases. // Intended for use in our auto-generated Standard Interface classes. // ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// getter(vector, index, ...) -// Index into vector data member of class. -// ----------------------------------------------------------------------------- - -// const -template -const T &getter( - const std::vector &vec, - const std::size_t index, - const std::string &nsname, // enclosing class' namespace - const std::string &clname, // enclosing class - const std::string &field // enclosing class' field we're accessing -) { - static const std::string context = "getter {}::{}.{}({}) on vector"; - - try { - // todo Make this more efficient, e.g. by assuming that the vector's - // elements are sorted by index, so that the wanted value is likely - // to be found at [index]. - - const T *selected = nullptr; - - for (auto &v : vec) { - const T *ptr = nullptr; - - if constexpr (isVariant::value) { - // T == variant - std::visit( - [&v,&index,&ptr](auto &&alternative) - { - if constexpr (hasIndex) - if (alternative.index() == index) - ptr = &v; - }, - v - ); - } else { - // T != variant - if constexpr (hasIndex) - if (v.index() == index) - ptr = &v; - } - - if (!ptr) - continue; - - if (selected) { - log::warning( - "Element with index {} was already found in the vector.\n" - "Keeping the first element that was found.", - index - ); - log::member(context, nsname, clname, field, index); - } else - selected = ptr; - } // for - - if (!selected) { - log::error( - "Element with index {} was not found in the vector" + - std::string(vec.size() ? "." : ";\nin fact the vector is empty."), - index - ); - throw std::exception{}; - } - - return *selected; - } catch (...) { - // context - // Example: prints "getter containers::Axes.axis(100)" - log::member(context, nsname, clname, field, index); - throw; - } -} - -// non-const -template -T &getter( - std::vector &vec, - const std::size_t index, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - return const_cast( - getter(std::as_const(vec), index, nsname, clname, field) - ); -} - - - -// ----------------------------------------------------------------------------- -// getter(vector, label, ...) -// Element of the vector that has .label() == label. -// Assumes that the element type has a .label() getter. -// ----------------------------------------------------------------------------- - -// const -template -const T &getter( - const std::vector &vec, - const std::string &label, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - static const std::string context = "getter {}::{}.{}(\"{}\") on vector"; - - try { - const T *selected = nullptr; - - for (auto &v : vec) { - const T *ptr = nullptr; - - if constexpr (isVariant::value) { - // T == variant - std::visit( - [&v,&label,&ptr](auto &&alternative) - { - if constexpr (hasLabel) - if (alternative.label() == label) - ptr = &v; - }, - v - ); - } else { - // T != variant - if constexpr (hasLabel) - if (v.label() == label) - ptr = &v; - } - - if (!ptr) - continue; - - if (selected) { - log::warning( - "Element with label \"{}\" was already found in the vector.\n" - "Keeping the first element that was found.", - label - ); - log::member(context, nsname, clname, field, label); - } else - selected = ptr; - } // for - - if (!selected) { - log::error( - "Element with label \"{}\" was not found in the vector" + - std::string(vec.size() ? "." : ";\nin fact the vector is empty."), - label - ); - throw std::exception{}; - } - - return *selected; - - } catch (...) { - // context - log::member(context, nsname, clname, field, label); - throw; - } -} - -// non-const -template -T &getter( - std::vector &vec, - const std::string &label, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - return const_cast( - getter(std::as_const(vec), label, nsname, clname, field) - ); -} - - - -// ----------------------------------------------------------------------------- -// getter(optional, index or label, ...) -// As earlier, but for optional data member. -// ----------------------------------------------------------------------------- - -// const -template< - class T, class LOOKUP, - class = std::enable_if_t< - std::is_convertible_v || - std::is_convertible_v - > -> -const T &getter( - const std::optional> &opt, - const LOOKUP &index_or_label, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - try { - // optional must have value - if (!opt.has_value()) { - log::error("optional vector {} does not have a value", field); - throw std::exception{}; - } - return getter((*opt), index_or_label, nsname, clname, field); - } catch (...) { - // context - log::member( - std::is_convertible_v - ? "getter {}::{}.{}({}) on optional" - : "getter {}::{}.{}(\"{}\") on optional", - nsname, clname, field, index_or_label); - throw; - } -} - -// non-const -template< - class T, class LOOKUP, - class = std::enable_if_t< - std::is_convertible_v || - std::is_convertible_v - > -> -T &getter( - std::optional> &opt, - const LOOKUP &index_or_label, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - return const_cast( - getter(std::as_const(opt), index_or_label, nsname, clname, field) - ); -} - - - -// ----------------------------------------------------------------------------- -// getter(...) -// With caller-specified type, when variant is involved -// ----------------------------------------------------------------------------- - -// ------------------------ -// variant,... -// ------------------------ - -template< - class T, - class... Ts, - class = std::enable_if_t>> -> -const T *getter( - const std::variant &var, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - try { - return std::holds_alternative(var) - ? &std::get(var) - : nullptr; - } catch (...) { - // context - log::member( - "getter {}::{}.{}() on variant", - nsname, clname, field); - throw; - } -} - - -// ------------------------ -// vector, -// index or label, -// ... -// ------------------------ - -// The (size_t index) and (string label) cases were similar enough that -// we were able to combine them into one function. - -template< - class T, class LOOKUP, - class = std::enable_if_t< - std::is_convertible_v || - std::is_convertible_v - >, - class... Ts -> -const T *getter( - const std::vector> &vec, - const LOOKUP &index_or_label, - const std::string &nsname, - const std::string &clname, - const std::string &field -) { - try { - return getter( - // no , so it calls getter(generic vector); it isn't recursive - getter(vec, index_or_label, nsname, clname, field), // scalar variant - nsname, clname, field - ); - } catch (...) { - // context - log::member( - std::is_convertible_v - ? "getter {}::{}.{}({}) on vector" - : "getter {}::{}.{}(\"{}\") on vector", - nsname, clname, field, index_or_label); - throw; - } -} +#include "GNDStk/Component/src/detail-getter.hpp" @@ -713,7 +370,7 @@ const T *getter( // For sorting derived-class fields based on index and label, if and when one // or the other of those is determined to be present. That determination hinges // on both a compile-time check that the classes involved even *have* index or -// label fields in their content struct, and if they do, if either of those is +// label fields in their Content struct, and if they do, if either of those is // possibly a std::optional that may or may not contain a value at the moment. // ----------------------------------------------------------------------------- @@ -731,46 +388,46 @@ bool compareRegular(const A &a, const B &b) // index? std::size_t aindex = 0; bool ahasindex = false; if constexpr (hasIndex) { - if constexpr (isOptional) { - if ((ahasindex = a.content.index.has_value())) - aindex = a.content.index.value(); + if constexpr (isOptional) { + if ((ahasindex = a.index().has_value())) + aindex = a.index().value(); } else { ahasindex = true; - aindex = a.content.index; + aindex = a.index(); } } std::size_t bindex = 0; bool bhasindex = false; if constexpr (hasIndex) { - if constexpr (isOptional) { - if ((bhasindex = b.content.index.has_value())) - bindex = b.content.index.value(); + if constexpr (isOptional) { + if ((bhasindex = b.index().has_value())) + bindex = b.index().value(); } else { bhasindex = true; - bindex = b.content.index; + bindex = b.index(); } } // label? std::string alabel = ""; bool ahaslabel = false; if constexpr (hasLabel) { - if constexpr (isOptional) { - if ((ahaslabel = a.content.label.has_value())) - alabel = a.content.label.value(); + if constexpr (isOptional) { + if ((ahaslabel = a.label().has_value())) + alabel = a.label().value(); } else { ahaslabel = true; - alabel = a.content.label; + alabel = a.label(); } } std::string blabel = ""; bool bhaslabel = false; if constexpr (hasLabel) { - if constexpr (isOptional) { - if ((bhaslabel = b.content.label.has_value())) - blabel = b.content.label.value(); + if constexpr (isOptional) { + if ((bhaslabel = b.label().has_value())) + blabel = b.label().value(); } else { bhaslabel = true; - blabel = b.content.label; + blabel = b.label(); } } diff --git a/src/GNDStk/Component/src/finish.hpp b/src/GNDStk/Component/src/finish.hpp index 864f5d5bf..e4376f74f 100644 --- a/src/GNDStk/Component/src/finish.hpp +++ b/src/GNDStk/Component/src/finish.hpp @@ -32,8 +32,8 @@ thus can, but does not need to, provide a construct(). Arguments are received where (1) the derived-class constructor receives the argument, but (2) the argument is transitory - it's used in the constructor, -but it doesn't go into the autogenerated "content" struct in the derived class. -(If it did go into the content struct then we'd simply extract it from there, +but it doesn't go into the autogenerated Content struct in the derived class. +(If it did go into the Content struct then we'd simply extract it from there, instead of having finish() receive it as a parameter.) Specifically, the constructors in the auto-generated classes call: @@ -48,11 +48,11 @@ Specifically, the constructors in the auto-generated classes call: Constructor from a Node: Component::finish(the Node) - Constructors involving a vector of "body text" data: + Constructors involving a vector of block data: Component::finish(the vector) Note: In the last case, we're speaking of a vector that's specifically for -body text, not a vector that might be there for a different reason. +block data, not a vector that might be there for a different reason. */ @@ -73,7 +73,7 @@ void construct(const Node &) { } // return void. We use bool, here, for technical reasons, relating to the test // used in the template finish() function (as opposed to the non-template cases) // to determine whether or not someone has provided a custom construct(). -template>> +template>> bool construct(const std::vector &) { return true; } @@ -88,13 +88,13 @@ bool construct(const std::vector &) { return true; } void finish() { - // If hasBodyText == true (else no-op), have Component's BodyText base + // If hasBlockData == true (else no-op), have Component's BlockData base // get length, start, and valueType, as available, from the derived class - if constexpr (hasBodyText) - body::pullFromDerived(derived()); + if constexpr (hasBlockData) + BLOCKDATA::pullFromDerived(derived()); - // Based on the derived class' keys(), locate and sort derived-class fields - // that are vectors, with vector elements that have index and/or label. + // Automatically locate and sort derived-class fields that are vectors + // with elements that have index and/or label. sort(); // construct @@ -109,8 +109,8 @@ void finish() void finish(const DERIVED &other) { // length, start, valueType - if constexpr (hasBodyText) - body::pullFromDerived(derived()); + if constexpr (hasBlockData) + BLOCKDATA::pullFromDerived(derived()); // derived-class vector fields sort(); @@ -131,16 +131,16 @@ void finish(const DERIVED &other) void finish(const Node &node) { - // Read fields from the Node into the derived object. This applies the keys() - // multi-query in the derived class, and also runs BodyText::fromNode() if - // the Node has body text, in order to get the Node's string of "body text". + // Read fields from the Node into the derived object. This applies the KEYS() + // multi-query in the derived class, and also runs BlockData::fromNode() - if + // the Node has block data - in order to get the Node's string of block data. fromNode(node); - if constexpr (hasBodyText) { + if constexpr (hasBlockData) { // length, start, valueType - body::pullFromDerived(derived()); + BLOCKDATA::pullFromDerived(derived()); // make vector - body::get(); + BLOCKDATA::get(); } // derived-class vector fields @@ -160,15 +160,15 @@ void finish(const Node &node) // finish(vector) // ------------------------ -template>> +template>> void finish(const std::vector &vector) { // assign from the vector - body::operator=(vector); + BLOCKDATA::operator=(vector); // length, start, valueType: push back up to derived, // as they would have been computed above in operator=. - body::pushToDerived(derived()); + BLOCKDATA::pushToDerived(derived()); // derived-class vector fields sort(); diff --git a/src/GNDStk/Component/src/fromNode.hpp b/src/GNDStk/Component/src/fromNode.hpp index f7760b4ca..097350208 100644 --- a/src/GNDStk/Component/src/fromNode.hpp +++ b/src/GNDStk/Component/src/fromNode.hpp @@ -21,41 +21,36 @@ void fromNode(const Node &node) { try { // does the node have the name we expect? - if (node.name != DERIVED::GNDSName()) { + if (node.name != DERIVED::FIELD()) { log::error( "Name \"{}\" in Node sent to Component::fromNode() is not the " "expected GNDS name \"{}\"", - node.name, DERIVED::GNDSName() + node.name, DERIVED::FIELD() ); throw std::exception{}; } - if constexpr (std::is_same_v>) { - // consistency check; then nothing further to do - assert(0 == links.size()); - } else { - // retrieve the node's data by doing a multi-query - const auto tup = node(toKeywordTup(DERIVED::keys())); - - // consistency check - assert(std::tuple_size::value == links.size()); - - // apply links: - // Node ==> derived-class data - // Below, each apply'd "result" is one particular element - one - // retrieved value - from the above multi-query on the node. - std::apply( - [this](const auto &... result) { - std::size_t n = 0; - ((*(std::decay_t *)links[n++] = result), ...); - }, - tup - ); - } - - // body text, a.k.a. XML "pcdata" (plain character data), if any - if constexpr (hasBodyText) - body::fromNode(node); + // retrieve the node's data by doing a multi-query + const auto tuple = node(Keys()); + + // consistency check + assert(std::tuple_size::value == links.size()); + + // apply links: + // Node ==> derived-class data + // Below, each apply'd "result" is one particular element - one + // retrieved value - from the above multi-query on the node. + std::apply( + [this](const auto &... result) { + std::size_t n = 0; + ((*(std::decay_t *)links[n++] = result), ...); + }, + tuple + ); + + // block data, a.k.a. XML "pcdata" (plain character data), if any + if constexpr (hasBlockData) + BLOCKDATA::fromNode(node); } catch (...) { log::member("Component.fromNode(Node(\"{}\"))", node.name); diff --git a/src/GNDStk/Component/src/getter.hpp b/src/GNDStk/Component/src/getter.hpp index 1f8228830..38dbca732 100644 --- a/src/GNDStk/Component/src/getter.hpp +++ b/src/GNDStk/Component/src/getter.hpp @@ -1,117 +1,132 @@ +// ----------------------------------------------------------------------------- +// Component::getter() +// ----------------------------------------------------------------------------- + // The getter() functions of class Component get some names from the derived -// class (those are used when printing diagnostics, if applicable), and then +// class (which are used when printing diagnostics, if applicable), and then // call getter() functions in the detail:: namespace to do most of the work. // // The motivation for having the following at all is to simplify the retrieval, -// in the derived-class getters, of certain information in the content{} struct +// in the derived-class getters, of certain information in the Content{} struct // of the derived class object. For simple data, e.g. an int or a std::string -// in the derived class' content struct, a derived-class getter will simply -// do a "return content.something", because nothing more complicated is needed. +// in the derived class' Content struct, a derived-class getter will simply +// do a "return Content.something", because nothing more complicated is needed. // So, the below functions involve circumstances where something more involved -// needs to be done. See the various remarks below for more information. +// needs to be done. // ----------------------------------------------------------------------------- -// (field, key, name) -// FIELD in this context is either a vector or an optional, and KEY -// is either an integral index or a string label. (If FIELD were just a plain -// data type, not an [optional] vector, then there would be no reason to bother -// with a getter() function for it; we'd just return content.field in the -// derived class, instead of calling getter() to do something more complicated. -// And, besides, the fact that we're looking up by index or label suggests that -// we're dealing with a vector, not something simple like an int or a string.) +// getter(vec, key, name) // ----------------------------------------------------------------------------- // const -template // KEY: for index or label -const auto &getter( - const FIELD &field, - const KEY &key, +template< + class VEC, class KEY, + class = detail::isSearchKey +> +decltype(auto) getter( + const VEC &vec, // vector, or optional vector + const KEY &key, // index, label, or Lookup const std::string &fieldName ) const { return detail::getter( - field, key, - DERIVED::namespaceName(), DERIVED::className(), fieldName + vec, key, DERIVED::NAMESPACE(), DERIVED::CLASS(), fieldName ); } // non-const -template -auto &getter( - FIELD &field, +template< + class VEC, class KEY, + class = detail::isSearchKey +> +decltype(auto) getter( + VEC &vec, const KEY &key, const std::string &fieldName ) { - return detail::getter( - field, key, - DERIVED::namespaceName(), DERIVED::className(), fieldName - ); + using RET = decltype( + std::as_const(*this).template getter(vec, key, fieldName)); + + if constexpr (std::is_reference_v) + return const_cast &>( + std::as_const(*this).template getter(vec, key, fieldName)); + else + return std::as_const(*this).template getter(vec, key, fieldName); } // ----------------------------------------------------------------------------- -// (variant, name) +// getter(variant, name) // These, in contrast to the getter()s above, don't involve a vector or an -// optional vector, or an index or a label. We bother having these only because -// of the (admittedly small, in this case) extra complexity of checking that -// the variant holds the requested alternative, and of producing diagnostics -// if it doesn't. +// optional vector. We bother having these only because of the (admittedly +// small, in this case) extra complexity of checking that the variant holds +// the requested alternative, and of producing diagnostics if it doesn't. // ----------------------------------------------------------------------------- // const -template +template< + class RETURN, class... Ts, + class = std::enable_if_t>> +> const RETURN *getter( const std::variant &var, const std::string &fieldName ) const { return detail::getter( - var, - DERIVED::namespaceName(), DERIVED::className(), fieldName + var, DERIVED::NAMESPACE(), DERIVED::CLASS(), fieldName ); } // non-const -template +template< + class RETURN, class... Ts, + class = std::enable_if_t>> +> RETURN *getter( std::variant &var, const std::string &fieldName ) { return const_cast( - std::as_const(*this).template - getter(std::as_const(var), fieldName) + std::as_const(*this).template getter(var, fieldName) ); } // ----------------------------------------------------------------------------- -// (vector, key, name) +// getter(vector, key, name) // The motivation for these essentially amounts to the combined motivations // for the above two sets of getter() functions. // ----------------------------------------------------------------------------- // const -template +template< + class RETURN, class KEY, class... Ts, + class = detail::isSearchKey, + class = std::enable_if_t>> +> const RETURN *getter( - const std::vector> &var, + const std::vector> &vecvar, const KEY &key, const std::string &fieldName ) const { return detail::getter( - var, key, - DERIVED::namespaceName(), DERIVED::className(), fieldName + vecvar, key, DERIVED::NAMESPACE(), DERIVED::CLASS(), fieldName ); } // non-const -template +template< + class RETURN, class KEY, class... Ts, + class = detail::isSearchKey, + class = std::enable_if_t>> +> RETURN *getter( - std::vector> &var, + std::vector> &vecvar, const KEY &key, const std::string &fieldName -) const { +) { return const_cast( - std::as_const(*this).template - getter(std::as_const(var), key, fieldName) + std::as_const(*this).template getter(vecvar, key, fieldName) ); } diff --git a/src/GNDStk/Component/src/print.hpp b/src/GNDStk/Component/src/print.hpp new file mode 100644 index 000000000..40e17a70f --- /dev/null +++ b/src/GNDStk/Component/src/print.hpp @@ -0,0 +1,209 @@ + +// ----------------------------------------------------------------------------- +// REMARK +// Regarding "write" vs. "print", and newlines +// ----------------------------------------------------------------------------- + +/* +Python has print(), and we anticipate having many Python-aware users. First and +foremost, this is why we provide these print() functions. + +Elsewhere, we've given Component a set of write() (not print()) functions that +mirror Node's functions of the same name. These first make use of Component's +ability to convert objects of its derived classes to Node, then they call Node's +write() functions. Node's write() functions can do a number of things, such as +writing to XML, or to GNDStk's debug format. + +Someone who wishes to print the contents of a Component-derived class may prefer +to see our print() function's "prettyprinting" output. Not XML, not our internal +debug format, not the various other things that the write() functions can do. + +The name print(), then, not only aligns with what a Python user might expect, +but also reflects the difference from its - really, Node's - write() functions. +Note, in particular, that write() (called with no argument) behaves as it does +for Node, while print() (called with no argument) does something completely +different: prettyprint to standard output. + +Our no-argument print() functions also print a newline at the end - which, when +prettyprinting, a user probably expects. + +The write() functions, being arguably more "low level", don't emit that newline, +and shouldn't. Just as C++ doesn't automatically print something basic (an int, +for example, or a floating-point number) with a newline, neither should a well- +mannered system for writing class objects. Whether a newline is really wanted, +or not, depends on context. + +If you write std::cout << 1.23 << std::endl, you expect one line, with "1.23", +followed by a newline via std::endl, then the cursor ready at the beginning of +the very next line. Write std::cout << obj << std::endl, where obj is of some +user-defined type whose stream output operator already prints its own newline, +and the cursor will end up *two* lines down, after an intervening blank line. +It may seem convenient for "large" objects to print with their own newline, but +doing so creates inconsistent behavior between them and more-basic object types. +Inconsistencies beget unpredictability. + +Moreover, Component-derived classes often contain instances of other Component- +derived classes. An enclosing object should place its own newlines - only where +appropriate, and not where not appropriate - between its constituent parts. If +those parts did their own thing in this respect, they'd stymie the ability of +the enclosing class to do the right thing. +*/ + + +// ----------------------------------------------------------------------------- +// print(ostream,level) +// Low-level version, possibly building on other Component-derived objects. +// Doesn't print the trailing newline. +// ----------------------------------------------------------------------------- + +std::ostream &print(std::ostream &os, const int level) const +{ + try { + // Indent, header, newline + detail::indentString( + os, level, + detail::colorize_component( + detail::fullName(DERIVED::NAMESPACE(), DERIVED::CLASS()) + ) + " " + + detail::colorize_brace("{") + "\n" + ); + + // Consistency check + assert(std::tuple_size::value == links.size()); + + // Compute maximum length of key names, if aligning. Note that we + // could - but don't - take into account that keys associated with + // optional or Defaulted values *might* not in fact show up in the + // final printed text. In such cases, and if values of those types + // happen to have longer names, then the printing that does appear + // might use more spacing than it really needs to. By choosing not + // to factor this in, on a case-by-case basis, all objects of this + // particular Component<...> type will print with consistent spacing. + // We prefer this behavior, and its code is also slightly simpler. + std::size_t maxlen = 0; + if (GNDStk::align) + std::apply( + [&maxlen](const auto &... key) { + ((maxlen=std::max(maxlen,detail::getName(key).size())), ...); + }, + Keys().tup + ); + + // Apply links: + // derived-class data ==> print + std::apply( + [this,&os,&level,maxlen](const auto &... key) { + std::size_t n = 0; + ( + ( + // indent, value, newline + detail::printComponentPart( + os, + level+1, + *(std::decay_t *)links[n++], + detail::getName(key), + maxlen + ) && (os << '\n') // no if()s in fold expressions :-/ + ), + ... + ); + }, + Keys().tup + ); + + // Custom derived-class print()s, if any. + // To be recognized here, derived-class print() functions must be public, + // and have signatures that are *exactly* as we expect, including their + // constness. + if constexpr (detail::hasPrintTwoArg) { + // Derived class has: + // std::ostream &print(std::ostream &os, const int level) const; + // and handles indentation level in its own way; we won't here. + std::ostringstream tmp; + derived().print(tmp,level+1); + const std::string &str = tmp.str(); + + std::size_t size = str.size(); + if (size) { + // expect that customizations may have spurious newlines :-/ + if (str[size-1] == '\n') size--; + for (std::size_t i = 0; i < size; ++i) + os << str[i]; + std::cout << std::endl; + } + } else if constexpr (detail::hasPrintOneArg) { + // Derived class has: + // std::ostream &print(std::ostream &os) const; + // and we'll detect newlines and handle indentation automatically. + std::ostringstream tmp; + derived().print(tmp); + const std::string &str = tmp.str(); + + std::size_t size = str.size(); + if (size) { + // remark as above + if (str[size-1] == '\n') size--; + if (size) + os << indentTo(level+1); + for (std::size_t i = 0; i < size; ++i) + os << str[i] << (str[i] == '\n' ? indentTo(level+1) : ""); + std::cout << std::endl; + } + } + + // BlockData, if any + if constexpr (hasBlockData) + BLOCKDATA::print(os,level+1); + + // Indent, footer, NO trailing newline + detail::indentString( + os, level, + detail::colorize_brace("}") + + (comments + ? " " + + detail::colorize_comment( + std::string("// ") + + detail::fullName( + DERIVED::NAMESPACE(), + DERIVED::CLASS() + ) + ) + : "" + ) + ); + + return os; + + } catch (...) { + log::member("Component.print()"); + throw; + } +} + + +// ----------------------------------------------------------------------------- +// print +// print(ostream) +// Print trailing newlines. +// ----------------------------------------------------------------------------- + +// We'll give these const and non-const versions (one would normally expect only +// const versions of print functions), and with a "builder pattern" that mirrors +// that of the setters that GNDStk's code generator gives its generated classes. +// This way, someone can prettyprint an object while it's being built, builder +// style. Some users may find this to be useful for visualizing what's happening +// as they create an object. + +// const +const DERIVED &print(std::ostream &os = std::cout) const +{ + print(os,0) << std::endl; + return *static_cast(this); +} + +// non-const +DERIVED &print(std::ostream &os = std::cout) +{ + print(os,0) << std::endl; + return *static_cast(this); +} diff --git a/src/GNDStk/Component/src/read.hpp b/src/GNDStk/Component/src/read.hpp new file mode 100644 index 000000000..fa9c94c8b --- /dev/null +++ b/src/GNDStk/Component/src/read.hpp @@ -0,0 +1,54 @@ + +// ----------------------------------------------------------------------------- +// Component::read() +// Via Node, and using Node's available read() functions. +// So, autogenerated classes can directly use .read(...). +// ----------------------------------------------------------------------------- + +// read(istream, FileType) +std::istream &read( + std::istream &is, + const FileType format = FileType::guess, + const bool decl = false +) { + Node node; + std::istream &ret = node.read(is, format, decl); + derived() = DERIVED(node); + return ret; +} + +// read(file, FileType) +bool read( + const std::string &filename, + const FileType format = FileType::guess, + const bool decl = false +) { + Node node; + bool ret = node.read(filename, format, decl); + derived() = DERIVED(node); + return ret; +} + +// read(istream, string) +std::istream &read( + std::istream &is, + const std::string &format, + const bool decl = false +) { + Node node; + std::istream &ret = node.read(is, format, decl); + derived() = DERIVED(node); + return ret; +} + +// read(file, string) +bool read( + const std::string &filename, + const std::string &format, + const bool decl = false +) { + Node node; + bool ret = node.read(filename, format, decl); + derived() = DERIVED(node); + return ret; +} diff --git a/src/GNDStk/Component/src/setter.hpp b/src/GNDStk/Component/src/setter.hpp new file mode 100644 index 000000000..58b4a1e96 --- /dev/null +++ b/src/GNDStk/Component/src/setter.hpp @@ -0,0 +1,29 @@ + +// Like getter.hpp, but to help with *setters* in Component-derived classes. + +// push_back a value into the vector. +template< + class T, class FROM, + class = std::enable_if_t< + std::is_constructible_v || std::is_convertible_v + > +> +void setter(std::vector &vec, const FROM &value) +{ + vec.push_back(value); +} + +// Create an empty vector in the optional if it has no value, then +// push_back a value into the vector. +template< + class T, class FROM, + class = std::enable_if_t< + std::is_constructible_v || std::is_convertible_v + > +> +void setter(std::optional> &opt, const FROM &value) +{ + if (!opt.has_value()) + opt = std::vector{}; + opt->push_back(value); +} diff --git a/src/GNDStk/Component/src/sort.hpp b/src/GNDStk/Component/src/sort.hpp index 68dd7b309..88c4d1ba7 100644 --- a/src/GNDStk/Component/src/sort.hpp +++ b/src/GNDStk/Component/src/sort.hpp @@ -6,30 +6,20 @@ void sort() { try { - if constexpr (std::is_same_v>) { - // Consistency check; then nothing further to do - assert(0 == links.size()); - } else { - // Make tuple (of individual keys) from DERIVED::keys() - const auto tup = toKeywordTup(DERIVED::keys()).tup; + // Consistency check + assert(std::tuple_size::value == links.size()); - // Consistency check - assert(std::tuple_size::value == links.size()); - - // Apply links - std::apply( - [this](const auto &... key) { - std::size_t n = 0; - ( - detail::sort( - *(std::decay_t *)links[n++] - ), - ... - ); - }, - tup - ); - } + // Apply links + std::apply( + [this](const auto &... key) { + std::size_t n = 0; + ( + detail::sort(*(std::decay_t *)links[n++]), + ... + ); + }, + Keys().tup + ); } catch (...) { log::member("Component.sort()"); throw; diff --git a/src/GNDStk/Component/src/toNode.hpp b/src/GNDStk/Component/src/toNode.hpp index 52c291d5b..83fcc306b 100644 --- a/src/GNDStk/Component/src/toNode.hpp +++ b/src/GNDStk/Component/src/toNode.hpp @@ -1,43 +1,60 @@ // ----------------------------------------------------------------------------- // Component -// conversion to Node +// Conversion to Node. // ----------------------------------------------------------------------------- -// Normally we'd need just a const version of a conversion operator, and, if -// we needed a non-const version at all, it could build on the const version. -// A glitch in the present circumstances is that BodyText::toNode(), which is -// called from within these, splits const and non-const cases, and that needs -// to be preserved here. So, then, why does BodyText::toNode() have a non-const -// version? The issue is that in the non-const case, BodyText::toNode() may -// need to deal with a vector (not just an original "body text" string as may -// have been read into a const BodyText). And, dealing with a vector means -// computing a proper length, start, and valueType while doing toNode() - and -// pushing those up to the class derived from Component, as it's from that -// class that those fields are written to the Node. The need to compute proper -// values for those parameters is why we need the non-const case. (And we can't -// just make length etc. mutable in BodyText, as the length etc. in the derived -// class come into play too.) Maybe we'll work out a different way to handle -// all this, but for now, we have the following. - -// const operator Node() const { + // Initialize a Node, with the necessary name + Node node(DERIVED::FIELD()); + try { - #include "GNDStk/Component/src/toNodeBody.hpp" + // Handle block data, if applicable + if constexpr (hasBlockData) { + // GNDStk uses a TEXT metadatum of a PCDATA child node for this + std::string &text = + node.add(special::pcdata).add(special::text,"").second; + BLOCKDATA::toNode(text); + } + + // Write fields... + + // consistency check + assert(std::tuple_size::value == links.size()); + + // apply links: + // derived-class data ==> Node + // Below, each apply'd "key" is one value from DERIVED::KEYS(), and + // is a Meta, Child, or pair. The cast gives the + // underlying raw data type - int, say, or std::string - so that we + // can correctly use our generic void* link to a derived-class field. + std::apply( + [this,&node](const auto &... key) { + std::size_t n = 0; + (node.add(key,*(std::decay_t*)links[n++]), + ...); + }, + Keys().tup + ); } catch (...) { log::member("Component.operator Node() const"); throw; } + + return node; } -// non-const -operator Node() + +// ----------------------------------------------------------------------------- +// Component +// Conversion to Tree. +// Like conversion to Node, but with a proper root Node. +// ----------------------------------------------------------------------------- + +operator Tree() const { - try { - #include "GNDStk/Component/src/toNodeBody.hpp" - } catch (...) { - log::member("Component.operator Node()"); - throw; - } + Tree tree; + tree.add(Node(*this)); + return tree; } diff --git a/src/GNDStk/Component/src/toNodeBody.hpp b/src/GNDStk/Component/src/toNodeBody.hpp deleted file mode 100644 index a5182a737..000000000 --- a/src/GNDStk/Component/src/toNodeBody.hpp +++ /dev/null @@ -1,40 +0,0 @@ - -// 1. Initialize a Node, with the necessary name -Node node(DERIVED::GNDSName()); - -// 2. Body text, if applicable -if constexpr (hasBodyText) { - // GNDStk uses a "text" metadatum of a "pcdata" child node for this - std::string &text = node.add("pcdata").add("text","").second; - // Note: the following call might compute length, start, and valueType; - // so we need all of this before the upcoming writing of fields. - body::toNode(text,derived().content); -} - -// 3. Write fields -if constexpr (std::is_same_v>) { - // consistency check - assert(0 == links.size()); -} else { - // make tuple (of individual keys) from DERIVED::keys() - const auto tup = toKeywordTup(DERIVED::keys()).tup; - - // consistency check - assert(std::tuple_size::value == links.size()); - - // apply links: - // derived-class data ==> Node - // Below, each apply'd "key" is one value from DERIVED::keys(), and - // is a Meta, Child, or pair. The cast gives the - // underlying raw data type - int, say, or std::string - so that we - // can correctly use our generic void* link to a derived-class field. - std::apply( - [this,&node](const auto &... key) { - std::size_t n = 0; - (node.add(key,*(std::decay_t*)links[n++]), ...); - }, - tup - ); -} - -return node; diff --git a/src/GNDStk/Component/src/write.hpp b/src/GNDStk/Component/src/write.hpp index a2a8507bb..49cdcad8e 100644 --- a/src/GNDStk/Component/src/write.hpp +++ b/src/GNDStk/Component/src/write.hpp @@ -1,126 +1,42 @@ // ----------------------------------------------------------------------------- // Component::write() +// Via Node, and using Node's write()s. +// So, Component-derived classes can use .write(...) directly. // ----------------------------------------------------------------------------- -std::ostream &write(std::ostream &os = std::cout, const int level = 0) const -{ - try { - // Indent, write header, newline - detail::indentString( - os, level, - detail::colorize_component( - detail::fullName(DERIVED::namespaceName(), DERIVED::className()) - ) + " " + - detail::colorize_brace("{") + - (comments - ? " " + - detail::colorize_comment( - std::string("// GNDS: ") + DERIVED::GNDSName() - ) - : "" - ) + "\n" - ); - - if constexpr (std::is_same_v>) { - // Consistency check - assert(0 == links.size()); - } else { - // Make tuple (of individual keys) from DERIVED::keys() - const auto tup = toKeywordTup(DERIVED::keys()).tup; - - // Consistency check - assert(std::tuple_size::value == links.size()); - - // Compute maximum length of key names, if aligning. Note that we - // could - but don't - take into account that keys associated with - // optional or Defaulted values *might* not in fact show up in the - // final printed text. In such cases, and if values of those types - // happen to have longer names, then the printing that does appear - // might use more spacing than it really needs to. By choosing not - // to factor this in, on a case-by-case basis, all objects of this - // particular Component<...> type will print with consistent spacing. - // We prefer this behavior, and it's also slightly simpler to write. - std::size_t maxlen = 0; - if (GNDStk::align) - std::apply( - [&maxlen](const auto &... key) { - ((maxlen=std::max(maxlen,detail::getName(key).size())), ...); - }, - tup - ); - - // Apply links: - // derived-class data ==> print - std::apply( - [this,&os,&level,maxlen](const auto &... key) { - std::size_t n = 0; - ( - ( - // indent, write internal value, newline - detail::writeComponentPart( - os, - level+1, - *(std::decay_t *)links[n++], - detail::getName(key), - maxlen - ) && (os << '\n') // no if()s in fold expressions :-/ - ), - ... - ); - }, - tup - ); - } - - // Derived class write()s, if any. - // Note that neither, either, or both can be provided. - // To be recognized here, signatures must be exactly what we expect. - if constexpr (detail::hasWriteOneArg) { - // DERIVED::write() doesn't take an indentation level; we handle here - std::ostringstream tmp; - derived().write(tmp); - if (tmp.str().size() != 0) - os << indentTo(level+1); - for (char c : tmp.str()) - os << c << (c == '\n' ? indentTo(level+1) : ""); - if (tmp.str().size()) - os << std::endl; - } - if constexpr (detail::hasWriteTwoArg) { - // DERIVED::write() takes an indentation level - std::ostringstream tmp; - derived().write(tmp,level+1); - os << tmp.str(); - if (tmp.str().size()) - os << std::endl; - } - - // BodyText, if any - if constexpr (hasBodyText) - body::write(os,level+1); +// write(ostream, FileType) +std::ostream &write( + std::ostream &os = std::cout, + const FileType format = FileType::guess, + const bool decl = false +) const { + return Node(*this).write(os, format, decl); +} - // Indent, write footer, NO newline - detail::indentString( - os, level, - detail::colorize_brace("}") - + (comments - ? " " + - detail::colorize_comment( - std::string("// ") + - detail::fullName( - DERIVED::namespaceName(), - DERIVED::className() - ) - ) - : "" - ) - ); +// write(file, FileType) +bool write( + const std::string &filename, + const FileType format = FileType::guess, + const bool decl = false +) const { + return Node(*this).write(filename, format, decl); +} - return os; +// write(ostream, string) +std::ostream &write( + std::ostream &os, + const std::string &format, + const bool decl = false +) const { + return Node(*this).write(os, format, decl); +} - } catch (...) { - log::member("Component.write()"); - throw; - } +// write(file, string) +bool write( + const std::string &filename, + const std::string &format, + const bool decl = false +) const { + return Node(*this).write(filename, format, decl); } diff --git a/src/GNDStk/Component/test/CMakeLists.txt b/src/GNDStk/Component/test/CMakeLists.txt index a81b982ff..178fbe81a 100644 --- a/src/GNDStk/Component/test/CMakeLists.txt +++ b/src/GNDStk/Component/test/CMakeLists.txt @@ -7,7 +7,7 @@ add_executable( GNDStk.Component.test fromNode.test.cpp getter.test.cpp toNode.test.cpp - write.test.cpp ) + print.test.cpp ) target_compile_options( GNDStk.Component.test PRIVATE ${${PREFIX}_common_flags} $<$:${${PREFIX}_strict_flags}>$<$: ${${PREFIX}_DEBUG_flags} diff --git a/src/GNDStk/Component/test/Component.test.cpp b/src/GNDStk/Component/test/Component.test.cpp index 5c524cc2c..9d6899fd2 100644 --- a/src/GNDStk/Component/test/Component.test.cpp +++ b/src/GNDStk/Component/test/Component.test.cpp @@ -4,7 +4,7 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; @@ -21,11 +21,11 @@ class DerivedT : public Component { "", "class DerivedT" }, { "foo", "Help for foo" } }; - static auto namespaceName() { return "hello"; } - static auto className() { return "DerivedT"; } - static auto GNDSName() { return "none"; } - static auto keys() { return std::tuple<>{}; } - DerivedT() : Component(BodyText{}) { } + static auto NAMESPACE() { return "hello"; } + static auto CLASS() { return "DerivedT"; } + static auto FIELD() { return "none"; } + static auto KEYS() { return std::tuple<>{}; } + DerivedT() : Component(BlockData{}) { } }; @@ -38,27 +38,27 @@ class DerivedF : public Component { "", "class DerivedF" }, { "bar", "Help for bar" } }; - static auto namespaceName() { return "world"; } - static auto className() { return "DerivedF"; } - static auto GNDSName() { return "none"; } - static auto keys() { return std::tuple<>{}; } - DerivedF() : Component(BodyText{}) { } + static auto NAMESPACE() { return "world"; } + static auto CLASS() { return "DerivedF"; } + static auto FIELD() { return "none"; } + static auto KEYS() { return std::tuple<>{}; } + DerivedF() : Component(BlockData{}) { } }; // DerivedData // A Component-derived class with some data in it. -// Note that this class doesn't have help or namespaceName(); so we'll also use +// Note that this class doesn't have help or NAMESPACE(); so we'll also use // this class to test that Component's functionality that uses those still works // properly, as it should in that case. class DerivedData : public Component { public: friend class Component; - static auto className() { return "DerivedData"; } - static auto GNDSName() { return "data"; } + static auto CLASS() { return "DerivedData"; } + static auto FIELD() { return "data"; } - static auto keys() + static auto KEYS() { return int {} / Meta<>("foo") | @@ -69,22 +69,27 @@ class DerivedData : public Component struct { int foo; double bar; - } content; + } Content; + + const int &foo() const { return Content.foo; } + int &foo() { return Content.foo; } + const double &bar() const { return Content.bar; } + double &bar() { return Content.bar; } DerivedData() : Component( - BodyText{}, - content.foo, - content.bar + BlockData{}, + foo(), + bar() ) { } DerivedData(const Node &node) : Component( - BodyText{}, - content.foo, - content.bar + BlockData{}, + foo(), + bar() ) { Component::finish(node); @@ -140,17 +145,17 @@ SCENARIO("Testing GNDStk Component") { CHECK(der.documentation("bar") == "No help information is available"); } - // namespaceName() - WHEN("We test namespaceName()") { + // NAMESPACE() + WHEN("We test NAMESPACE()") { // For these two we need the std::string() only because the functions // were written (above, in the class definitions) with an auto return - // of a plain character string. Where Component needs namespaceName(), + // of a plain character string. Where Component needs NAMESPACE(), // it converts to std::string, so it's fine to write it that way. Here, // though, in this test file, it means we need the std::string(). - CHECK(der1.namespaceName() == std::string("hello")); - CHECK(der2.namespaceName() == std::string("world")); + CHECK(der1.NAMESPACE() == std::string("hello")); + CHECK(der2.NAMESPACE() == std::string("world")); DerivedData der; - CHECK(der.namespaceName() == ""); + CHECK(der.NAMESPACE() == ""); } // Component << string @@ -158,13 +163,13 @@ SCENARIO("Testing GNDStk Component") { // // Don't confuse the above two. Component << string reads from an XML // or JSON snippet into an object of the class that's derived from - // Component. ostream << Component writes (to the ostream) the object. + // Component. ostream << Component prints the object to the ostream. WHEN("We test (Component << string) and (ostream << Component)") { DerivedData der; color = false; // avoid cluttering the checked output below const std::string expected = - "DerivedData { // GNDS: data\n" + "DerivedData {\n" " foo : 12\n" " bar : 34.56\n" "} // DerivedData" @@ -174,7 +179,7 @@ SCENARIO("Testing GNDStk Component") { WHEN("We read a Component-derived object << XML text") { der << ""; - // write & check + // print, check THEN("The result is as expected") { std::ostringstream oss; oss << der; @@ -187,14 +192,14 @@ SCENARIO("Testing GNDStk Component") { der << "{" " \"data\": {" - " \"attributes\": {" + " \"#metadata\": {" " \"foo\": \"12\"," " \"bar\": \"34.56\"" " }" " }" "}"; - // write & check + // print, check THEN("The result is as expected") { std::ostringstream oss; oss << der; diff --git a/src/GNDStk/Component/test/ctor.test.cpp b/src/GNDStk/Component/test/ctor.test.cpp index 74e5ed7b0..6a38b5744 100644 --- a/src/GNDStk/Component/test/ctor.test.cpp +++ b/src/GNDStk/Component/test/ctor.test.cpp @@ -2,7 +2,7 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- @@ -17,7 +17,7 @@ using namespace njoy::GNDStk::core; // situations mentioned below: a class with no fields, and a class with fields. // We don't anticipate that people will need Component-derived classes that have // no fields, but still illustrate such a beast, for completeness. Note that the -// keys() function should return a std::tuple<>{} in that situation. +// KEYS() function should return a std::tuple<>{} in that situation. // ----------------------------------------------------------------------------- // DerivedNothing @@ -26,14 +26,14 @@ class DerivedNothing : public Component { friend class Component; - static auto keys() + static auto KEYS() { return std::tuple<>{}; } public: - DerivedNothing() : Component(BodyText{}) + DerivedNothing() : Component(BlockData{}) { Component::finish(); } @@ -46,7 +46,7 @@ class DerivedSomething : public Component { friend class Component; - static auto keys() + static auto KEYS() { return int {} / Meta<>("foo") | @@ -56,15 +56,20 @@ class DerivedSomething : public Component struct { int foo; double bar; - } content; + } Content; + + const int &foo() const { return Content.foo; } + int &foo() { return Content.foo; } + const double &bar() const { return Content.bar; } + double &bar() { return Content.bar; } public: DerivedSomething() : Component( - BodyText{}, - content.foo, - content.bar + BlockData{}, + foo(), + bar() ) { Component::finish(); diff --git a/src/GNDStk/Component/test/detail.test.cpp b/src/GNDStk/Component/test/detail.test.cpp index 3011e0182..508ef293e 100644 --- a/src/GNDStk/Component/test/detail.test.cpp +++ b/src/GNDStk/Component/test/detail.test.cpp @@ -2,21 +2,21 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- -// Classes for testing the hasWrite*() functions +// Classes for testing the hasPrint*() functions // ----------------------------------------------------------------------------- struct Neither { - // has neither of the write()s seen in the upcoming classes + // has neither of the print()s seen in the upcoming classes }; struct One { // (ostream) only - std::ostream &write(std::ostream &os) const + std::ostream &print(std::ostream &os) const { return os; } @@ -24,7 +24,7 @@ struct One { struct Two { // (ostream,int) only - std::ostream &write(std::ostream &os, const int) const + std::ostream &print(std::ostream &os, const int) const { return os; } @@ -32,12 +32,12 @@ struct Two { struct Both { // (ostream) - std::ostream &write(std::ostream &os) const + std::ostream &print(std::ostream &os) const { return os; } // (ostream,int) - std::ostream &write(std::ostream &os, const int) const + std::ostream &print(std::ostream &os, const int) const { return os; } @@ -57,7 +57,12 @@ struct FooBar { struct { int foo; double bar; - } content; + } Content; + + const int &foo() const { return Content.foo; } + int &foo() { return Content.foo; } + const double &bar() const { return Content.bar; } + double &bar() { return Content.bar; } }; @@ -65,17 +70,17 @@ struct FooBar { // ----------------------------------------------------------------------------- // class Derived // Is derived from Component -// Used in the tests of writeComponentPart() +// Used in the tests of printComponentPart() // ----------------------------------------------------------------------------- class Derived : public Component { public: friend class Component; - static auto className() { return "Derived"; } - static auto GNDSName() { return "none"; } + static auto CLASS() { return "Derived"; } + static auto FIELD() { return "none"; } - static auto keys() + static auto KEYS() { return // metadata @@ -87,7 +92,7 @@ class Derived : public Component { int foo = 56; double bar = 7.8; - Derived() : Component(BodyText{},foo,bar) { } + Derived() : Component(BlockData{},foo,bar) { } }; @@ -103,7 +108,7 @@ class NonDerived { double bar = 3.4; }; -// Needs << in order to participate in writeComponentPart() - which it does, +// Needs << in order to participate in printComponentPart() - which it does, // because we're using it as a test subject there. inline std::ostream &operator<<(std::ostream &s, const NonDerived &obj) @@ -228,20 +233,20 @@ SCENARIO("Testing Component detail:: miscellaneous functions") { CHECK(oss.str() == " foo"); } // GIVEN - // hasWrite* + // hasPrint* // Test some SFINAE constructs - GIVEN("Functions: hasWriteOneArg(), hasWriteTwoArg()") { - CHECK(detail::hasWriteOneArg == false); - CHECK(detail::hasWriteTwoArg == false); + GIVEN("Functions: hasPrintOneArg(), hasPrintTwoArg()") { + CHECK(detail::hasPrintOneArg == false); + CHECK(detail::hasPrintTwoArg == false); - CHECK(detail::hasWriteOneArg == true); - CHECK(detail::hasWriteTwoArg == false); + CHECK(detail::hasPrintOneArg == true); + CHECK(detail::hasPrintTwoArg == false); - CHECK(detail::hasWriteOneArg == false); - CHECK(detail::hasWriteTwoArg == true); + CHECK(detail::hasPrintOneArg == false); + CHECK(detail::hasPrintTwoArg == true); - CHECK(detail::hasWriteOneArg == true); - CHECK(detail::hasWriteTwoArg == true); + CHECK(detail::hasPrintOneArg == true); + CHECK(detail::hasPrintTwoArg == true); } // GIVEN } @@ -260,66 +265,66 @@ SCENARIO("Testing Component detail:: miscellaneous functions") { // ostream, level, vector, label, maxlen, color = "" // All return bool. -SCENARIO("Testing Component detail:: writeComponentPart()") { +SCENARIO("Testing Component detail:: printComponentPart()") { // for clarity below int level; std::size_t maxlen; std::ostringstream oss; indent = 2; - using detail::writeComponentPart; + using detail::printComponentPart; // For string - GIVEN("writeComponentPart() for string") { + GIVEN("printComponentPart() for string") { oss.str(""); - writeComponentPart(oss, level=2, "foo\nbar", "label", maxlen=0); + printComponentPart(oss, level=2, "foo\nbar", "label", maxlen=0); CHECK(oss.str() == " label : foo\n" " bar"); oss.str(""); - writeComponentPart(oss, level=2, "foo\nbar", "label", maxlen=10); + printComponentPart(oss, level=2, "foo\nbar", "label", maxlen=10); CHECK(oss.str() == " label : foo\n" " bar"); oss.str(""); - writeComponentPart(oss, level=2, "foo\nbar", "", maxlen=0); + printComponentPart(oss, level=2, "foo\nbar", "", maxlen=0); CHECK(oss.str() == " foo\n" " bar"); oss.str(""); - writeComponentPart(oss, level=2, "foo\nbar", "", maxlen=10); + printComponentPart(oss, level=2, "foo\nbar", "", maxlen=10); CHECK(oss.str() == " foo\n" " bar"); } // GIVEN // For general types T - GIVEN("writeComponentPart() for T") { + GIVEN("printComponentPart() for T") { // For double WHEN("T is double") { double value = 1.234; oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=0); + printComponentPart(oss, level=2, value, "label", maxlen=0); CHECK(oss.str() == " label : 1.234"); oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=10); + printComponentPart(oss, level=2, value, "label", maxlen=10); CHECK(oss.str() == " label : 1.234"); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=0); + printComponentPart(oss, level=2, value, "", maxlen=0); CHECK(oss.str() == " 1.234"); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=10); + printComponentPart(oss, level=2, value, "", maxlen=10); CHECK(oss.str() == " 1.234"); } - // writeComponentPart() for general T has an if-constexpr that + // printComponentPart() for general T has an if-constexpr that // distinguished classes that *are* derived from Component from // those that aren't, so we'll test both cases. (double, above, // in fact falls into the latter category.) ... @@ -330,28 +335,28 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { // label and maxlen don't get used in this case. // The Component-derived nature of the class causes - // value.write(stream,level) to be called instead. + // value.print(stream,level) to be called instead. // So we get the same result from each call. const std::string expected = - " Derived { // GNDS: none\n" + " Derived {\n" " foo : 56\n" " bar : 7.8\n" " } // Derived"; oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=0); + printComponentPart(oss, level=2, value, "label", maxlen=0); CHECK(oss.str() == expected); oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=10); + printComponentPart(oss, level=2, value, "label", maxlen=10); CHECK(oss.str() == expected); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=0); + printComponentPart(oss, level=2, value, "", maxlen=0); CHECK(oss.str() == expected); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=10); + printComponentPart(oss, level=2, value, "", maxlen=10); CHECK(oss.str() == expected); } @@ -360,42 +365,42 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { NonDerived value; oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=0); + printComponentPart(oss, level=2, value, "label", maxlen=0); CHECK(oss.str() == " label : {12,3.4}"); oss.str(""); - writeComponentPart(oss, level=2, value, "label", maxlen=10); + printComponentPart(oss, level=2, value, "label", maxlen=10); CHECK(oss.str() == " label : {12,3.4}"); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=0); + printComponentPart(oss, level=2, value, "", maxlen=0); CHECK(oss.str() == " {12,3.4}"); oss.str(""); - writeComponentPart(oss, level=2, value, "", maxlen=10); + printComponentPart(oss, level=2, value, "", maxlen=10); CHECK(oss.str() == " {12,3.4}"); } } // GIVEN // For optional - GIVEN("writeComponentPart() for optional") { + GIVEN("printComponentPart() for optional") { WHEN("The optional has a value") { std::optional opt = 1.234; oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=0); + printComponentPart(oss, level=2, opt, "label", maxlen=0); CHECK(oss.str() == " label : 1.234"); oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=10); + printComponentPart(oss, level=2, opt, "label", maxlen=10); CHECK(oss.str() == " label : 1.234"); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=0); + printComponentPart(oss, level=2, opt, "", maxlen=0); CHECK(oss.str() == " 1.234"); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=10); + printComponentPart(oss, level=2, opt, "", maxlen=10); CHECK(oss.str() == " 1.234"); } @@ -405,19 +410,19 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { comments = false; oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=0); + printComponentPart(oss, level=2, opt, "label", maxlen=0); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=10); + printComponentPart(oss, level=2, opt, "label", maxlen=10); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=0); + printComponentPart(oss, level=2, opt, "", maxlen=0); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=10); + printComponentPart(oss, level=2, opt, "", maxlen=10); CHECK(oss.str() == ""); } @@ -427,25 +432,25 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { comments = true; oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=0); + printComponentPart(oss, level=2, opt, "label", maxlen=0); CHECK(oss.str() == " label : // optional; has no value"); oss.str(""); - writeComponentPart(oss, level=2, opt, "label", maxlen=10); + printComponentPart(oss, level=2, opt, "label", maxlen=10); CHECK(oss.str() == " label : // optional; has no value"); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=0); + printComponentPart(oss, level=2, opt, "", maxlen=0); CHECK(oss.str() == " // optional; has no value"); oss.str(""); - writeComponentPart(oss, level=2, opt, "", maxlen=10); + printComponentPart(oss, level=2, opt, "", maxlen=10); CHECK(oss.str() == " // optional; has no value"); } } // GIVEN // For Defaulted - GIVEN("writeComponentPart() for Defaulted") { + GIVEN("printComponentPart() for Defaulted") { WHEN("The Defaulted has an explicitly provided value") { // For the following: // 5.6 is the default @@ -453,19 +458,19 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { Defaulted def(5.6,7.8); oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=0); + printComponentPart(oss, level=2, def, "label", maxlen=0); CHECK(oss.str() == " label : 7.8"); oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=10); + printComponentPart(oss, level=2, def, "label", maxlen=10); CHECK(oss.str() == " label : 7.8"); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=0); + printComponentPart(oss, level=2, def, "", maxlen=0); CHECK(oss.str() == " 7.8"); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=10); + printComponentPart(oss, level=2, def, "", maxlen=10); CHECK(oss.str() == " 7.8"); } @@ -475,19 +480,19 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { comments = false; oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=0); + printComponentPart(oss, level=2, def, "label", maxlen=0); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=10); + printComponentPart(oss, level=2, def, "label", maxlen=10); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=0); + printComponentPart(oss, level=2, def, "", maxlen=0); CHECK(oss.str() == ""); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=10); + printComponentPart(oss, level=2, def, "", maxlen=10); CHECK(oss.str() == ""); } @@ -497,47 +502,49 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { comments = true; oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=0); - CHECK(oss.str() == " label : // defaulted; is its default (2.72)"); + printComponentPart(oss, level=2, def, "label", maxlen=0); + CHECK(oss.str() == + " label : // defaulted; is its default (2.72)"); oss.str(""); - writeComponentPart(oss, level=2, def, "label", maxlen=10); - CHECK(oss.str() == " label : // defaulted; is its default (2.72)"); + printComponentPart(oss, level=2, def, "label", maxlen=10); + CHECK(oss.str() == + " label : // defaulted; is its default (2.72)"); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=0); + printComponentPart(oss, level=2, def, "", maxlen=0); CHECK(oss.str() == " // defaulted; is its default (2.72)"); oss.str(""); - writeComponentPart(oss, level=2, def, "", maxlen=10); + printComponentPart(oss, level=2, def, "", maxlen=10); CHECK(oss.str() == " // defaulted; is its default (2.72)"); } } // GIVEN // For variant - GIVEN("writeComponentPart() for variant") { + GIVEN("printComponentPart() for variant") { oss.str(""); std::variant var(9.87); oss.str(""); - writeComponentPart(oss, level=2, var, "label", maxlen=0); + printComponentPart(oss, level=2, var, "label", maxlen=0); CHECK(oss.str() == " label : 9.87"); oss.str(""); - writeComponentPart(oss, level=2, var, "label", maxlen=10); + printComponentPart(oss, level=2, var, "label", maxlen=10); CHECK(oss.str() == " label : 9.87"); oss.str(""); - writeComponentPart(oss, level=2, var, "", maxlen=0); + printComponentPart(oss, level=2, var, "", maxlen=0); CHECK(oss.str() == " 9.87"); oss.str(""); - writeComponentPart(oss, level=2, var, "", maxlen=10); + printComponentPart(oss, level=2, var, "", maxlen=10); CHECK(oss.str() == " 9.87"); } // GIVEN // For vector - GIVEN("writeComponentPart() for vector") { + GIVEN("printComponentPart() for vector") { oss.str(""); const std::vector vec{{"a","b","c","d","e"}}; @@ -551,11 +558,11 @@ SCENARIO("Testing Component detail:: writeComponentPart()") { " ]"; oss.str(""); - writeComponentPart(oss, level=2, vec, "label", maxlen=0); + printComponentPart(oss, level=2, vec, "label", maxlen=0); CHECK(oss.str() == expected); oss.str(""); - writeComponentPart(oss, level=2, vec, "label", maxlen=10); + printComponentPart(oss, level=2, vec, "label", maxlen=10); CHECK(oss.str() == expected); } // GIVEN } @@ -658,13 +665,14 @@ SCENARIO("Testing Component detail:: getter() functions") { GIVEN("A vector of objects that have both index and label") { // look for specific index THEN("getter() based on index works properly") { - CHECK((detail::getter(vec,0,"name","class","field").value() == "0a")); - CHECK((detail::getter(vec,1,"name","class","field").value() == "1b")); - CHECK((detail::getter(vec,2,"name","class","field").value() == "2c")); - CHECK((detail::getter(vec,3,"name","class","field").value() == "3d")); - CHECK((detail::getter(vec,4,"name","class","field").value() == "4e")); + using detail::getter; + CHECK((getter(vec, 0, "name", "class", "field").value() == "0a")); + CHECK((getter(vec, 1, "name", "class", "field").value() == "1b")); + CHECK((getter(vec, 2, "name", "class", "field").value() == "2c")); + CHECK((getter(vec, 3, "name", "class", "field").value() == "3d")); + CHECK((getter(vec, 4, "name", "class", "field").value() == "4e")); try { - detail::getter(vec,100,"name","class","field"); + getter(vec, 100, "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { @@ -673,13 +681,14 @@ SCENARIO("Testing Component detail:: getter() functions") { // look for specific label THEN("getter() based on label works properly") { - CHECK((detail::getter(vec,"a","name","class","field").value() == "0a")); - CHECK((detail::getter(vec,"b","name","class","field").value() == "1b")); - CHECK((detail::getter(vec,"c","name","class","field").value() == "2c")); - CHECK((detail::getter(vec,"d","name","class","field").value() == "3d")); - CHECK((detail::getter(vec,"e","name","class","field").value() == "4e")); + using detail::getter; + CHECK((getter(vec, "a", "name", "class", "field").value() == "0a")); + CHECK((getter(vec, "b", "name", "class", "field").value() == "1b")); + CHECK((getter(vec, "c", "name", "class", "field").value() == "2c")); + CHECK((getter(vec, "d", "name", "class", "field").value() == "3d")); + CHECK((getter(vec, "e", "name", "class", "field").value() == "4e")); try { - detail::getter(vec,"z","name","class","field"); + getter(vec, "z", "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { @@ -698,13 +707,14 @@ SCENARIO("Testing Component detail:: getter() functions") { // look for specific index THEN("getter() based on index works properly") { - CHECK((detail::getter(opt,0UL,"name","class","field").value() == "0a")); - CHECK((detail::getter(opt,1UL,"name","class","field").value() == "1b")); - CHECK((detail::getter(opt,2UL,"name","class","field").value() == "2c")); - CHECK((detail::getter(opt,3UL,"name","class","field").value() == "3d")); - CHECK((detail::getter(opt,4UL,"name","class","field").value() == "4e")); + using detail::getter; + CHECK((getter(opt, 0UL, "name", "class", "field").value() == "0a")); + CHECK((getter(opt, 1UL, "name", "class", "field").value() == "1b")); + CHECK((getter(opt, 2UL, "name", "class", "field").value() == "2c")); + CHECK((getter(opt, 3UL, "name", "class", "field").value() == "3d")); + CHECK((getter(opt, 4UL, "name", "class", "field").value() == "4e")); try { - detail::getter(opt,100UL,"name","class","field"); + getter(opt, 100UL, "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { @@ -713,13 +723,14 @@ SCENARIO("Testing Component detail:: getter() functions") { // look for specific label THEN("getter() based on label works properly") { - CHECK((detail::getter(opt,"a","name","class","field").value() == "0a")); - CHECK((detail::getter(opt,"b","name","class","field").value() == "1b")); - CHECK((detail::getter(opt,"c","name","class","field").value() == "2c")); - CHECK((detail::getter(opt,"d","name","class","field").value() == "3d")); - CHECK((detail::getter(opt,"e","name","class","field").value() == "4e")); + using detail::getter; + CHECK((getter(opt, "a", "name", "class", "field").value() == "0a")); + CHECK((getter(opt, "b", "name", "class", "field").value() == "1b")); + CHECK((getter(opt, "c", "name", "class", "field").value() == "2c")); + CHECK((getter(opt, "d", "name", "class", "field").value() == "3d")); + CHECK((getter(opt, "e", "name", "class", "field").value() == "4e")); try { - detail::getter(opt,"z","name","class","field"); + getter(opt, "z", "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { @@ -739,7 +750,7 @@ SCENARIO("Testing Component detail:: getter() functions") { // look for specific index THEN("getter() based on index works properly") { try { - detail::getter(opt,0,"name","class","field"); + detail::getter(opt, 0, "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { @@ -749,7 +760,7 @@ SCENARIO("Testing Component detail:: getter() functions") { // look for specific label THEN("getter() based on label works properly") { try { - detail::getter(opt,"a","name","class","field"); + detail::getter(opt, "a", "name", "class", "field"); // the above should throw, so we shouldn't get here... CHECK(false); } catch (...) { diff --git a/src/GNDStk/Component/test/finish.test.cpp b/src/GNDStk/Component/test/finish.test.cpp index 59d7edab3..d999b1a8c 100644 --- a/src/GNDStk/Component/test/finish.test.cpp +++ b/src/GNDStk/Component/test/finish.test.cpp @@ -2,13 +2,13 @@ #include "catch.hpp" #include "GNDStk.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- // DerivedValue -// Has body text +// Has block data // ----------------------------------------------------------------------------- namespace test { @@ -17,14 +17,17 @@ namespace test { struct IndexStruct { struct { std::size_t index; - } content; - IndexStruct(const std::size_t i = 0) { content.index = i; } + } Content; + const std::size_t &index() const { return Content.index; } + std::size_t &index() { return Content.index; } + + IndexStruct(const std::size_t i = 0) { index() = i; } IndexStruct(const Node &) : IndexStruct(0) { } }; inline bool operator==(const IndexStruct &one, const IndexStruct &two) { - return one.content.index == two.content.index; + return one.index() == two.index(); } @@ -42,12 +45,12 @@ class DerivedValue : public Component friend class Component; // names - static auto namespaceName() { return "test"; } - static auto className() { return "DerivedValue"; } - static auto GNDSName() { return "value"; } + static auto NAMESPACE() { return "test"; } + static auto CLASS() { return "DerivedValue"; } + static auto FIELD() { return "value"; } // keys - static auto keys() + static auto KEYS() { return int{} / Meta<>("length") | @@ -59,12 +62,13 @@ class DerivedValue : public Component public: - // content + // Content // Typically doesn't need to be public, but we make it public here because // one of the tests involves checking these struct { // Initialize these to specific values, so that we can ensure that - // Component's finish() functions properly call body::pullFromDerived() + // Component's finish() functions properly call + // BLOCKDATA::pullFromDerived() int length = 11; int start = 3; std::string valueType = "foobar"; @@ -73,7 +77,21 @@ class DerivedValue : public Component // functions detect and sort it. std::optional> indices = {{3,2,17,7,5,9,13,11}}; - } content; + } Content; + + const int &length() const { return Content.length; } + int &length() { return Content.length; } + + const int &start() const { return Content.start; } + int &start() { return Content.start; } + + const std::string &valueType() const { return Content.valueType; } + std::string &valueType() { return Content.valueType; } + + const std::optional> &indices() const + { return Content.indices; } + std::optional> &indices() + { return Content.indices; } private: @@ -106,8 +124,8 @@ class DerivedValue : public Component // ctor: default DerivedValue() : Component( - BodyText{}, - content.length, content.start, content.valueType, content.indices + BlockData{}, + length(), start(), valueType(), indices() ) { // finish() @@ -118,9 +136,9 @@ class DerivedValue : public Component DerivedValue(const DerivedValue &other) : Component{ other, - content.length, content.start, content.valueType, content.indices + length(), start(), valueType(), indices() }, - content{other.content} + Content{other.Content} { // finish(derived) Component::finish(other); @@ -129,8 +147,8 @@ class DerivedValue : public Component // ctor: node DerivedValue(const Node &node) : Component{ - BodyText{}, - content.length, content.start, content.valueType, content.indices + BlockData{}, + length(), start(), valueType(), indices() } { // finish(node) @@ -140,8 +158,8 @@ class DerivedValue : public Component // ctor: vector DerivedValue(const std::vector &vec) : Component{ - BodyText{}, - content.length, content.start, content.valueType, content.indices + BlockData{}, + length(), start(), valueType(), indices() } { // finish(vector) @@ -155,7 +173,7 @@ class DerivedValue : public Component // ----------------------------------------------------------------------------- // DerivedPlain -// Does not have body text +// Does not have block data // ----------------------------------------------------------------------------- namespace test { @@ -164,18 +182,21 @@ namespace test { struct LabelStruct { struct { std::string label; - } content; + } Content; + const std::string &label() const { return Content.label; } + std::string &label() { return Content.label; } + // apparently need a char* ctor for initializer-list initialization to work - LabelStruct(const char *const str = "") { content.label = str; } + LabelStruct(const char *const str = "") { label() = str; } LabelStruct(const Node &node) { - content.label = node(std::string{}/Meta<>("label")); + label() = node(std::string{}/Meta<>("label")); } }; inline bool operator==(const LabelStruct &one, const LabelStruct &two) { - return one.content.label == two.content.label; + return one.label() == two.label(); } @@ -191,12 +212,12 @@ class DerivedPlain : public Component friend class Component; // names - static auto namespaceName() { return "test"; } - static auto className() { return "DerivedPlain"; } - static auto GNDSName() { return "plain"; } + static auto NAMESPACE() { return "test"; } + static auto CLASS() { return "DerivedPlain"; } + static auto FIELD() { return "plain"; } // keys - static auto keys() + static auto KEYS() { return int {} / Meta<>("foo") | @@ -207,7 +228,7 @@ class DerivedPlain : public Component public: - // content + // Content struct { int foo; double bar; @@ -216,7 +237,18 @@ class DerivedPlain : public Component // functions detect and sort it. std::optional> labels = {{"bc","a","p","efg","d","hi","no","jklm"}}; - } content; + } Content; + + const int &foo() const { return Content.foo; } + int &foo() { return Content.foo; } + + const double &bar() const { return Content.bar; } + double &bar() { return Content.bar; } + + const std::optional> &labels() const + { return Content.labels; } + std::optional> &labels() + { return Content.labels; } private: @@ -243,8 +275,8 @@ class DerivedPlain : public Component // ctor: default DerivedPlain() : Component( - BodyText{}, - content.foo, content.bar, content.labels + BlockData{}, + foo(), bar(), labels() ) { // finish() @@ -255,9 +287,9 @@ class DerivedPlain : public Component DerivedPlain(const DerivedPlain &other) : Component{ other, - content.foo, content.bar, content.labels + foo(), bar(), labels() }, - content{other.content} + Content{other.Content} { // finish(derived) Component::finish(other); @@ -266,8 +298,8 @@ class DerivedPlain : public Component // ctor: node DerivedPlain(const Node &node) : Component{ - BodyText{}, - content.foo, content.bar, content.labels + BlockData{}, + foo(), bar(), labels() } { // finish(node) @@ -289,7 +321,7 @@ class DerivedPlain : public Component SCENARIO("Component finish()") { - GIVEN("A component-derived class that has body text") { + GIVEN("A component-derived class that has block data") { const std::vector sorted = {{2,3,5,7,9,11,13,17}}; @@ -300,15 +332,15 @@ SCENARIO("Component finish()") { // Ensure that finish() called the construct() in the derived class... CHECK(test::construct1DerivedValue == true); - // Ensure that finish() did a BodyText::pullFromDerived() + // Ensure that finish() did a BlockData::pullFromDerived() CHECK(d.length() == 11); CHECK(d.start() == 3); CHECK(d.valueType() == "foobar"); // Ensure that finish() did a sort() - CHECK(d.content.indices.has_value() == true); - CHECK(d.content.indices->size() == 8); - CHECK(*d.content.indices == sorted); + CHECK(d.indices().has_value() == true); + CHECK(d.indices()->size() == 8); + CHECK(*d.indices() == sorted); } // ctor: copy @@ -340,9 +372,9 @@ SCENARIO("Component finish()") { CHECK(d.valueType() == "foobar"); // Ensure that finish() did a sort() - CHECK(d.content.indices.has_value() == true); - CHECK(d.content.indices->size() == 8); - CHECK(*d.content.indices == sorted); + CHECK(d.indices().has_value() == true); + CHECK(d.indices()->size() == 8); + CHECK(*d.indices() == sorted); } // ctor: from node @@ -357,7 +389,7 @@ SCENARIO("Component finish()") { test::DerivedValue d(node); CHECK(test::construct3DerivedValue == true); - // Here, the following values in the underlying BodyText should + // Here, the following values in the underlying BlockData should // reflect those that were brought in through the above string. CHECK(d.length() == 10); CHECK(d.start() == 2); @@ -375,9 +407,9 @@ SCENARIO("Component finish()") { CHECK(d.get(8) == 0); CHECK(d.get(9) == 0); - // The node from which we read had body text, not child nodes, + // The node from which we read had block data, not child nodes, // and thus would give us nothing for (std::optional) indices... - CHECK(d.content.indices.has_value() == false); + CHECK(d.indices().has_value() == false); } // ctor: from vector @@ -388,7 +420,7 @@ SCENARIO("Component finish()") { CHECK(test::construct4DerivedValue == true); // Here, the finish(vector) function was called, which in turn called - // BodyText's operator=(vector), which sets the following according + // BlockData's operator=(vector), which sets the following according // to what's actually in the vector CHECK(d.length() == 3); CHECK(d.start() == 0); // <== always the case in this context @@ -400,22 +432,22 @@ SCENARIO("Component finish()") { CHECK(Approx(d.get(1)) == 2.71828); CHECK(Approx(d.get(2)) == 1.41421); - // And, BodyText's operator=(vector) as mentioned above should also + // And, BlockData's operator=(vector) as mentioned above should also // have changed the corresponding values back up in the derived class - CHECK(d.content.length == 3); - CHECK(d.content.start == 0); - CHECK(d.content.valueType == "Float64"); + CHECK(d.length() == 3); + CHECK(d.start() == 0); + CHECK(d.valueType() == "Float64"); // Ensure that finish() did a sort() - CHECK(d.content.indices.has_value() == true); - CHECK(d.content.indices->size() == 8); - CHECK(*d.content.indices == sorted); + CHECK(d.indices().has_value() == true); + CHECK(d.indices()->size() == 8); + CHECK(*d.indices() == sorted); } } // GIVEN - GIVEN("A component-derived class that does not have body text") { + GIVEN("A component-derived class that does not have block data") { const std::vector sorted = {{"a","bc","d","efg","hi","jklm","no","p"}}; @@ -425,9 +457,9 @@ SCENARIO("Component finish()") { test::DerivedPlain d; CHECK(test::construct1DerivedPlain == true); - CHECK(d.content.labels.has_value() == true); - CHECK(d.content.labels->size() == 8); - CHECK(*d.content.labels == sorted); + CHECK(d.labels().has_value() == true); + CHECK(d.labels()->size() == 8); + CHECK(*d.labels() == sorted); } // ctor: copy @@ -438,9 +470,9 @@ SCENARIO("Component finish()") { test::DerivedPlain d(dfrom); CHECK(test::construct2DerivedPlain == true); - CHECK(d.content.labels.has_value() == true); - CHECK(d.content.labels->size() == 8); - CHECK(*d.content.labels == sorted); + CHECK(d.labels().has_value() == true); + CHECK(d.labels()->size() == 8); + CHECK(*d.labels() == sorted); } // ctor: from node, case 1 @@ -454,7 +486,7 @@ SCENARIO("Component finish()") { test::DerivedPlain d(node); CHECK(test::construct3DerivedPlain == true); - CHECK(d.content.labels.has_value() == false); + CHECK(d.labels().has_value() == false); } // ctor: from node, case 2 @@ -472,10 +504,10 @@ SCENARIO("Component finish()") { test::DerivedPlain d(node); CHECK(test::construct3DerivedPlain == true); - CHECK(d.content.labels.has_value() == true); - CHECK(d.content.labels->size() == 4); + CHECK(d.labels().has_value() == true); + CHECK(d.labels()->size() == 4); CHECK(( - *d.content.labels == + *d.labels() == std::vector{{"abc","def","ghi","jkl"}} )); } diff --git a/src/GNDStk/Component/test/fromNode.test.cpp b/src/GNDStk/Component/test/fromNode.test.cpp index 55a9e5cae..9c1bf456c 100644 --- a/src/GNDStk/Component/test/fromNode.test.cpp +++ b/src/GNDStk/Component/test/fromNode.test.cpp @@ -3,9 +3,12 @@ #include "GNDStk.hpp" #include "prototype.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; using namespace GNDStk::proto; +#include "GNDStk/test/keys.hpp" +using namespace basic; + // ----------------------------------------------------------------------------- // DISCUSSION @@ -19,9 +22,9 @@ Component does the following: - Calls Component's fromNode() function to read known fields from the Node into the derived class object. - - If the Node has "body text," syncs certain fields in the BodyText (base + - If the Node has block data, syncs certain fields in the BlockData (base of Component) class, with fields in the derived class. Then, converts a - raw body-text string into a vector of values. + raw block data string into a vector of values. - Performs a sort() of derived-class vectors that are known to Component, and that have an index and/or a label. @@ -35,7 +38,7 @@ The tests in this file make use of a particular GNDS file with a reactionSuite. We use a prototype ReactionSuite class (with content that's pared down from what's in the full GNDS spec) that's derived from Component. -The reaction suite itself doesn't (directly) have any body text or sort-able +The reaction suite itself doesn't (directly) have any block data or sort-able fields, and doesn't have a construct(). So, our first test (1) constructs from a Node, (2) uses fromNode() to read from @@ -53,10 +56,10 @@ give different results: the former sorts, the latter doesn't. After the results from (2) are sorted, however, the two Reactions objects are the same. Finally, our third test works with Values objects. Objects of this type have -body text. Construction from Node does a get(), which takes the original, raw -body text in the Node, and makes a vector (in this case vector) from +block data. Construction from Node does a get(), which takes the original, raw +block data in the Node, and makes a vector (in this case vector) from it. fromNode() doesn't do that until, and unless, we ask for it by calling get() -directly. Values objects with only raw text write differently than those with +directly. Values objects with only raw text print differently than those with text that was processed into a vector. So, this test first ensures that the two Values objects print differently. Then it does an explicit get() for the object that used fromNode(), and ensures that the results are identical thereafter. @@ -162,7 +165,7 @@ SCENARIO("Component fromNode()") { oss2 << values2; CHECK(oss1.str() != oss2.str()); // not equal (yet) - // *** Apply get() *** to transform the raw string of body-text + // *** Apply get() *** to transform the raw string of block data // values into a vector values2.get(); oss2.str(""); diff --git a/src/GNDStk/Component/test/getter.test.cpp b/src/GNDStk/Component/test/getter.test.cpp index 46e815e43..4ccf83d92 100644 --- a/src/GNDStk/Component/test/getter.test.cpp +++ b/src/GNDStk/Component/test/getter.test.cpp @@ -3,7 +3,7 @@ #include "GNDStk.hpp" #include "indexnlabel.hpp" -using namespace njoy::GNDStk::core; +using namespace njoy::GNDStk; // ----------------------------------------------------------------------------- @@ -18,9 +18,9 @@ class TestGetter : public Component { friend class Component; - static auto className() { return "TestGetter"; } - // static auto GNDSName() - not actually needed here - static auto keys() + static auto CLASS() { return "TestGetter"; } + // static auto FIELD() - not actually needed here + static auto KEYS() { return std::tuple<>{}; } @@ -38,7 +38,7 @@ class TestGetter : public Component // ------------------------ // See earlier remark. We don't bother linking these with GNDS fields, via - // Component's capabilities and the keys() function, because doing so isn't + // Component's capabilities and the KEYS() function, because doing so isn't // necessary for the present tests. // some vectors @@ -56,7 +56,7 @@ class TestGetter : public Component // constructor: default // ------------------------ - TestGetter() : Component{ BodyText{} } + TestGetter() : Component{ BlockData{} } { // Component::finish(); = not needed here } @@ -98,15 +98,24 @@ class TestGetter : public Component CHECK( getter(vecIndexLabel,7,"vecIndexLabel").value() == "7 (seven)" ); // re: vecIndexLabel, lookup by label - CHECK( getter(vecIndexLabel,"five","vecIndexLabel").index() == 5 ); - CHECK( getter(vecIndexLabel,"five","vecIndexLabel").label() == "five" ); - CHECK( getter(vecIndexLabel,"five","vecIndexLabel").value() == "5 (five)" ); - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").index() == 6 ); - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").label() == "six" ); - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").value() == "6 (six)" ); - CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").index() == 7 ); - CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").label() == "seven" ); - CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").value() == "7 (seven)" ); + CHECK( getter(vecIndexLabel,"five","vecIndexLabel").index() + == 5 ); + CHECK( getter(vecIndexLabel,"five","vecIndexLabel").label() + == "five" ); + CHECK( getter(vecIndexLabel,"five","vecIndexLabel").value() + == "5 (five)" ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").index() + == 6 ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").label() + == "six" ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").value() + == "6 (six)" ); + CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").index() + == 7 ); + CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").label() + == "seven" ); + CHECK( getter(vecIndexLabel,"seven","vecIndexLabel").value() + == "7 (seven)" ); } // non-const @@ -156,27 +165,36 @@ class TestGetter : public Component IndexLabel{ 11, "eleven", "11 (eleven)" }; // verify the new value - CHECK( getter(vecIndexLabel,11,"vecIndexLabel").index() == 11 ); - CHECK( getter(vecIndexLabel,11,"vecIndexLabel").label() == "eleven" ); - CHECK( getter(vecIndexLabel,11,"vecIndexLabel").value() == "11 (eleven)" ); + CHECK( getter(vecIndexLabel,11,"vecIndexLabel").index() + == 11 ); + CHECK( getter(vecIndexLabel,11,"vecIndexLabel").label() + == "eleven" ); + CHECK( getter(vecIndexLabel,11,"vecIndexLabel").value() + == "11 (eleven)" ); // ------------------------ // re: vecIndexLabel, lookup by label // ------------------------ // verify an existing value - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").index() == 6 ); - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").label() == "six" ); - CHECK( getter(vecIndexLabel,"six","vecIndexLabel").value() == "6 (six)" ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").index() + == 6 ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").label() + == "six" ); + CHECK( getter(vecIndexLabel,"six","vecIndexLabel").value() + == "6 (six)" ); // change getter(vecIndexLabel,"six","vecIndexLabel") = IndexLabel{ 13, "thirteen", "13 (thirteen)" }; // verify new value - CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").index() == 13); - CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").label() == "thirteen" ); - CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").value() == "13 (thirteen)" ); + CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").index() + == 13); + CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").label() + == "thirteen" ); + CHECK( getter(vecIndexLabel,"thirteen","vecIndexLabel").value() + == "13 (thirteen)" ); } // ------------------------ @@ -223,14 +241,20 @@ class TestGetter : public Component CHECK( getter)***"; } diff --git a/src/GNDStk/v1.9/containers/Axis.hpp b/src/GNDStk/v1.9/containers/Axis.hpp index 2fb9d900f..5675c7682 100644 --- a/src/GNDStk/v1.9/containers/Axis.hpp +++ b/src/GNDStk/v1.9/containers/Axis.hpp @@ -2,19 +2,15 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_AXIS -#define NJOY_GNDSTK_V1_9_CONTAINERS_AXIS +#ifndef GNDSTK_V1_9_CONTAINERS_AXIS +#define GNDSTK_V1_9_CONTAINERS_AXIS -// core interface -#include "GNDStk.hpp" +#include "GNDStk/v1.9/key.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -23,8 +19,7 @@ using namespace njoy::GNDStk::core; namespace containers { -class Axis : public Component { - +class Axis : public Component { // ------------------------ // For Component @@ -32,13 +27,13 @@ class Axis : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "Axis"; } - static auto GNDSName() { return "axis"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "Axis"; } + static auto FIELD() { return "axis"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -55,14 +50,6 @@ class Axis : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -72,7 +59,7 @@ class Axis : public Component { std::optional index; std::optional label; std::optional unit; - } content; + } Content; // ------------------------ // Getters @@ -81,21 +68,21 @@ class Axis : public Component { // index const std::optional &index() const - { return content.index; } + { return Content.index; } std::optional &index() - { return content.index; } + { return Content.index; } // label const std::optional &label() const - { return content.label; } + { return Content.label; } std::optional &label() - { return content.label; } + { return Content.label; } // unit const std::optional &unit() const - { return content.unit; } + { return Content.unit; } std::optional &unit() - { return content.unit; } + { return Content.unit; } // ------------------------ // Setters @@ -116,16 +103,28 @@ class Axis : public Component { { unit() = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Axis() : + // default, and from fields + explicit Axis( + const std::optional &index = + std::optional{}, + const std::optional &label = + std::optional{}, + const std::optional &unit = + std::optional{} + ) : Component{ - BodyText{}, - content.index, - content.label, - content.unit + BlockData{}, + this->index(), + this->label(), + this->unit() + }, + Content{ + index, + label, + unit } { Component::finish(); @@ -134,12 +133,12 @@ class Axis : public Component { // copy Axis(const Axis &other) : Component{ - other, - content.index, - content.label, - content.unit + other.baseBlockData(), + this->index(), + this->label(), + this->unit() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -147,12 +146,12 @@ class Axis : public Component { // move Axis(Axis &&other) : Component{ - other, - content.index, - content.label, - content.unit + other.baseBlockData(), + this->index(), + this->label(), + this->unit() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -160,36 +159,15 @@ class Axis : public Component { // from node Axis(const Node &node) : Component{ - BodyText{}, - content.index, - content.label, - content.unit + BlockData{}, + this->index(), + this->label(), + this->unit() } { Component::finish(node); } - // from fields - explicit Axis( - const std::optional &index, - const std::optional &label, - const std::optional &unit - ) : - Component{ - BodyText{}, - content.index, - content.label, - content.unit - }, - content{ - index, - label, - unit - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/containers/Axis/src/custom.hpp b/src/GNDStk/v1.9/containers/Axis/src/custom.hpp index 0dd9bcbf2..94ea19739 100644 --- a/src/GNDStk/v1.9/containers/Axis/src/custom.hpp +++ b/src/GNDStk/v1.9/containers/Axis/src/custom.hpp @@ -1,18 +1,30 @@ + private: - static inline helpMap help = { +static inline helpMap help = { + + { + "", + "A GNDS 1.9 basic container component: " + "an axis with an index, label and\n" + "optional unit\n\n" + "This component in used in the axes node, " + "which in turn is used in most\n" + "functional containers." + }, + + { + "constructor", + "Initialise the axis component\n\n" + "Arguments:\n" + " self the axis component\n" + " index the index of the axis component\n" + " label the label of the axis component\n" + " unit the unit of the axis component\n" + }, + + { "index", "The index of the axis component" }, + { "label", "The label of the axis component" }, + { "unit", "The unit of the axis component" } - { "", "A GNDS 1.9 basic container component: an axis with an index, label and\n" - "optional unit\n\n" - "This component in used in the axes node, which in turn is used in most\n" - "functional containers." }, - { "constructor", "Initialise the axis component\n\n" - "Arguments:\n" - " self the axis component\n" - " index the index of the axis component\n" - " label the label of the axis component\n" - " unit the unit of the axis component\n" }, - { "index", "The index of the axis component" }, - { "label", "The label of the axis component" }, - { "unit", "The unit of the axis component" } - }; +}; diff --git a/src/GNDStk/v1.9/containers/Axis/test/Axis.test.cpp b/src/GNDStk/v1.9/containers/Axis/test/Axis.test.cpp index dd5adb194..7fa31ba8b 100644 --- a/src/GNDStk/v1.9/containers/Axis/test/Axis.test.cpp +++ b/src/GNDStk/v1.9/containers/Axis/test/Axis.test.cpp @@ -21,7 +21,7 @@ SCENARIO( "Axis" ) { WHEN( "autogenerated constructor: the data is given explicitly" ) { - unsigned int index = 1; + unsigned index = 1; std::string label = "energy_in"; std::string unit = "eV"; @@ -124,8 +124,7 @@ SCENARIO( "Axis" ) { std::string chunk() { return -R"***( -)***"; +R"***()***"; } void verifyChunk( const Axis& component ) { @@ -147,6 +146,5 @@ std::string invalidName() { // wrong name for the node return -R"***( -)***"; +R"***()***"; } diff --git a/src/GNDStk/v1.9/containers/Grid.hpp b/src/GNDStk/v1.9/containers/Grid.hpp index bf20dbf93..51ccbe038 100644 --- a/src/GNDStk/v1.9/containers/Grid.hpp +++ b/src/GNDStk/v1.9/containers/Grid.hpp @@ -2,23 +2,17 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_GRID -#define NJOY_GNDSTK_V1_9_CONTAINERS_GRID +#ifndef GNDSTK_V1_9_CONTAINERS_GRID +#define GNDSTK_V1_9_CONTAINERS_GRID -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies -#include "GNDStk/v1.9/containers/Link.hpp" +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/containers/Values.hpp" +#include "GNDStk/v1.9/containers/Link.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -27,11 +21,11 @@ using namespace njoy::GNDStk::core; namespace containers { -class Grid : public Component { +class Grid : public Component { using link_values_t = std::variant< - containers::Link, - containers::Values + containers::Values, + containers::Link >; // ------------------------ @@ -40,13 +34,13 @@ class Grid : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "Grid"; } - static auto GNDSName() { return "grid"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "Grid"; } + static auto FIELD() { return "grid"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -62,7 +56,7 @@ class Grid : public Component { / Meta<>("unit") | // children link_values_t{} - / --(Child<>("link") || Child<>("values")) + / --(Child<>("values") || Child<>("link")) ; } @@ -92,7 +86,7 @@ class Grid : public Component { std::optional unit; // children - variant link_values_t link_values; - } content; + } Content; // ------------------------ // Getters @@ -101,45 +95,39 @@ class Grid : public Component { // index const std::optional &index() const - { return content.index; } + { return Content.index; } std::optional &index() - { return content.index; } + { return Content.index; } // interpolation const Defaulted &interpolation() const - { return content.interpolation; } + { return Content.interpolation; } Defaulted &interpolation() - { return content.interpolation; } + { return Content.interpolation; } // label const std::optional &label() const - { return content.label; } + { return Content.label; } std::optional &label() - { return content.label; } + { return Content.label; } // style const std::optional &style() const - { return content.style; } + { return Content.style; } std::optional &style() - { return content.style; } + { return Content.style; } // unit const std::optional &unit() const - { return content.unit; } + { return Content.unit; } std::optional &unit() - { return content.unit; } + { return Content.unit; } // link_values const link_values_t &link_values() const - { return content.link_values; } + { return Content.link_values; } link_values_t &link_values() - { return content.link_values; } - - // link - const containers::Link *link() const - { return getter(link_values(), "link"); } - containers::Link *link() - { return getter(link_values(), "link"); } + { return Content.link_values; } // values const containers::Values *values() const @@ -147,6 +135,12 @@ class Grid : public Component { containers::Values *values() { return getter(link_values(), "values"); } + // link + const containers::Link *link() const + { return getter(link_values(), "link"); } + containers::Link *link() + { return getter(link_values(), "link"); } + // ------------------------ // Setters // non-const @@ -159,9 +153,9 @@ class Grid : public Component { // interpolation(value) Grid &interpolation(const Defaulted &obj) - { content.interpolation = obj; return *this; } + { interpolation() = obj; return *this; } Grid &interpolation(const std::optional &obj) - { content.interpolation = obj; return *this; } + { interpolation() = obj; return *this; } // label(value) Grid &label(const std::optional &obj) @@ -179,28 +173,50 @@ class Grid : public Component { Grid &link_values(const link_values_t &obj) { link_values() = obj; return *this; } - // link(value) - Grid &link(const std::optional &obj) - { if (obj) link_values(obj.value()); return *this; } - // values(value) Grid &values(const std::optional &obj) { if (obj) link_values(obj.value()); return *this; } + // link(value) + Grid &link(const std::optional &obj) + { if (obj) link_values(obj.value()); return *this; } + // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Grid() : + // default, and from fields + // std::optional replaces Defaulted; this class knows the default(s) + explicit Grid( + const std::optional &index = + std::optional{}, + const std::optional &interpolation = + std::optional{}, + const std::optional &label = + std::optional{}, + const std::optional &style = + std::optional{}, + const std::optional &unit = + std::optional{}, + const link_values_t &link_values = + link_values_t{} + ) : Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.style, - content.unit, - content.link_values + BlockData{}, + this->index(), + this->interpolation(), + this->label(), + this->style(), + this->unit(), + this->link_values() + }, + Content{ + index, + Defaulted(defaults.interpolation,interpolation), + label, + style, + unit, + link_values } { Component::finish(); @@ -209,15 +225,15 @@ class Grid : public Component { // copy Grid(const Grid &other) : Component{ - other, - content.index, - content.interpolation, - content.label, - content.style, - content.unit, - content.link_values + other.baseBlockData(), + this->index(), + this->interpolation(), + this->label(), + this->style(), + this->unit(), + this->link_values() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -225,15 +241,15 @@ class Grid : public Component { // move Grid(Grid &&other) : Component{ - other, - content.index, - content.interpolation, - content.label, - content.style, - content.unit, - content.link_values + other.baseBlockData(), + this->index(), + this->interpolation(), + this->label(), + this->style(), + this->unit(), + this->link_values() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -241,49 +257,18 @@ class Grid : public Component { // from node Grid(const Node &node) : Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.style, - content.unit, - content.link_values + BlockData{}, + this->index(), + this->interpolation(), + this->label(), + this->style(), + this->unit(), + this->link_values() } { Component::finish(node); } - // from fields - // std::optional replaces Defaulted; this class knows the default(s) - explicit Grid( - const std::optional &index, - const std::optional &interpolation, - const std::optional &label, - const std::optional &style, - const std::optional &unit, - const link_values_t &link_values - ) : - Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.style, - content.unit, - content.link_values - }, - content{ - index, - Defaulted(defaults.interpolation,interpolation), - label, - style, - unit, - link_values - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/containers/Grid/test/Grid.test.cpp b/src/GNDStk/v1.9/containers/Grid/test/Grid.test.cpp index 078ac9417..e15392688 100644 --- a/src/GNDStk/v1.9/containers/Grid/test/Grid.test.cpp +++ b/src/GNDStk/v1.9/containers/Grid/test/Grid.test.cpp @@ -25,7 +25,7 @@ SCENARIO( "Grid" ) { WHEN( "autogenerated constructor: the data is given explicitly" ) { - unsigned int index = 2; + unsigned index = 2; std::string label = "row_energy_bounds"; std::string unit = "eV"; enums::GridStyle style = enums::GridStyle::boundaries; @@ -74,7 +74,7 @@ SCENARIO( "Grid" ) { WHEN( "autogenerated constructor: the data is given explicitly" ) { - unsigned int index = 1; + unsigned index = 1; std::string label = "column_energy_bounds"; std::string unit = "eV"; enums::GridStyle style = enums::GridStyle::link; @@ -181,9 +181,8 @@ std::string chunk() { return R"***( - 1e-05 2e+07 - -)***"; + 1e-05 2e+07 +)***"; } void verifyChunk( const Grid& component ) { @@ -220,8 +219,7 @@ std::string chunkWithLink() { return R"***( - -)***"; +)***"; } void verifyChunkWithLink( const Grid& component ) { @@ -251,6 +249,5 @@ std::string invalidName() { return R"***( - -)***"; +)***"; } diff --git a/src/GNDStk/v1.9/containers/Link.hpp b/src/GNDStk/v1.9/containers/Link.hpp index 0367513d2..d6f6ec6a3 100644 --- a/src/GNDStk/v1.9/containers/Link.hpp +++ b/src/GNDStk/v1.9/containers/Link.hpp @@ -2,19 +2,15 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_LINK -#define NJOY_GNDSTK_V1_9_CONTAINERS_LINK +#ifndef GNDSTK_V1_9_CONTAINERS_LINK +#define GNDSTK_V1_9_CONTAINERS_LINK -// core interface -#include "GNDStk.hpp" +#include "GNDStk/v1.9/key.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -23,8 +19,7 @@ using namespace njoy::GNDStk::core; namespace containers { -class Link : public Component { - +class Link : public Component { // ------------------------ // For Component @@ -32,13 +27,13 @@ class Link : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "Link"; } - static auto GNDSName() { return "link"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "Link"; } + static auto FIELD() { return "link"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -51,14 +46,6 @@ class Link : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -66,7 +53,7 @@ class Link : public Component { struct { // metadata std::string href; - } content; + } Content; // ------------------------ // Getters @@ -75,9 +62,9 @@ class Link : public Component { // href const std::string &href() const - { return content.href; } + { return Content.href; } std::string &href() - { return content.href; } + { return Content.href; } // ------------------------ // Setters @@ -90,14 +77,20 @@ class Link : public Component { { href() = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Link() : + // default, and from fields + explicit Link( + const std::string &href = + std::string{} + ) : Component{ - BodyText{}, - content.href + BlockData{}, + this->href() + }, + Content{ + href } { Component::finish(); @@ -106,10 +99,10 @@ class Link : public Component { // copy Link(const Link &other) : Component{ - other, - content.href + other.baseBlockData(), + this->href() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -117,10 +110,10 @@ class Link : public Component { // move Link(Link &&other) : Component{ - other, - content.href + other.baseBlockData(), + this->href() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -128,28 +121,13 @@ class Link : public Component { // from node Link(const Node &node) : Component{ - BodyText{}, - content.href + BlockData{}, + this->href() } { Component::finish(node); } - // from fields - explicit Link( - const std::string &href - ) : - Component{ - BodyText{}, - content.href - }, - content{ - href - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/containers/Link/test/Link.test.cpp b/src/GNDStk/v1.9/containers/Link/test/Link.test.cpp index a0c5d544c..12f9a1d27 100644 --- a/src/GNDStk/v1.9/containers/Link/test/Link.test.cpp +++ b/src/GNDStk/v1.9/containers/Link/test/Link.test.cpp @@ -122,8 +122,7 @@ SCENARIO( "Link" ) { std::string chunk() { return -R"***( -)***"; +R"***()***"; } void verifyChunk( const Link& component ) { @@ -135,6 +134,5 @@ std::string invalidName() { // wrong name for the node return -R"***( -)***"; +R"***()***"; } diff --git a/src/GNDStk/v1.9/containers/Regions1d.hpp b/src/GNDStk/v1.9/containers/Regions1d.hpp index c1a3c1002..43e48319b 100644 --- a/src/GNDStk/v1.9/containers/Regions1d.hpp +++ b/src/GNDStk/v1.9/containers/Regions1d.hpp @@ -2,23 +2,17 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_REGIONS1D -#define NJOY_GNDSTK_V1_9_CONTAINERS_REGIONS1D +#ifndef GNDSTK_V1_9_CONTAINERS_REGIONS1D +#define GNDSTK_V1_9_CONTAINERS_REGIONS1D -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies -#include "GNDStk/v1.9/containers/XYs1d.hpp" +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/containers/Axes.hpp" +#include "GNDStk/v1.9/containers/XYs1d.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -27,8 +21,7 @@ using namespace njoy::GNDStk::core; namespace containers { -class Regions1d : public Component { - +class Regions1d : public Component { // ------------------------ // For Component @@ -36,13 +29,13 @@ class Regions1d : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "Regions1d"; } - static auto GNDSName() { return "regions1d"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "Regions1d"; } + static auto FIELD() { return "regions1d"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -51,10 +44,10 @@ class Regions1d : public Component { std::optional{} / Meta<>("outerDomainValue") | // children - containers::XYs1d{} - / ++Child<>("XYs1d") | std::optional{} - / --Child<>("axes") + / --Child<>("axes") | + containers::XYs1d{} + / ++Child<>("XYs1d") ; } @@ -62,14 +55,6 @@ class Regions1d : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -79,9 +64,9 @@ class Regions1d : public Component { std::optional label; std::optional outerDomainValue; // children - std::vector XYs1d; std::optional axes; - } content; + std::vector XYs1d; + } Content; // ------------------------ // Getters @@ -90,39 +75,35 @@ class Regions1d : public Component { // label const std::optional &label() const - { return content.label; } + { return Content.label; } std::optional &label() - { return content.label; } + { return Content.label; } // outerDomainValue const std::optional &outerDomainValue() const - { return content.outerDomainValue; } + { return Content.outerDomainValue; } std::optional &outerDomainValue() - { return content.outerDomainValue; } + { return Content.outerDomainValue; } + + // axes + const std::optional &axes() const + { return Content.axes; } + std::optional &axes() + { return Content.axes; } // XYs1d const std::vector &XYs1d() const - { return content.XYs1d; } + { return Content.XYs1d; } std::vector &XYs1d() - { return content.XYs1d; } - - // XYs1d(index) - const containers::XYs1d &XYs1d(const std::size_t index) const - { return getter(XYs1d(), index, "XYs1d"); } - containers::XYs1d &XYs1d(const std::size_t index) - { return getter(XYs1d(), index, "XYs1d"); } + { return Content.XYs1d; } - // XYs1d(label) - const containers::XYs1d &XYs1d(const std::string &label) const - { return getter(XYs1d(), label, "XYs1d"); } - containers::XYs1d &XYs1d(const std::string &label) - { return getter(XYs1d(), label, "XYs1d"); } - - // axes - const std::optional &axes() const - { return content.axes; } - std::optional &axes() - { return content.axes; } + // XYs1d(index/label/Lookup) + template> + decltype(auto) XYs1d(const KEY &key) const + { return getter(XYs1d(), key, "XYs1d"); } + template> + decltype(auto) XYs1d(const KEY &key) + { return getter(XYs1d(), key, "XYs1d"); } // ------------------------ // Setters @@ -138,42 +119,52 @@ class Regions1d : public Component { Regions1d &outerDomainValue(const std::optional &obj) { outerDomainValue() = obj; return *this; } - // XYs1d(value) + // axes(value) + Regions1d &axes(const std::optional &obj) + { axes() = obj; return *this; } + + // XYs1d(vector): replace vector Regions1d &XYs1d(const std::vector &obj) { XYs1d() = obj; return *this; } - // XYs1d(index,value) - Regions1d &XYs1d( - const std::size_t index, - const containers::XYs1d &obj - ) { - XYs1d(index) = obj; return *this; - } + // XYs1d(scalar): vector push_back + Regions1d &XYs1d(const containers::XYs1d &obj) + { setter(XYs1d(), obj); return *this; } - // XYs1d(label,value) - Regions1d &XYs1d( - const std::string &label, - const containers::XYs1d &obj - ) { - XYs1d(label) = obj; return *this; + // XYs1d(index/label/Lookup, value): replace vector entry + template> + Regions1d &XYs1d(const KEY &key, const containers::XYs1d &obj) + { + XYs1d(key) = obj; return *this; } - // axes(value) - Regions1d &axes(const std::optional &obj) - { axes() = obj; return *this; } - // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Regions1d() : + // default, and from fields + explicit Regions1d( + const std::optional &label = + std::optional{}, + const std::optional &outerDomainValue = + std::optional{}, + const std::optional &axes = + std::optional{}, + const std::vector &XYs1d = + std::vector{} + ) : Component{ - BodyText{}, - content.label, - content.outerDomainValue, - content.XYs1d, - content.axes + BlockData{}, + this->label(), + this->outerDomainValue(), + this->axes(), + this->XYs1d() + }, + Content{ + label, + outerDomainValue, + axes, + XYs1d } { Component::finish(); @@ -182,13 +173,13 @@ class Regions1d : public Component { // copy Regions1d(const Regions1d &other) : Component{ - other, - content.label, - content.outerDomainValue, - content.XYs1d, - content.axes + other.baseBlockData(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->XYs1d() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -196,13 +187,13 @@ class Regions1d : public Component { // move Regions1d(Regions1d &&other) : Component{ - other, - content.label, - content.outerDomainValue, - content.XYs1d, - content.axes + other.baseBlockData(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->XYs1d() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -210,40 +201,16 @@ class Regions1d : public Component { // from node Regions1d(const Node &node) : Component{ - BodyText{}, - content.label, - content.outerDomainValue, - content.XYs1d, - content.axes + BlockData{}, + this->label(), + this->outerDomainValue(), + this->axes(), + this->XYs1d() } { Component::finish(node); } - // from fields - explicit Regions1d( - const std::optional &label, - const std::optional &outerDomainValue, - const std::vector &XYs1d, - const std::optional &axes - ) : - Component{ - BodyText{}, - content.label, - content.outerDomainValue, - content.XYs1d, - content.axes - }, - content{ - label, - outerDomainValue, - XYs1d, - axes - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/containers/Regions1d/test/Regions1d.test.cpp b/src/GNDStk/v1.9/containers/Regions1d/test/Regions1d.test.cpp index f8d93ec35..f46acc7f7 100644 --- a/src/GNDStk/v1.9/containers/Regions1d/test/Regions1d.test.cpp +++ b/src/GNDStk/v1.9/containers/Regions1d/test/Regions1d.test.cpp @@ -28,21 +28,23 @@ SCENARIO( "Regions1d" ) { WHEN( "autogenerated constructor: the data is given explicitly" ) { Regions1d chunk( - std::nullopt, // optional label - std::nullopt, // optional outer domain value + std::nullopt, // optional label + std::nullopt, // optional outer domain value + Axes( std::nullopt, + std::vector< std::variant< Axis, Grid > >{ + Axis( 1, "energy_in", "eV" ), + Axis( 0, "crossSection", "b" ) } ), // optional axes std::vector< XYs1d >{ XYs1d( 0, std::nullopt, std::nullopt, std::nullopt, std::nullopt, - Values( std::vector< double >{ 0.0253, 4.34057, 30000, 1.62386 } ) ), + Values( std::vector< double >{ + 0.0253, 4.34057, 30000, 1.62386 } ) ), XYs1d( 1, std::nullopt, std::nullopt, std::nullopt, std::nullopt, - Values( std::vector< double >{ 30000, 1.65691, 2e+7, 2.35696 } ) ) - }, // vector of 1D functions - Axes( std::nullopt, - std::vector< std::variant< Axis, Grid > >{ - Axis( 1, "energy_in", "eV" ), - Axis( 0, "crossSection", "b" ) } ) // optional axes + Values( std::vector< double >{ + 30000, 1.65691, 2e+7, 2.35696 } ) ) + } // vector of 1D functions ); THEN( "the component can be constructed and members can be tested" ) { @@ -143,18 +145,17 @@ std::string chunk() { return R"***( - - 0.0253 4.34057 30000 1.62386 - - - 30000 1.65691 2e+07 2.35696 - - -)***"; + + 0.0253 4.34057 30000 1.62386 + + + 30000 1.65691 2e+07 2.35696 + +)***"; } void verifyChunk( const Regions1d& component ) { @@ -166,7 +167,8 @@ void verifyChunk( const Regions1d& component ) { // axes data CHECK( 2 == component.axes().value().axis_grid().size() ); - decltype(auto) axis0 = std::get< Axis >( component.axes().value().axis_grid()[0] ); + decltype(auto) axis0 = + std::get< Axis >( component.axes().value().axis_grid()[0] ); CHECK( std::nullopt != axis0.index() ); CHECK( std::nullopt != axis0.label() ); CHECK( std::nullopt != axis0.unit() ); @@ -174,7 +176,8 @@ void verifyChunk( const Regions1d& component ) { CHECK( "crossSection" == axis0.label().value() ); CHECK( "b" == axis0.unit().value() ); - decltype(auto) axis1 = std::get< Axis >( component.axes().value().axis_grid()[1] ); + decltype(auto) axis1 = + std::get< Axis >( component.axes().value().axis_grid()[1] ); CHECK( std::nullopt != axis1.index() ); CHECK( std::nullopt != axis1.label() ); CHECK( std::nullopt != axis1.unit() ); @@ -224,15 +227,14 @@ std::string invalidName() { return R"***( - 0.0253 4.34057 30000 1.62386 + 0.0253 4.34057 30000 1.62386 - 30000 1.65691 2e+07 2.35696 + 30000 1.65691 2e+07 2.35696 - -)***"; +)***"; } diff --git a/src/GNDStk/v1.9/containers/Values.hpp b/src/GNDStk/v1.9/containers/Values.hpp index 257ea0d1e..84a6c66d7 100644 --- a/src/GNDStk/v1.9/containers/Values.hpp +++ b/src/GNDStk/v1.9/containers/Values.hpp @@ -2,19 +2,15 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_VALUES -#define NJOY_GNDSTK_V1_9_CONTAINERS_VALUES +#ifndef GNDSTK_V1_9_CONTAINERS_VALUES +#define GNDSTK_V1_9_CONTAINERS_VALUES -// core interface -#include "GNDStk.hpp" +#include "GNDStk/v1.9/key.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -23,8 +19,7 @@ using namespace njoy::GNDStk::core; namespace containers { -class Values : public Component { - +class Values : public Component { // ------------------------ // For Component @@ -32,29 +27,29 @@ class Values : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "Values"; } - static auto GNDSName() { return "values"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "Values"; } + static auto FIELD() { return "values"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata - std::optional{} - / Meta<>("length") | + Defaulted{"double"} + / Meta<>("valueType") | Defaulted{0} / Meta<>("start") | - Defaulted{"double"} - / Meta<>("valueType") + std::optional{} + / Meta<>("length") ; } public: using Component::construct; - using BodyText::operator=; + using BlockData::operator=; // ------------------------ // Relevant defaults @@ -62,8 +57,8 @@ class Values : public Component { // ------------------------ static inline const struct Defaults { - static inline const int start = 0; static inline const std::string valueType = "double"; + static inline const int start = 0; } defaults; // ------------------------ @@ -72,33 +67,33 @@ class Values : public Component { struct { // metadata - mutable std::optional length; - mutable Defaulted start{0}; mutable Defaulted valueType{"double"}; - } content; + mutable Defaulted start{0}; + mutable std::optional length; + } Content; // ------------------------ // Getters // const and non-const // ------------------------ - // length - const std::optional &length() const - { return content.length; } - std::optional &length() - { return content.length; } + // valueType + const Defaulted &valueType() const + { return Content.valueType; } + Defaulted &valueType() + { return Content.valueType; } // start const Defaulted &start() const - { return content.start; } + { return Content.start; } Defaulted &start() - { return content.start; } + { return Content.start; } - // valueType - const Defaulted &valueType() const - { return content.valueType; } - Defaulted &valueType() - { return content.valueType; } + // length + const std::optional &length() const + { return Content.length; } + std::optional &length() + { return Content.length; } // ------------------------ // Setters @@ -106,33 +101,46 @@ class Values : public Component { // All return *this // ------------------------ - // length(value) - Values &length(const std::optional &obj) - { BodyText::length(length() = obj); return *this; } + // valueType(value) + Values &valueType(const Defaulted &obj) + { BlockData::valueType(valueType() = obj); return *this; } + Values &valueType(const std::optional &obj) + { BlockData::valueType(valueType() = obj); return *this; } // start(value) Values &start(const Defaulted &obj) - { BodyText::start(content.start = obj); return *this; } + { BlockData::start(start() = obj); return *this; } Values &start(const std::optional &obj) - { BodyText::start(content.start = obj); return *this; } + { BlockData::start(start() = obj); return *this; } - // valueType(value) - Values &valueType(const Defaulted &obj) - { BodyText::valueType(content.valueType = obj); return *this; } - Values &valueType(const std::optional &obj) - { BodyText::valueType(content.valueType = obj); return *this; } + // length(value) + Values &length(const std::optional &obj) + { BlockData::length(length() = obj); return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Values() : + // default, and from fields + // std::optional replaces Defaulted; this class knows the default(s) + explicit Values( + const std::optional &valueType = + std::optional{}, + const std::optional &start = + std::optional{}, + const std::optional &length = + std::optional{} + ) : Component{ - BodyText{}, - content.length, - content.start, - content.valueType + BlockData{}, + this->valueType(), + this->start(), + this->length() + }, + Content{ + Defaulted(defaults.valueType,valueType), + Defaulted(defaults.start,start), + length } { Component::finish(); @@ -141,12 +149,12 @@ class Values : public Component { // copy Values(const Values &other) : Component{ - other, - content.length, - content.start, - content.valueType + other.baseBlockData(), + this->valueType(), + this->start(), + this->length() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -154,12 +162,12 @@ class Values : public Component { // move Values(Values &&other) : Component{ - other, - content.length, - content.start, - content.valueType + other.baseBlockData(), + this->valueType(), + this->start(), + this->length() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -167,45 +175,23 @@ class Values : public Component { // from node Values(const Node &node) : Component{ - BodyText{}, - content.length, - content.start, - content.valueType + BlockData{}, + this->valueType(), + this->start(), + this->length() } { Component::finish(node); } - // from fields - // std::optional replaces Defaulted; this class knows the default(s) - explicit Values( - const std::optional &length, - const std::optional &start, - const std::optional &valueType - ) : - Component{ - BodyText{}, - content.length, - content.start, - content.valueType - }, - content{ - length, - Defaulted(defaults.start,start), - Defaulted(defaults.valueType,valueType) - } - { - Component::finish(); - } - // from vector - template>> + template>> Values(const std::vector &vector) : Component{ - BodyText{}, - content.length, - content.start, - content.valueType + BlockData{}, + this->valueType(), + this->start(), + this->length() } { Component::finish(vector); diff --git a/src/GNDStk/v1.9/containers/Values/src/custom.hpp b/src/GNDStk/v1.9/containers/Values/src/custom.hpp index 562142c21..6c58a1714 100644 --- a/src/GNDStk/v1.9/containers/Values/src/custom.hpp +++ b/src/GNDStk/v1.9/containers/Values/src/custom.hpp @@ -44,10 +44,10 @@ const std::optional< std::string >& valueType, const std::vector< T >& values ) : Component{ - BodyText{}, - content.length, - content.start, - content.valueType + BlockData{}, + this->length(), + this->start(), + this->valueType() } { diff --git a/src/GNDStk/v1.9/containers/Values/test/Values.test.cpp b/src/GNDStk/v1.9/containers/Values/test/Values.test.cpp index d8e132d5d..bf9a2a95b 100644 --- a/src/GNDStk/v1.9/containers/Values/test/Values.test.cpp +++ b/src/GNDStk/v1.9/containers/Values/test/Values.test.cpp @@ -216,8 +216,7 @@ SCENARIO( "Values" ) { std::string chunk() { return -R"***(2500 8.9172 2550 8.9155 -)***"; +R"***(2500 8.9172 2550 8.9155)***"; } void verifyChunk( const Values& component ) { @@ -238,8 +237,7 @@ void verifyChunk( const Values& component ) { std::string chunkInts() { return -R"***(2500 9 2550 9 -)***"; +R"***(2500 9 2550 9)***"; } void verifyChunkInts( const Values& component ) { @@ -260,8 +258,7 @@ void verifyChunkInts( const Values& component ) { std::string chunkStrings() { return -R"***(2500 8.9172 2550 8.9155 -)***"; +R"***(2500 8.9172 2550 8.9155)***"; } void verifyChunkStrings( const Values& component ) { @@ -283,6 +280,5 @@ std::string invalidName() { // wrong name for the node return -R"***(2500 8.9172 2550 8.9155 -)***"; +R"***(2500 8.9172 2550 8.9155)***"; } diff --git a/src/GNDStk/v1.9/containers/XYs1d.hpp b/src/GNDStk/v1.9/containers/XYs1d.hpp index 6cf404257..7239381b3 100644 --- a/src/GNDStk/v1.9/containers/XYs1d.hpp +++ b/src/GNDStk/v1.9/containers/XYs1d.hpp @@ -2,13 +2,10 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_CONTAINERS_XYS1D -#define NJOY_GNDSTK_V1_9_CONTAINERS_XYS1D +#ifndef GNDSTK_V1_9_CONTAINERS_XYS1D +#define GNDSTK_V1_9_CONTAINERS_XYS1D -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/containers/Axes.hpp" #include "GNDStk/v1.9/containers/Values.hpp" @@ -16,9 +13,6 @@ namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // containers:: @@ -27,8 +21,7 @@ using namespace njoy::GNDStk::core; namespace containers { -class XYs1d : public Component { - +class XYs1d : public Component { // ------------------------ // For Component @@ -36,13 +29,13 @@ class XYs1d : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "containers"; } - static auto className() { return "XYs1d"; } - static auto GNDSName() { return "XYs1d"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "containers"; } + static auto CLASS() { return "XYs1d"; } + static auto FIELD() { return "XYs1d"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -88,7 +81,7 @@ class XYs1d : public Component { // children std::optional axes; containers::Values values; - } content; + } Content; // ------------------------ // Getters @@ -97,39 +90,39 @@ class XYs1d : public Component { // index const std::optional &index() const - { return content.index; } + { return Content.index; } std::optional &index() - { return content.index; } + { return Content.index; } // interpolation const Defaulted &interpolation() const - { return content.interpolation; } + { return Content.interpolation; } Defaulted &interpolation() - { return content.interpolation; } + { return Content.interpolation; } // label const std::optional &label() const - { return content.label; } + { return Content.label; } std::optional &label() - { return content.label; } + { return Content.label; } // outerDomainValue const std::optional &outerDomainValue() const - { return content.outerDomainValue; } + { return Content.outerDomainValue; } std::optional &outerDomainValue() - { return content.outerDomainValue; } + { return Content.outerDomainValue; } // axes const std::optional &axes() const - { return content.axes; } + { return Content.axes; } std::optional &axes() - { return content.axes; } + { return Content.axes; } // values const containers::Values &values() const - { return content.values; } + { return Content.values; } containers::Values &values() - { return content.values; } + { return Content.values; } // ------------------------ // Setters @@ -143,9 +136,9 @@ class XYs1d : public Component { // interpolation(value) XYs1d &interpolation(const Defaulted &obj) - { content.interpolation = obj; return *this; } + { interpolation() = obj; return *this; } XYs1d &interpolation(const std::optional &obj) - { content.interpolation = obj; return *this; } + { interpolation() = obj; return *this; } // label(value) XYs1d &label(const std::optional &obj) @@ -164,19 +157,41 @@ class XYs1d : public Component { { values() = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - XYs1d() : + // default, and from fields + // std::optional replaces Defaulted; this class knows the default(s) + explicit XYs1d( + const std::optional &index = + std::optional{}, + const std::optional &interpolation = + std::optional{}, + const std::optional &label = + std::optional{}, + const std::optional &outerDomainValue = + std::optional{}, + const std::optional &axes = + std::optional{}, + const containers::Values &values = + containers::Values{} + ) : Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.outerDomainValue, - content.axes, - content.values + BlockData{}, + this->index(), + this->interpolation(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->values() + }, + Content{ + index, + Defaulted(defaults.interpolation,interpolation), + label, + outerDomainValue, + axes, + values } { Component::finish(); @@ -185,15 +200,15 @@ class XYs1d : public Component { // copy XYs1d(const XYs1d &other) : Component{ - other, - content.index, - content.interpolation, - content.label, - content.outerDomainValue, - content.axes, - content.values + other.baseBlockData(), + this->index(), + this->interpolation(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->values() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -201,15 +216,15 @@ class XYs1d : public Component { // move XYs1d(XYs1d &&other) : Component{ - other, - content.index, - content.interpolation, - content.label, - content.outerDomainValue, - content.axes, - content.values + other.baseBlockData(), + this->index(), + this->interpolation(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->values() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -217,49 +232,18 @@ class XYs1d : public Component { // from node XYs1d(const Node &node) : Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.outerDomainValue, - content.axes, - content.values + BlockData{}, + this->index(), + this->interpolation(), + this->label(), + this->outerDomainValue(), + this->axes(), + this->values() } { Component::finish(node); } - // from fields - // std::optional replaces Defaulted; this class knows the default(s) - explicit XYs1d( - const std::optional &index, - const std::optional &interpolation, - const std::optional &label, - const std::optional &outerDomainValue, - const std::optional &axes, - const containers::Values &values - ) : - Component{ - BodyText{}, - content.index, - content.interpolation, - content.label, - content.outerDomainValue, - content.axes, - content.values - }, - content{ - index, - Defaulted(defaults.interpolation,interpolation), - label, - outerDomainValue, - axes, - values - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/containers/XYs1d/test/XYs1d.test.cpp b/src/GNDStk/v1.9/containers/XYs1d/test/XYs1d.test.cpp index 05c427b6a..128557a00 100644 --- a/src/GNDStk/v1.9/containers/XYs1d/test/XYs1d.test.cpp +++ b/src/GNDStk/v1.9/containers/XYs1d/test/XYs1d.test.cpp @@ -31,7 +31,8 @@ SCENARIO( "XYs1d" ) { std::vector< std::variant< Axis, Grid > >{ Axis( 1, "energy_in", "eV" ), Axis( 0, "crossSection", "b" ) } ), - Values( std::vector< double >{ 1e-05, 1., 2.53e-2, 2., 2.5e+3, 3. } ) ); + Values( std::vector< double > + { 1e-05, 1., 2.53e-2, 2., 2.5e+3, 3. } ) ); THEN( "the component can be constructed and members can be tested" ) { @@ -135,9 +136,8 @@ R"***( - 1e-05 1 0.0253 2 2500 3 - -)***"; + 1e-05 1 0.0253 2 2500 3 +)***"; } void verifyChunk( const XYs1d& component ) { @@ -150,7 +150,8 @@ void verifyChunk( const XYs1d& component ) { CHECK( enums::Interpolation::linlin == component.interpolation() ); // axes data - decltype(auto) axis0 = std::get< Axis >( component.axes().value().axis_grid()[0] ); + decltype(auto) axis0 = + std::get< Axis >( component.axes().value().axis_grid()[0] ); CHECK( std::nullopt != axis0.index() ); CHECK( std::nullopt != axis0.label() ); @@ -160,7 +161,8 @@ void verifyChunk( const XYs1d& component ) { CHECK( "crossSection" == axis0.label().value() ); CHECK( "b" == axis0.unit().value() ); - decltype(auto) axis1 = std::get< Axis >( component.axes().value().axis_grid()[1] ); + decltype(auto) axis1 = + std::get< Axis >( component.axes().value().axis_grid()[1] ); CHECK( std::nullopt != axis1.index() ); CHECK( std::nullopt != axis1.label() ); @@ -196,6 +198,5 @@ R"***( 1e-05 1. 2.53e-2 2. 2.5e+3 3. - -)***"; +)***"; } diff --git a/src/GNDStk/v1.9/key.hpp b/src/GNDStk/v1.9/key.hpp index 214b239e0..6fbb35d80 100644 --- a/src/GNDStk/v1.9/key.hpp +++ b/src/GNDStk/v1.9/key.hpp @@ -2,73 +2,62 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -/* -This file contains Meta and Child objects for metadata and child nodes in the -current GNDS version. These may prove to be useful if you wish to use the Core -Interface in conjunction with the autogenerated classes for this GNDS version. - -Within the outer njoy::GNDStk::version namespace below, the remaining namespace -arrangement was chosen to make the use of these objects smooth and logical. - -Meta and Child objects are collectively called "keys." Meta keys are placed -into key::meta. Child keys correspond to autogenerated classes, each of which -is already in some namespace; we thus use theNamespace::key::child::. That way, -an autogenerated class [ns::Foo] has [ns::key::foo] as its Child object, and -a "using namespace ns" allows the class and the Child object to be [Foo] and -[key::foo], respectively. (If we reordered ns:: and key::, that wouldn't work.) - -Within key::, we use meta:: and child:: around Meta and Child objects, just in -case there exist any identical GNDS metadata names and child-node names. (That -can, in fact, happen). The "using namespace meta" and "using namespace child" -directives then make the Meta<> and Child<> objects appear directly in key::, -so that "meta::" and "child::" are needed only to disambiguate identical names. -*/ - -#ifndef NJOY_GNDSTK_V1_9_KEY -#define NJOY_GNDSTK_V1_9_KEY +#ifndef GNDSTK_V1_9_KEY +#define GNDSTK_V1_9_KEY + +// GNDStk Core Interface +#include "GNDStk.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { +using namespace njoy::GNDStk; + // ----------------------------------------------------------------------------- -// key::meta:: +// meta:: // ----------------------------------------------------------------------------- -namespace key { namespace meta { -inline const Meta<> ENDF_MT("ENDF_MT"); -inline const Meta<> evaluation("evaluation"); -inline const Meta<> fissionGenre("fissionGenre"); -inline const Meta<> format("format"); -inline const Meta<> href("href"); -inline const Meta<> index("index"); -inline const Meta<> interaction("interaction"); -inline const Meta<> interpolation("interpolation"); -inline const Meta<> label("label"); -inline const Meta<> length("length"); -inline const Meta<> outerDomainValue("outerDomainValue"); -inline const Meta<> projectile("projectile"); -inline const Meta<> projectileFrame("projectileFrame"); -inline const Meta<> start("start"); -inline const Meta<> style("style"); -inline const Meta<> target("target"); -inline const Meta<> unit("unit"); -inline const Meta<> valueType("valueType"); +#define GNDSTK_MAKE_LOOKUP(nameField,nameGNDS) \ + inline const auto nameField = makeLookup( \ + [](const auto &obj) -> decltype(obj.nameField()) \ + { return obj.nameField(); }, \ + #nameGNDS \ + ) +// nameField vs. nameGNDS: for, e.g., Double vs. double in GNDS + +GNDSTK_MAKE_LOOKUP(ENDF_MT,ENDF_MT); +GNDSTK_MAKE_LOOKUP(evaluation,evaluation); +GNDSTK_MAKE_LOOKUP(fissionGenre,fissionGenre); +GNDSTK_MAKE_LOOKUP(format,format); +GNDSTK_MAKE_LOOKUP(href,href); +GNDSTK_MAKE_LOOKUP(index,index); +GNDSTK_MAKE_LOOKUP(interaction,interaction); +GNDSTK_MAKE_LOOKUP(interpolation,interpolation); +GNDSTK_MAKE_LOOKUP(label,label); +GNDSTK_MAKE_LOOKUP(length,length); +GNDSTK_MAKE_LOOKUP(outerDomainValue,outerDomainValue); +GNDSTK_MAKE_LOOKUP(projectile,projectile); +GNDSTK_MAKE_LOOKUP(projectileFrame,projectileFrame); +GNDSTK_MAKE_LOOKUP(start,start); +GNDSTK_MAKE_LOOKUP(style,style); +GNDSTK_MAKE_LOOKUP(target,target); +GNDSTK_MAKE_LOOKUP(unit,unit); +GNDSTK_MAKE_LOOKUP(valueType,valueType); + +#undef GNDSTK_MAKE_LOOKUP } // namespace meta -using namespace meta; -} // namespace key // ----------------------------------------------------------------------------- -// containers::key::child:: +// containers::child:: // ----------------------------------------------------------------------------- namespace containers { -namespace key { namespace child { inline const Child<> XYs1d("XYs1d"); @@ -81,16 +70,14 @@ inline const Child<> values("values"); } // namespace child using namespace child; -} // namespace key } // namespace containers // ----------------------------------------------------------------------------- -// transport::key::child:: +// transport::child:: // ----------------------------------------------------------------------------- namespace transport { -namespace key { namespace child { inline const Child<> crossSection("crossSection"); @@ -100,10 +87,24 @@ inline const Child<> reactions("reactions"); } // namespace child using namespace child; -} // namespace key } // namespace transport +// ----------------------------------------------------------------------------- +// For convenience: using directives +// ----------------------------------------------------------------------------- + +namespace key { + using namespace meta; + using namespace containers::child; + using namespace transport::child; +} // namespace key + +using namespace key; +using namespace containers; +using namespace transport; + + // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- diff --git a/src/GNDStk/v1.9/transport/CrossSection.hpp b/src/GNDStk/v1.9/transport/CrossSection.hpp index 12aeb298f..4f5ca09e5 100644 --- a/src/GNDStk/v1.9/transport/CrossSection.hpp +++ b/src/GNDStk/v1.9/transport/CrossSection.hpp @@ -2,13 +2,10 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_TRANSPORT_CROSSSECTION -#define NJOY_GNDSTK_V1_9_TRANSPORT_CROSSSECTION +#ifndef GNDSTK_V1_9_TRANSPORT_CROSSSECTION +#define GNDSTK_V1_9_TRANSPORT_CROSSSECTION -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/containers/XYs1d.hpp" #include "GNDStk/v1.9/containers/Regions1d.hpp" @@ -16,9 +13,6 @@ namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // transport:: @@ -27,7 +21,7 @@ using namespace njoy::GNDStk::core; namespace transport { -class CrossSection : public Component { +class CrossSection : public Component { using XYs1d_regions1d_t = std::variant< containers::XYs1d, @@ -40,13 +34,13 @@ class CrossSection : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "transport"; } - static auto className() { return "CrossSection"; } - static auto GNDSName() { return "crossSection"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "transport"; } + static auto CLASS() { return "CrossSection"; } + static auto FIELD() { return "crossSection"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // children @@ -59,14 +53,6 @@ class CrossSection : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -74,7 +60,7 @@ class CrossSection : public Component { struct { // children - variant std::vector XYs1d_regions1d; - } content; + } Content; // ------------------------ // Getters @@ -83,45 +69,33 @@ class CrossSection : public Component { // XYs1d_regions1d const std::vector &XYs1d_regions1d() const - { return content.XYs1d_regions1d; } + { return Content.XYs1d_regions1d; } std::vector &XYs1d_regions1d() - { return content.XYs1d_regions1d; } - - // XYs1d_regions1d(index) - const XYs1d_regions1d_t &XYs1d_regions1d(const std::size_t index) const - { return getter(XYs1d_regions1d(), index, "XYs1d_regions1d"); } - XYs1d_regions1d_t &XYs1d_regions1d(const std::size_t index) - { return getter(XYs1d_regions1d(), index, "XYs1d_regions1d"); } - - // XYs1d_regions1d(label) - const XYs1d_regions1d_t &XYs1d_regions1d(const std::string &label) const - { return getter(XYs1d_regions1d(), label, "XYs1d_regions1d"); } - XYs1d_regions1d_t &XYs1d_regions1d(const std::string &label) - { return getter(XYs1d_regions1d(), label, "XYs1d_regions1d"); } - - // XYs1d(index) - const containers::XYs1d *XYs1d(const std::size_t index) const - { return getter(XYs1d_regions1d(), index, "XYs1d"); } - containers::XYs1d *XYs1d(const std::size_t index) - { return getter(XYs1d_regions1d(), index, "XYs1d"); } - - // XYs1d(label) - const containers::XYs1d *XYs1d(const std::string &label) const - { return getter(XYs1d_regions1d(), label, "XYs1d"); } - containers::XYs1d *XYs1d(const std::string &label) - { return getter(XYs1d_regions1d(), label, "XYs1d"); } - - // regions1d(index) - const containers::Regions1d *regions1d(const std::size_t index) const - { return getter(XYs1d_regions1d(), index, "regions1d"); } - containers::Regions1d *regions1d(const std::size_t index) - { return getter(XYs1d_regions1d(), index, "regions1d"); } - - // regions1d(label) - const containers::Regions1d *regions1d(const std::string &label) const - { return getter(XYs1d_regions1d(), label, "regions1d"); } - containers::Regions1d *regions1d(const std::string &label) - { return getter(XYs1d_regions1d(), label, "regions1d"); } + { return Content.XYs1d_regions1d; } + + // XYs1d_regions1d(index/label/Lookup) + template> + decltype(auto) XYs1d_regions1d(const KEY &key) const + { return getter(XYs1d_regions1d(), key, "XYs1d_regions1d"); } + template> + decltype(auto) XYs1d_regions1d(const KEY &key) + { return getter(XYs1d_regions1d(), key, "XYs1d_regions1d"); } + + // XYs1d(index/label/Lookup) + template> + decltype(auto) XYs1d(const KEY &key) const + { return getter(XYs1d_regions1d(), key, "XYs1d"); } + template> + decltype(auto) XYs1d(const KEY &key) + { return getter(XYs1d_regions1d(), key, "XYs1d"); } + + // regions1d(index/label/Lookup) + template> + decltype(auto) regions1d(const KEY &key) const + { return getter(XYs1d_regions1d(), key, "regions1d"); } + template> + decltype(auto) regions1d(const KEY &key) + { return getter(XYs1d_regions1d(), key, "regions1d"); } // ------------------------ // Setters @@ -129,71 +103,56 @@ class CrossSection : public Component { // All return *this // ------------------------ - // XYs1d_regions1d(value) + // XYs1d_regions1d(vector): replace vector CrossSection &XYs1d_regions1d(const std::vector &obj) { XYs1d_regions1d() = obj; return *this; } - // XYs1d_regions1d(index,value) - CrossSection &XYs1d_regions1d( - const std::size_t index, - const XYs1d_regions1d_t &obj - ) { - XYs1d_regions1d(index) = obj; return *this; - } + // XYs1d_regions1d(scalar): vector push_back + CrossSection &XYs1d_regions1d(const XYs1d_regions1d_t &obj) + { setter(XYs1d_regions1d(), obj); return *this; } - // XYs1d_regions1d(label,value) - CrossSection &XYs1d_regions1d( - const std::string &label, - const XYs1d_regions1d_t &obj - ) { - XYs1d_regions1d(label) = obj; return *this; - } - - // XYs1d(index,value) - CrossSection &XYs1d( - const std::size_t index, - const std::optional &obj - ) { - if (obj) XYs1d_regions1d(index,obj.value()); - return *this; + // XYs1d_regions1d(index/label/Lookup, value): replace vector entry + template> + CrossSection &XYs1d_regions1d(const KEY &key, const XYs1d_regions1d_t &obj) + { + XYs1d_regions1d(key) = obj; return *this; } - // XYs1d(label,value) + // XYs1d(index/label/Lookup, value): replace vector entry + template> CrossSection &XYs1d( - const std::string &label, + const KEY &key, const std::optional &obj ) { - if (obj) XYs1d_regions1d(label,obj.value()); + if (obj) XYs1d_regions1d(key,obj.value()); return *this; } - // regions1d(index,value) + // regions1d(index/label/Lookup, value): replace vector entry + template> CrossSection ®ions1d( - const std::size_t index, + const KEY &key, const std::optional &obj ) { - if (obj) XYs1d_regions1d(index,obj.value()); - return *this; - } - - // regions1d(label,value) - CrossSection ®ions1d( - const std::string &label, - const std::optional &obj - ) { - if (obj) XYs1d_regions1d(label,obj.value()); + if (obj) XYs1d_regions1d(key,obj.value()); return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - CrossSection() : + // default, and from fields + explicit CrossSection( + const std::vector &XYs1d_regions1d = + std::vector{} + ) : Component{ - BodyText{}, - content.XYs1d_regions1d + BlockData{}, + this->XYs1d_regions1d() + }, + Content{ + XYs1d_regions1d } { Component::finish(); @@ -202,10 +161,10 @@ class CrossSection : public Component { // copy CrossSection(const CrossSection &other) : Component{ - other, - content.XYs1d_regions1d + other.baseBlockData(), + this->XYs1d_regions1d() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -213,10 +172,10 @@ class CrossSection : public Component { // move CrossSection(CrossSection &&other) : Component{ - other, - content.XYs1d_regions1d + other.baseBlockData(), + this->XYs1d_regions1d() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -224,28 +183,13 @@ class CrossSection : public Component { // from node CrossSection(const Node &node) : Component{ - BodyText{}, - content.XYs1d_regions1d + BlockData{}, + this->XYs1d_regions1d() } { Component::finish(node); } - // from fields - explicit CrossSection( - const std::vector &XYs1d_regions1d - ) : - Component{ - BodyText{}, - content.XYs1d_regions1d - }, - content{ - XYs1d_regions1d - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/transport/Reaction.hpp b/src/GNDStk/v1.9/transport/Reaction.hpp index bb15a3f88..42669a2b6 100644 --- a/src/GNDStk/v1.9/transport/Reaction.hpp +++ b/src/GNDStk/v1.9/transport/Reaction.hpp @@ -2,22 +2,16 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_TRANSPORT_REACTION -#define NJOY_GNDSTK_V1_9_TRANSPORT_REACTION +#ifndef GNDSTK_V1_9_TRANSPORT_REACTION +#define GNDSTK_V1_9_TRANSPORT_REACTION -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/transport/CrossSection.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // transport:: @@ -26,8 +20,7 @@ using namespace njoy::GNDStk::core; namespace transport { -class Reaction : public Component { - +class Reaction : public Component { // ------------------------ // For Component @@ -35,13 +28,13 @@ class Reaction : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "transport"; } - static auto className() { return "Reaction"; } - static auto GNDSName() { return "reaction"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "transport"; } + static auto CLASS() { return "Reaction"; } + static auto FIELD() { return "reaction"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -61,14 +54,6 @@ class Reaction : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -80,7 +65,7 @@ class Reaction : public Component { std::string label; // children transport::CrossSection crossSection; - } content; + } Content; // ------------------------ // Getters @@ -89,27 +74,27 @@ class Reaction : public Component { // ENDF_MT const int &ENDF_MT() const - { return content.ENDF_MT; } + { return Content.ENDF_MT; } int &ENDF_MT() - { return content.ENDF_MT; } + { return Content.ENDF_MT; } // fissionGenre const std::optional &fissionGenre() const - { return content.fissionGenre; } + { return Content.fissionGenre; } std::optional &fissionGenre() - { return content.fissionGenre; } + { return Content.fissionGenre; } // label const std::string &label() const - { return content.label; } + { return Content.label; } std::string &label() - { return content.label; } + { return Content.label; } // crossSection const transport::CrossSection &crossSection() const - { return content.crossSection; } + { return Content.crossSection; } transport::CrossSection &crossSection() - { return content.crossSection; } + { return Content.crossSection; } // ------------------------ // Setters @@ -134,17 +119,32 @@ class Reaction : public Component { { crossSection() = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Reaction() : + // default, and from fields + explicit Reaction( + const int &ENDF_MT = + int{}, + const std::optional &fissionGenre = + std::optional{}, + const std::string &label = + std::string{}, + const transport::CrossSection &crossSection = + transport::CrossSection{} + ) : Component{ - BodyText{}, - content.ENDF_MT, - content.fissionGenre, - content.label, - content.crossSection + BlockData{}, + this->ENDF_MT(), + this->fissionGenre(), + this->label(), + this->crossSection() + }, + Content{ + ENDF_MT, + fissionGenre, + label, + crossSection } { Component::finish(); @@ -153,13 +153,13 @@ class Reaction : public Component { // copy Reaction(const Reaction &other) : Component{ - other, - content.ENDF_MT, - content.fissionGenre, - content.label, - content.crossSection + other.baseBlockData(), + this->ENDF_MT(), + this->fissionGenre(), + this->label(), + this->crossSection() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -167,13 +167,13 @@ class Reaction : public Component { // move Reaction(Reaction &&other) : Component{ - other, - content.ENDF_MT, - content.fissionGenre, - content.label, - content.crossSection + other.baseBlockData(), + this->ENDF_MT(), + this->fissionGenre(), + this->label(), + this->crossSection() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -181,40 +181,16 @@ class Reaction : public Component { // from node Reaction(const Node &node) : Component{ - BodyText{}, - content.ENDF_MT, - content.fissionGenre, - content.label, - content.crossSection + BlockData{}, + this->ENDF_MT(), + this->fissionGenre(), + this->label(), + this->crossSection() } { Component::finish(node); } - // from fields - explicit Reaction( - const int &ENDF_MT, - const std::optional &fissionGenre, - const std::string &label, - const transport::CrossSection &crossSection - ) : - Component{ - BodyText{}, - content.ENDF_MT, - content.fissionGenre, - content.label, - content.crossSection - }, - content{ - ENDF_MT, - fissionGenre, - label, - crossSection - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/transport/ReactionSuite.hpp b/src/GNDStk/v1.9/transport/ReactionSuite.hpp index 86601b7d2..9592e3d72 100644 --- a/src/GNDStk/v1.9/transport/ReactionSuite.hpp +++ b/src/GNDStk/v1.9/transport/ReactionSuite.hpp @@ -2,22 +2,16 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_TRANSPORT_REACTIONSUITE -#define NJOY_GNDSTK_V1_9_TRANSPORT_REACTIONSUITE +#ifndef GNDSTK_V1_9_TRANSPORT_REACTIONSUITE +#define GNDSTK_V1_9_TRANSPORT_REACTIONSUITE -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/transport/Reactions.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // transport:: @@ -26,8 +20,7 @@ using namespace njoy::GNDStk::core; namespace transport { -class ReactionSuite : public Component { - +class ReactionSuite : public Component { // ------------------------ // For Component @@ -35,13 +28,13 @@ class ReactionSuite : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "transport"; } - static auto className() { return "ReactionSuite"; } - static auto GNDSName() { return "reactionSuite"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "transport"; } + static auto CLASS() { return "ReactionSuite"; } + static auto FIELD() { return "reactionSuite"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // metadata @@ -49,14 +42,14 @@ class ReactionSuite : public Component { / Meta<>("evaluation") | std::string{} / Meta<>("format") | - std::optional{} - / Meta<>("interaction") | std::string{} / Meta<>("projectile") | enums::Frame{} / Meta<>("projectileFrame") | std::string{} / Meta<>("target") | + std::optional{} + / Meta<>("interaction") | // children std::optional{} / --Child<>("reactions") @@ -67,14 +60,6 @@ class ReactionSuite : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -83,13 +68,13 @@ class ReactionSuite : public Component { // metadata std::string evaluation; std::string format; - std::optional interaction; std::string projectile; enums::Frame projectileFrame; std::string target; + std::optional interaction; // children std::optional reactions; - } content; + } Content; // ------------------------ // Getters @@ -98,45 +83,45 @@ class ReactionSuite : public Component { // evaluation const std::string &evaluation() const - { return content.evaluation; } + { return Content.evaluation; } std::string &evaluation() - { return content.evaluation; } + { return Content.evaluation; } // format const std::string &format() const - { return content.format; } + { return Content.format; } std::string &format() - { return content.format; } - - // interaction - const std::optional &interaction() const - { return content.interaction; } - std::optional &interaction() - { return content.interaction; } + { return Content.format; } // projectile const std::string &projectile() const - { return content.projectile; } + { return Content.projectile; } std::string &projectile() - { return content.projectile; } + { return Content.projectile; } // projectileFrame const enums::Frame &projectileFrame() const - { return content.projectileFrame; } + { return Content.projectileFrame; } enums::Frame &projectileFrame() - { return content.projectileFrame; } + { return Content.projectileFrame; } // target const std::string &target() const - { return content.target; } + { return Content.target; } std::string &target() - { return content.target; } + { return Content.target; } + + // interaction + const std::optional &interaction() const + { return Content.interaction; } + std::optional &interaction() + { return Content.interaction; } // reactions const std::optional &reactions() const - { return content.reactions; } + { return Content.reactions; } std::optional &reactions() - { return content.reactions; } + { return Content.reactions; } // ------------------------ // Setters @@ -152,10 +137,6 @@ class ReactionSuite : public Component { ReactionSuite &format(const std::string &obj) { format() = obj; return *this; } - // interaction(value) - ReactionSuite &interaction(const std::optional &obj) - { interaction() = obj; return *this; } - // projectile(value) ReactionSuite &projectile(const std::string &obj) { projectile() = obj; return *this; } @@ -168,25 +149,53 @@ class ReactionSuite : public Component { ReactionSuite &target(const std::string &obj) { target() = obj; return *this; } + // interaction(value) + ReactionSuite &interaction(const std::optional &obj) + { interaction() = obj; return *this; } + // reactions(value) ReactionSuite &reactions(const std::optional &obj) { reactions() = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - ReactionSuite() : + // default, and from fields + explicit ReactionSuite( + const std::string &evaluation = + std::string{}, + const std::string &format = + std::string{}, + const std::string &projectile = + std::string{}, + const enums::Frame &projectileFrame = + enums::Frame{}, + const std::string &target = + std::string{}, + const std::optional &interaction = + std::optional{}, + const std::optional &reactions = + std::optional{} + ) : Component{ - BodyText{}, - content.evaluation, - content.format, - content.interaction, - content.projectile, - content.projectileFrame, - content.target, - content.reactions + BlockData{}, + this->evaluation(), + this->format(), + this->projectile(), + this->projectileFrame(), + this->target(), + this->interaction(), + this->reactions() + }, + Content{ + evaluation, + format, + projectile, + projectileFrame, + target, + interaction, + reactions } { Component::finish(); @@ -195,16 +204,16 @@ class ReactionSuite : public Component { // copy ReactionSuite(const ReactionSuite &other) : Component{ - other, - content.evaluation, - content.format, - content.interaction, - content.projectile, - content.projectileFrame, - content.target, - content.reactions + other.baseBlockData(), + this->evaluation(), + this->format(), + this->projectile(), + this->projectileFrame(), + this->target(), + this->interaction(), + this->reactions() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -212,16 +221,16 @@ class ReactionSuite : public Component { // move ReactionSuite(ReactionSuite &&other) : Component{ - other, - content.evaluation, - content.format, - content.interaction, - content.projectile, - content.projectileFrame, - content.target, - content.reactions + other.baseBlockData(), + this->evaluation(), + this->format(), + this->projectile(), + this->projectileFrame(), + this->target(), + this->interaction(), + this->reactions() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -229,52 +238,19 @@ class ReactionSuite : public Component { // from node ReactionSuite(const Node &node) : Component{ - BodyText{}, - content.evaluation, - content.format, - content.interaction, - content.projectile, - content.projectileFrame, - content.target, - content.reactions + BlockData{}, + this->evaluation(), + this->format(), + this->projectile(), + this->projectileFrame(), + this->target(), + this->interaction(), + this->reactions() } { Component::finish(node); } - // from fields - explicit ReactionSuite( - const std::string &evaluation, - const std::string &format, - const std::optional &interaction, - const std::string &projectile, - const enums::Frame &projectileFrame, - const std::string &target, - const std::optional &reactions - ) : - Component{ - BodyText{}, - content.evaluation, - content.format, - content.interaction, - content.projectile, - content.projectileFrame, - content.target, - content.reactions - }, - content{ - evaluation, - format, - interaction, - projectile, - projectileFrame, - target, - reactions - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------ diff --git a/src/GNDStk/v1.9/transport/Reactions.hpp b/src/GNDStk/v1.9/transport/Reactions.hpp index bf92b5bdc..8d62e6e6f 100644 --- a/src/GNDStk/v1.9/transport/Reactions.hpp +++ b/src/GNDStk/v1.9/transport/Reactions.hpp @@ -2,22 +2,16 @@ // THIS FILE WAS AUTOGENERATED! // DO NOT MODIFY! -#ifndef NJOY_GNDSTK_V1_9_TRANSPORT_REACTIONS -#define NJOY_GNDSTK_V1_9_TRANSPORT_REACTIONS +#ifndef GNDSTK_V1_9_TRANSPORT_REACTIONS +#define GNDSTK_V1_9_TRANSPORT_REACTIONS -// core interface -#include "GNDStk.hpp" - -// v1.9 dependencies +#include "GNDStk/v1.9/key.hpp" #include "GNDStk/v1.9/transport/Reaction.hpp" namespace njoy { namespace GNDStk { namespace v1_9 { -using namespace njoy::GNDStk::core; - - // ----------------------------------------------------------------------------- // transport:: @@ -26,8 +20,7 @@ using namespace njoy::GNDStk::core; namespace transport { -class Reactions : public Component { - +class Reactions : public Component { // ------------------------ // For Component @@ -35,13 +28,13 @@ class Reactions : public Component { friend class Component; - // Current namespace, current class, and GNDS node name - static auto namespaceName() { return "transport"; } - static auto className() { return "Reactions"; } - static auto GNDSName() { return "reactions"; } + // Names: this namespace, this class, a field / node of this type + static auto NAMESPACE() { return "transport"; } + static auto CLASS() { return "Reactions"; } + static auto FIELD() { return "reactions"; } // Core Interface multi-query to extract metadata and child nodes - static auto keys() + static auto KEYS() { return // children @@ -54,14 +47,6 @@ class Reactions : public Component { using Component::construct; - // ------------------------ - // Relevant defaults - // FYI for users - // ------------------------ - - static inline const struct Defaults { - } defaults; - // ------------------------ // Raw GNDS content // ------------------------ @@ -69,7 +54,7 @@ class Reactions : public Component { struct { // children std::vector reaction; - } content; + } Content; // ------------------------ // Getters @@ -78,21 +63,17 @@ class Reactions : public Component { // reaction const std::vector &reaction() const - { return content.reaction; } + { return Content.reaction; } std::vector &reaction() - { return content.reaction; } - - // reaction(index) - const transport::Reaction &reaction(const std::size_t index) const - { return getter(reaction(), index, "reaction"); } - transport::Reaction &reaction(const std::size_t index) - { return getter(reaction(), index, "reaction"); } + { return Content.reaction; } - // reaction(label) - const transport::Reaction &reaction(const std::string &label) const - { return getter(reaction(), label, "reaction"); } - transport::Reaction &reaction(const std::string &label) - { return getter(reaction(), label, "reaction"); } + // reaction(index/label/Lookup) + template> + decltype(auto) reaction(const KEY &key) const + { return getter(reaction(), key, "reaction"); } + template> + decltype(auto) reaction(const KEY &key) + { return getter(reaction(), key, "reaction"); } // ------------------------ // Setters @@ -100,35 +81,36 @@ class Reactions : public Component { // All return *this // ------------------------ - // reaction(value) + // reaction(vector): replace vector Reactions &reaction(const std::vector &obj) { reaction() = obj; return *this; } - // reaction(index,value) - Reactions &reaction( - const std::size_t index, - const transport::Reaction &obj - ) { - reaction(index) = obj; return *this; - } + // reaction(scalar): vector push_back + Reactions &reaction(const transport::Reaction &obj) + { setter(reaction(), obj); return *this; } - // reaction(label,value) - Reactions &reaction( - const std::string &label, - const transport::Reaction &obj - ) { - reaction(label) = obj; return *this; + // reaction(index/label/Lookup, value): replace vector entry + template> + Reactions &reaction(const KEY &key, const transport::Reaction &obj) + { + reaction(key) = obj; return *this; } // ------------------------ - // Construction + // Constructors // ------------------------ - // default - Reactions() : + // default, and from fields + explicit Reactions( + const std::vector &reaction = + std::vector{} + ) : Component{ - BodyText{}, - content.reaction + BlockData{}, + this->reaction() + }, + Content{ + reaction } { Component::finish(); @@ -137,10 +119,10 @@ class Reactions : public Component { // copy Reactions(const Reactions &other) : Component{ - other, - content.reaction + other.baseBlockData(), + this->reaction() }, - content{other.content} + Content{other.Content} { Component::finish(other); } @@ -148,10 +130,10 @@ class Reactions : public Component { // move Reactions(Reactions &&other) : Component{ - other, - content.reaction + other.baseBlockData(), + this->reaction() }, - content{std::move(other.content)} + Content{std::move(other.Content)} { Component::finish(other); } @@ -159,28 +141,13 @@ class Reactions : public Component { // from node Reactions(const Node &node) : Component{ - BodyText{}, - content.reaction + BlockData{}, + this->reaction() } { Component::finish(node); } - // from fields - explicit Reactions( - const std::vector &reaction - ) : - Component{ - BodyText{}, - content.reaction - }, - content{ - reaction - } - { - Component::finish(); - } - // ------------------------ // Assignment // ------------------------