From 2ef68d9f16176de310793d2b5c93ef73a4ca84c1 Mon Sep 17 00:00:00 2001 From: Markus Frank <Markus.Frank@cern.ch> Date: Thu, 16 Mar 2017 13:32:06 +0100 Subject: [PATCH] Add first version of JSON interpreter --- DDCore/CMakeLists.txt | 2 +- DDCore/include/JSON/Elements.h | 505 ++++++++++++++++++++++++++++++++ DDCore/include/JSON/Evaluator.h | 24 ++ DDCore/include/JSON/Printout.h | 24 ++ DDCore/include/JSON/config.h | 35 +++ DDCore/src/JSON/Elements.cpp | 502 +++++++++++++++++++++++++++++++ 6 files changed, 1091 insertions(+), 1 deletion(-) create mode 100644 DDCore/include/JSON/Elements.h create mode 100644 DDCore/include/JSON/Evaluator.h create mode 100644 DDCore/include/JSON/Printout.h create mode 100644 DDCore/include/JSON/config.h create mode 100644 DDCore/src/JSON/Elements.cpp diff --git a/DDCore/CMakeLists.txt b/DDCore/CMakeLists.txt index d680fcd21..fc752dc5a 100644 --- a/DDCore/CMakeLists.txt +++ b/DDCore/CMakeLists.txt @@ -42,7 +42,7 @@ dd4hep_add_package_library ( DDParsers #---Generate DDCore Library------------------------------------------------------- dd4hep_add_package_library ( DDCore - SOURCES src/*.cpp src/XML/*.cpp + SOURCES src/*.cpp src/XML/*.cpp src/JSON/*.cpp GENERATED G__DD4hep.cxx INCLUDE_DIRS ${GaudiPluginService_INCLUDE_DIRS} LINK_LIBRARIES DDParsers ${GaudiPluginService_LIBRARIES} diff --git a/DDCore/include/JSON/Elements.h b/DDCore/include/JSON/Elements.h new file mode 100644 index 000000000..580855a11 --- /dev/null +++ b/DDCore/include/JSON/Elements.h @@ -0,0 +1,505 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDCORE_DD4HEP_JSON_ELEMENTS_H +#define DDCORE_DD4HEP_JSON_ELEMENTS_H + +// C/C++ include files +#include <cmath> +#include <string> +#include <vector> +#include <stdexcept> + +// Framework include files +#include "JSON/config.h" + +#ifndef RAD_2_DEGREE +#define RAD_2_DEGREE 57.295779513082320876798154814105 +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the AIDA detector description toolkit supporting JSON utilities + namespace JSON { + + typedef const JsonAttr* Attribute; + + typedef const std::string& CSTR; + + /// Dump DOM tree of a document + void dumpTree(JsonDocument* doc); + + /// Convert json attribute to STL string \ingroup DD4HEP_JSON + std::string _toString(const Attribute attr); + /// Convert json string to STL string \ingroup DD4HEP_JSON + std::string _toString(const JsonChar *toTranscode); + /// Do-nothing version. Present for completeness and argument interchangeability \ingroup DD4HEP_JSON + std::string _toString(const char* s); + /// Do-nothing version. Present for completeness and argument interchangeability \ingroup DD4HEP_JSON + std::string _toString(const std::string& s); + /// Format unsigned long integer to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(unsigned long i, const char* fmt = "%lu"); + /// Format unsigned integer (32 bits) to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(unsigned int i, const char* fmt = "%u"); + /// Format signed integer (32 bits) to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(int i, const char* fmt = "%d"); + /// Format signed long integer to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(long i, const char* fmt = "%ld"); + /// Format single procision float number (32 bits) to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(float d, const char* fmt = "%.17e"); + /// Format double procision float number (64 bits) to string with arbitrary format \ingroup DD4HEP_JSON + std::string _toString(double d, const char* fmt = "%.17e"); + /// Format void pointer (64 bits) to string with arbitrary format \ingroup DD4HEP_JSON + std::string _ptrToString(const void* p, const char* fmt = "%p"); + /// Format void pointer (64 bits) to string with arbitrary format \ingroup DD4HEP_JSON + template <typename T> std::string _toString(const T* p, const char* fmt = "%p") + { return _ptrToString((void*)p,fmt); } + + /// Helper function to populate the evaluator dictionary \ingroup DD4HEP_JSON + void _toDictionary(const JsonChar* name, const JsonChar* value); + /// Helper function to populate the evaluator dictionary \ingroup DD4HEP_JSON + void _toDictionary(const std::string& name, const JsonChar* value) + { _toDictionary(name, value); } + /// Helper function to populate the evaluator dictionary \ingroup DD4HEP_JSON + template <typename T> void _toDictionary(const JsonChar* name, T value); + + /// Helper function to populate the evaluator dictionary \ingroup DD4HEP_JSON + void _toDictionary(const JsonChar* name, float value); + /// Helper function to populate the evaluator dictionary \ingroup DD4HEP_JSON + void _toDictionary(const JsonChar* name, double value); + /// Helper function to lookup environment from the expression evaluator + std::string getEnviron(const std::string& env); + + /// Conversion function from raw unicode string to bool \ingroup DD4HEP_JSON + bool _toBool(const JsonChar* value); + /// Conversion function from raw unicode string to int \ingroup DD4HEP_JSON + int _toInt(const JsonChar* value); + /// Conversion function from raw unicode string to long \ingroup DD4HEP_JSON + long _toLong(const JsonChar* value); + /// Conversion function from raw unicode string to float \ingroup DD4HEP_JSON + float _toFloat(const JsonChar* value); + /// Conversion function from raw unicode string to double \ingroup DD4HEP_JSON + double _toDouble(const JsonChar* value); + + /// Class describing a list of JSON nodes + /** + * Definition of a "list" of json elements hanging of the parent. + * The list allows iterations, which can be restarted. + * Please not: Copies are not entirely free, since the + * string tag need to be replicated using strdup/free + * (or when using xerces the corresponding unicode routines). + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class NodeList { + public: + typedef std::pair<JsonElement::second_type::assoc_iterator,JsonElement::second_type::assoc_iterator> iter_t; + std::string m_tag; + JsonElement* m_node; + mutable iter_t m_ptr; + + /// Copy constructor + NodeList(const NodeList& l); + /// Initializing constructor + NodeList(JsonElement* frst, const std::string& tag); + /// Default destructor + ~NodeList(); + /// Reset the nodelist - e.g. restart iteration from beginning + JsonElement* reset(); + /// Advance to next element + JsonElement* next() const; + /// Go back to previous element + JsonElement* previous() const; + /// Assignment operator + NodeList& operator=(const NodeList& l); + }; + + /// Class to easily access the properties of single JsonElements. + /** + * Note: The assignmant operator as well as the copy constructor + * do not have to be implemented, they are aut-generated by the compiler! + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class Handle_t { + public: + // Abbreviation for internal use + typedef JsonElement* Elt_t; + + /// The pointer to the JsonElement + mutable Elt_t m_node; + + /// Initializing constructor + Handle_t(Elt_t e = 0) + : m_node(e) { + } + /// Direct access to the JsonElement using the operator-> + Elt_t operator->() const { + return m_node; + } + /// Direct access to the JsonElement by dereferencing + operator Elt_t() const { + return m_node; + } + /// Direct access to the JsonElement by function + Elt_t ptr() const { + return m_node; + } + /// Clone the DOMelement - with the option of a deep copy + Handle_t clone(JsonDocument* new_doc) const; + + /// Unicode text access to the element's tag. Tis must be wrong .... + const JsonChar* rawTag() const; + /// Unicode text access to the element's text + const JsonChar* rawText() const; + /// Unicode text access to the element's value + const JsonChar* rawValue() const; + /// Text access to the element's tag + std::string tag() const { + return _toString(rawTag()); + } + /// Text access to the element's text + std::string text() const { + return _toString(rawText()); + } + /// Text access to the element's value + std::string value() const { + return _toString(rawValue()); + } + + /*** DOM Attribute handling + */ + /// Access attribute name (throws exception if not present) + const JsonChar* attr_name(const Attribute attr) const; + /// Access attribute value by the attribute (throws exception if not present) + const JsonChar* attr_value(const Attribute attr) const; + /// Access attribute value by the attribute's unicode name (throws exception if not present) + const JsonChar* attr_value(const JsonChar* attr) const; + /// Access attribute value by the attribute's unicode name (no exception thrown if not present) + const JsonChar* attr_value_nothrow(const JsonChar* attr) const; + + /// Access attribute pointer by the attribute's unicode name (throws exception if not present) + Attribute attr_ptr(const JsonChar* attr) const; + /// Access attribute pointer by the attribute's unicode name (no exception thrown if not present) + Attribute attr_nothrow(const JsonChar* tag) const; + /// Check for the existence of a named attribute + bool hasAttr(const JsonChar* t) const; + /// Retrieve a collection of all attributes of this DOM element + std::vector<Attribute> attributes() const; + /// Access typed attribute value by the JsonAttr + template <class T> T attr(const Attribute a) const { + return this->attr<T>(this->attr_name(a)); + } + /// Access typed attribute value by it's unicode name + template <class T> T attr(const JsonChar* name) const; + + /*** DOM Element child handling + */ + /// Check the existence of a child with a given tag name + bool hasChild(const JsonChar* tag) const; + /// Access a single child by it's tag name (unicode) + Handle_t child(const JsonChar* tag, bool throw_exception = true) const; + /// Access a group of children identified by the same tag name + NodeList children(const JsonChar* tag) const; + /// Access the number of children of this DOM element with a given tag name + size_t numChildren(const JsonChar* tag, bool throw_exception) const; + /// Access the element's parent element + //Handle_t parent() const; + }; + +#define INLINE inline + typedef const JsonChar* cpJsonChar; + + template <> INLINE Attribute Handle_t::attr<Attribute>(const JsonChar* tag_value) const { + return attr_ptr(tag_value); + } + + template <> INLINE cpJsonChar Handle_t::attr<cpJsonChar>(const JsonChar* tag_value) const { + return attr_value(tag_value); + } + + template <> INLINE bool Handle_t::attr<bool>(const JsonChar* tag_value) const { + return _toBool(attr_value(tag_value)); + } + + template <> INLINE int Handle_t::attr<int>(const JsonChar* tag_value) const { + return _toInt(attr_value(tag_value)); + } + + template <> INLINE long Handle_t::attr<long>(const JsonChar* tag_value) const { + return _toLong(attr_value(tag_value)); + } + + template <> INLINE float Handle_t::attr<float>(const JsonChar* tag_value) const { + return _toFloat(attr_value(tag_value)); + } + + template <> INLINE double Handle_t::attr<double>(const JsonChar* tag_value) const { + return _toDouble(attr_value(tag_value)); + } + + template <> INLINE std::string Handle_t::attr<std::string>(const JsonChar* tag_value) const { + return _toString(attr_value(tag_value)); + } + + /// Class to support the access to collections of JsonNodes (or JsonElements) + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class Collection_t : public Handle_t { + public: + /// Reference to the list of child nodes + NodeList m_children; + /// Constructor over JsonElements with a given tag name + Collection_t(Handle_t node, const char* tag); + /// Constructor over JsonElements in a node list + Collection_t(NodeList children); + /// Reset the collection object to restart the iteration + Collection_t& reset(); + /// Access the collection size. Avoid this call -- sloooow! + size_t size() const; + /// Operator to advance the collection (pre increment) + void operator++() const; + /// Operator to advance the collection (post increment) + void operator++(int) const; + /// Operator to advance the collection (pre decrement) + void operator--() const; + /// Operator to advance the collection (post decrement) + void operator--(int) const; + /// Access to current element + Elt_t current() const { + return m_node; + } + /// Helper function to throw an exception + void throw_loop_exception(const std::exception& e) const; + /// Loop processor using function object + template <class T> void for_each(T oper) const { + try { + for (const Collection_t& c = *this; c; ++c) + oper(*this); + } + catch (const std::exception& e) { + throw_loop_exception(e); + } + } + /// Loop processor using function object + template <class T> void for_each(const JsonChar* tag_name, T oper) const { + try { + for (const Collection_t& c = *this; c; ++c) + Collection_t(c.m_node, tag_name).for_each(oper); + } + catch (const std::exception& e) { + throw_loop_exception(e); + } + } + }; + + /// Class supporting the basic functionality of an JSON document + /** + * User class encapsulating a DOM document. + * Nothing special - normal handle around pointer. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class Document { + public: + typedef JsonDocument* DOC; + DOC m_doc; + + /// Constructor + Document(DOC d) : m_doc(d) { + } + /// Auto-conversion to DOM document + operator DOC() const { + return m_doc; + } + /// Accessot to DOM document behaviour using arrow operator + DOC operator->() const { + return m_doc; + } + /// Accessot to DOM document behaviour + DOC ptr() const { + return m_doc; + } + }; + + /// Class supporting the basic functionality of an JSON document including ownership + /** + * User class encapsulating a DOM document. + * Nothing special - normal handle around pointer. + * Contrary to the Document class, on destruction the + * JSON document shall be destroyed and the corresponding + * resources released. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class DocumentHolder : public Document { + public: + /// Default Constructor + DocumentHolder() : Document(0) { + } + /// Constructor + DocumentHolder(DOC d) : Document(d) { + } + /// Assign new document. Old document is dropped. + DocumentHolder& assign(DOC d); + /// Standard destructor - releases the document + virtual ~DocumentHolder(); + }; + + /// User abstraction class to manipulate JSON elements within a document + /** + * User class encapsulating a DOM element + * using the Handle helper. + * This is the main class we interact with when + * analysing the json documents for constructing + * sub-detectors etc. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_JSON + */ + class Element { + public: + /// Simplification type declarations + typedef Handle_t::Elt_t Elt_t; + + /// The underlying object holding the JsonElement pointer + Handle_t m_element; + + /// Constructor from JsonElement handle + Element(const Handle_t& e) : m_element(e) { } + /// Constructor from JsonElement handle + Element(const Element& e) : m_element(e.m_element) { } + /// Constructor from DOM document entity + //Element(const Document& document, const JsonChar* type); + /// Access the hosting document handle of this DOM element + //Document document() const; + + /// operator bool: check handle validity + operator bool() const { + return 0 != m_element.ptr(); + } + /// operator NOT: check handle validity + bool operator!() const { + return 0 == m_element.ptr(); + } + /// Assignment operator + Element& operator=(const Element& c) { + m_element = c.m_element; + return *this; + } + /// Assignment operator + Element& operator=(Handle_t handle) { + m_element = handle; + return *this; + } + /// Automatic conversion to DOM element handle + operator Handle_t() const { + return m_element; + } + /// Automatic conversion to JsonElement pointer + operator Elt_t() const { + return m_element; + } + /// Access to JsonElement pointer + Elt_t ptr() const { + return m_element; + } +#if 0 + /// Access the JsonElements parent + Handle_t parent() const { + return m_element.parent(); + } + /// Access the JsonElements parent + Elt_t parentElement() const; +#endif + /// Access the tag name of this element + std::string tag() const { + return m_element.tag(); + } + /// Access the tag name of this element + const JsonChar* tagName() const { + return m_element.rawTag(); + } + /// Access the tag name of this element + std::string text() const { + return m_element.text(); + } + /// Check for the existence of a named attribute + bool hasAttr(const JsonChar* name) const { + return m_element.hasAttr(name); + } + /// Access attribute with implicit return type conversion + template <class T> T attr(const JsonChar* tag_value) const { + return m_element.attr<T>(tag_value); + } + /// Access attribute name (throws exception if not present) + const JsonChar* attr_name(const Attribute a) const { + return m_element.attr_name(a); + } + /// Access attribute value by the attribute (throws exception if not present) + const JsonChar* attr_value(const Attribute a) const { + return m_element.attr_value(a); + } + /// Access the number of children of this element with a given tag name + size_t numChildren(const JsonChar* tag_value, bool exc = true) const { + return m_element.numChildren(tag_value, exc); + } + /// Retrieve a collection of all attributes of this element + std::vector<Attribute> attributes() const { + return m_element.attributes(); + } + /// Access single attribute by it's name + Attribute getAttr(const JsonChar* name) const; + /// Access child by tag name. Thow an exception if required in case the child is not present + Handle_t child(const JsonChar* tag_value, bool except = true) const { + return m_element.child(tag_value, except); + } + /// Check the existence of a child with a given tag name + bool hasChild(const JsonChar* tag_value) const { + return m_element.hasChild(tag_value); + } + }; + + +#undef INLINE + + /// Forward declarations + class DocumentHandler; + + /// Dump partial or full JSON trees to stdout + void dump_tree(Handle_t elt); + /// Dump partial or full JSON trees + void dump_tree(Handle_t elt, std::ostream& os); + /// Dump partial or full JSON documents to stdout + void dump_tree(Document doc); + /// Dump partial or full JSON documents + void dump_tree(Document doc, std::ostream& os); + + } /* End namespace XML */ +} /* End namespace DD4hep */ +#endif /* DDCORE_DD4HEP_JSON_ELEMENTS_H */ diff --git a/DDCore/include/JSON/Evaluator.h b/DDCore/include/JSON/Evaluator.h new file mode 100644 index 000000000..665691919 --- /dev/null +++ b/DDCore/include/JSON/Evaluator.h @@ -0,0 +1,24 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DD4HEP_DDCORE_JSON_EVALUATOR_H +#define DD4HEP_DDCORE_JSON_EVALUATOR_H + +// Forwarding printout functionality to DD4hep +/** Note: This is necessary to use the JSON functionality as a standalone + * utility without the need to externalize the world. + * + * See the externalized header in doc/externalize for details. + */ +#include "XML/Evaluator.h" + +#endif /* DD4HEP_DDCORE_JSON_EVALUATOR_H */ diff --git a/DDCore/include/JSON/Printout.h b/DDCore/include/JSON/Printout.h new file mode 100644 index 000000000..08dd2294e --- /dev/null +++ b/DDCore/include/JSON/Printout.h @@ -0,0 +1,24 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DD4HEP_DDCORE_JSON_PRINTOUT_H +#define DD4HEP_DDCORE_JSON_PRINTOUT_H + +// Forwarding printout functionality to DD4hep +/** Note: This is necessary to use the JSON functionality as a standalone + * utility without the need to externalize the world. + * + * See the externalized header in doc/externalize for details. + */ +#include "DD4hep/Printout.h" + +#endif /* DD4HEP_DDCORE_JSON_PRINTOUT_H */ diff --git a/DDCore/include/JSON/config.h b/DDCore/include/JSON/config.h new file mode 100644 index 000000000..aa7d5e41a --- /dev/null +++ b/DDCore/include/JSON/config.h @@ -0,0 +1,35 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DD4HEP_DDCORE_JSON_CONFIG_H +#define DD4HEP_DDCORE_JSON_CONFIG_H + +#define DD4HEP_USE_BOOST_JSON 1 + +#include <boost/property_tree/json_parser.hpp> +#include <boost/property_tree/ptree.hpp> + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the AIDA detector description toolkit supporting JSON utilities + namespace JSON { + + typedef char JsonChar; + typedef boost::property_tree::ptree ptree; + typedef boost::property_tree::ptree JsonDocument; + typedef boost::property_tree::ptree::value_type JsonAttr; + typedef boost::property_tree::ptree::value_type JsonElement; + } /* End namespace JSON */ +} /* End namespace DD4hep */ + +#endif /* DD4HEP_DDCORE_JSON_CONFIG_H */ diff --git a/DDCore/src/JSON/Elements.cpp b/DDCore/src/JSON/Elements.cpp new file mode 100644 index 000000000..f3617d273 --- /dev/null +++ b/DDCore/src/JSON/Elements.cpp @@ -0,0 +1,502 @@ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include "JSON/Printout.h" +#include "JSON/Evaluator.h" +#include "JSON/Elements.h" +//#include "XML/XMLTags.h" + +// C/C++ include files +#include <iostream> +#include <stdexcept> +#include <cstdio> +#include <map> + +using namespace std; +using namespace DD4hep::JSON; +static const size_t INVALID_NODE = ~0U; + +// Forward declarations +namespace DD4hep { + XmlTools::Evaluator& evaluator(); +} +// Static storage +namespace { + XmlTools::Evaluator& eval(DD4hep::evaluator()); + string _checkEnviron(const string& env) { + string r = getEnviron(env); + return r.empty() ? env : r; + } +} + +namespace { + + JsonElement* node_first(JsonElement* e, const JsonChar* tag) { + if ( e ) { + string t(tag); + if ( t == "*" ) { + auto i = e->second.begin(); + return i != e->second.end() ? &(*i) : 0; + } + auto i = e->second.find(t); + return i != e->second.not_found() ? &(*i) : 0; + } + return 0; + } + size_t node_count(JsonElement* e, const string& t) { + return e ? (t=="*" ? e->second.size() : e->second.count(t)) : 0; + } +} + +namespace { + Attribute attribute_node(JsonElement* n, const JsonChar* t) { + auto i = n->second.find(t); + return i != n->second.not_found() ? &(*i) : 0; + } + const JsonChar* attribute_value(Attribute a) { + return a->second.get_value<std::string>().c_str(); + } +} + +string DD4hep::JSON::_toString(Attribute attr) { + if (attr) + return _toString(attribute_value(attr)); + return ""; +} + +template <typename T> static inline string __to_string(T value, const char* fmt) { + char text[128]; + ::snprintf(text, sizeof(text), fmt, value); + return text; +} + +/// Do-nothing version. Present for completeness and argument interchangeability +string DD4hep::JSON::_toString(const char* s) { + if ( !s || *s == 0 ) return ""; + else if ( !(*s == '$' && *(s+1) == '{') ) return s; + return _checkEnviron(s); +} + +/// Do-nothing version. Present for completeness and argument interchangeability +string DD4hep::JSON::_toString(const string& s) { + if ( s.length() < 3 || s[0] != '$' ) return s; + else if ( !(s[0] == '$' && s[1] == '{') ) return s; + return _checkEnviron(s); +} + +/// Format unsigned long integer to string with arbitrary format +string DD4hep::JSON::_toString(unsigned long v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format unsigned integer (32 bits) to string with arbitrary format +string DD4hep::JSON::_toString(unsigned int v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format signed integer (32 bits) to string with arbitrary format +string DD4hep::JSON::_toString(int v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format signed long integer to string with arbitrary format +string DD4hep::JSON::_toString(long v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format single procision float number (32 bits) to string with arbitrary format +string DD4hep::JSON::_toString(float v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format double procision float number (64 bits) to string with arbitrary format +string DD4hep::JSON::_toString(double v, const char* fmt) { + return __to_string(v, fmt); +} + +/// Format pointer to string with arbitrary format +string DD4hep::JSON::_ptrToString(const void* v, const char* fmt) { + return __to_string(v, fmt); +} + +long DD4hep::JSON::_toLong(const JsonChar* value) { + if (value) { + string s = _toString(value); + size_t idx = s.find("(int)"); + if (idx != string::npos) + s.erase(idx, 5); + idx = s.find("(long)"); + if (idx != string::npos) + s.erase(idx, 6); + while (s[0] == ' ') + s.erase(0, 1); + double result = eval.evaluate(s.c_str()); + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << s << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during expression evaluation of " + s); + } + return (long) result; + } + return -1; +} + +int DD4hep::JSON::_toInt(const JsonChar* value) { + if (value) { + string s = _toString(value); + size_t idx = s.find("(int)"); + if (idx != string::npos) + s.erase(idx, 5); + while (s[0] == ' ') + s.erase(0, 1); + double result = eval.evaluate(s.c_str()); + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << s << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during expression evaluation of " + s); + } + return (int) result; + } + return -1; +} + +bool DD4hep::JSON::_toBool(const JsonChar* value) { + if (value) { + string s = _toString(value); + return s == "true"; + } + return false; +} + +float DD4hep::JSON::_toFloat(const JsonChar* value) { + if (value) { + string s = _toString(value); + double result = eval.evaluate(s.c_str()); + + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << s << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during expression evaluation of " + s); + } + return (float) result; + } + return 0.0; +} + +double DD4hep::JSON::_toDouble(const JsonChar* value) { + if (value) { + string s = _toString(value); + double result = eval.evaluate(s.c_str()); + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << s << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during expression evaluation of " + s); + } + return result; + } + return 0.0; +} + +void DD4hep::JSON::_toDictionary(const JsonChar* name, const JsonChar* value) { + string n = _toString(name).c_str(), v = _toString(value); + size_t idx = v.find("(int)"); + if (idx != string::npos) + v.erase(idx, 5); + while (v[0] == ' ') + v.erase(0, 1); + double result = eval.evaluate(v.c_str()); + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << v << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during expression evaluation of " + v); + } + eval.setVariable(n.c_str(), result); +} + +template <typename T> +void DD4hep::JSON::_toDictionary(const JsonChar* name, T value) { + string item = _toString(value); + _toDictionary(name, item.c_str()); +} + +template void DD4hep::JSON::_toDictionary(const JsonChar* name, const string& value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned long value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned int value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, unsigned short value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, int value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, long value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, short value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, float value); +template void DD4hep::JSON::_toDictionary(const JsonChar* name, double value); + +/// Evaluate string constant using environment stored in the evaluator +string DD4hep::JSON::getEnviron(const string& env) { + size_t id1 = env.find("${"); + size_t id2 = env.rfind("}"); + if ( id1 == string::npos || id2 == string::npos ) { + return ""; + } + else { + string v = env.substr(0,id2+1); + const char* ret = eval.getEnviron(v.c_str()); + if (eval.status() != XmlTools::Evaluator::OK) { + cerr << env << ": "; + eval.print_error(); + throw runtime_error("DD4hep: Severe error during environment lookup of " + env); + } + v = env.substr(0,id1); + v += ret; + v += env.substr(id2+1); + return v; + } +} + +/// Copy constructor +NodeList::NodeList(const NodeList& copy) + : m_tag(copy.m_tag), m_node(copy.m_node) +{ + reset(); +} + +/// Initializing constructor +NodeList::NodeList(JsonElement* node, const string& tag_value) + : m_tag(tag_value), m_node(node) +{ + reset(); +} + +/// Default destructor +NodeList::~NodeList() { +} + +/// Reset the nodelist +JsonElement* NodeList::reset() { + if ( m_tag == "*" ) + m_ptr = make_pair(m_node->second.ordered_begin(), m_node->second.not_found()); + else + m_ptr = m_node->second.equal_range(m_tag); + if ( m_ptr.first != m_ptr.second ) + return &(*m_ptr.first); + return 0; +} + +/// Advance to next element +JsonElement* NodeList::next() const { + if ( m_ptr.first != m_ptr.second ) { + m_ptr.first = ++m_ptr.first; + if ( m_ptr.first != m_ptr.second ) return &(*m_ptr.first); + } + return 0; +} + +/// Go back to previous element +JsonElement* NodeList::previous() const { + if ( m_ptr.first != m_ptr.second ) { + m_ptr.first = --m_ptr.first; + if ( m_ptr.first != m_ptr.second ) return &(*m_ptr.first); + } + return 0; +} + +/// Assignment operator +NodeList& NodeList::operator=(const NodeList& l) { + if ( this != &l ) { + m_tag = l.m_tag; + m_node = l.m_node; + reset(); + } + return *this; +} + +/// Unicode text access to the element's tag. This must be wrong .... +const JsonChar* Handle_t::rawTag() const { + return (*m_node).first.c_str(); +} + +/// Unicode text access to the element's text +const JsonChar* Handle_t::rawText() const { + return (*m_node).second.get_value<string>().c_str(); +} + +/// Unicode text access to the element's value +const JsonChar* Handle_t::rawValue() const { + return (*m_node).second.get_value<string>().c_str(); +} + +/// Access attribute pointer by the attribute's unicode name (no exception thrown if not present) +Attribute Handle_t::attr_nothrow(const JsonChar* tag_value) const { + return attribute_node(m_node, tag_value); +} + +/// Check for the existence of a named attribute +bool Handle_t::hasAttr(const JsonChar* tag_value) const { + return m_node && 0 != node_first(m_node, tag_value); +} + +/// Retrieve a collection of all attributes of this DOM element +vector<Attribute> Handle_t::attributes() const { + vector < Attribute > attrs; + if (m_node) { + for(ptree::iterator i=m_node->second.begin(); i!=m_node->second.end(); ++i) { + Attribute a = &(*i); + attrs.push_back(a); + } + } + return attrs; +} + +size_t Handle_t::numChildren(const JsonChar* t, bool throw_exception) const { + size_t n = node_count(m_node, t); + if (n == INVALID_NODE && !throw_exception) + return 0; + else if (n != INVALID_NODE) + return n; + string msg = "Handle_t::numChildren: "; + if (m_node) + msg += "Element [" + tag() + "] has no children of type '" + _toString(t) + "'"; + else + msg += "Element [INVALID] has no children of type '" + _toString(t) + "'"; + throw runtime_error(msg); +} + +/// Remove a single child node identified by it's handle from the tree of the element +Handle_t Handle_t::child(const JsonChar* t, bool throw_exception) const { + Elt_t e = node_first(m_node, t); + if (e || !throw_exception) + return e; + string msg = "Handle_t::child: "; + if (m_node) + msg += "Element [" + tag() + "] has no child of type '" + _toString(t) + "'"; + else + msg += "Element [INVALID]. Cannot remove child of type: '" + _toString(t) + "'"; + throw runtime_error(msg); +} + +NodeList Handle_t::children(const JsonChar* tag_value) const { + return NodeList(m_node, tag_value); +} + +bool Handle_t::hasChild(const JsonChar* tag_value) const { + return node_first(m_node, tag_value) != 0; +} + +/// Access attribute pointer by the attribute's unicode name (throws exception if not present) +Attribute Handle_t::attr_ptr(const JsonChar* t) const { + Attribute a = attribute_node(m_node, t); + if (0 != a) + return a; + string msg = "Handle_t::attr_ptr: "; + if (m_node) + msg += "Element [" + tag() + "] has no attribute of type '" + _toString(t) + "'"; + else + msg += "Element [INVALID] has no attribute of type '" + _toString(t) + "'"; + throw runtime_error(msg); +} + +/// Access attribute name (throws exception if not present) +const JsonChar* Handle_t::attr_name(const Attribute a) const { + if (a) { + return (*a).first.c_str(); + } + throw runtime_error("Attempt to access invalid XML attribute object!"); +} + +/// Access attribute value by the attribute's unicode name (throws exception if not present) +const JsonChar* Handle_t::attr_value(const JsonChar* attr_tag) const { + return attribute_value(attr_ptr(attr_tag)); +} + +/// Access attribute value by the attribute (throws exception if not present) +const JsonChar* Handle_t::attr_value(const Attribute attr_val) const { + return attribute_value(attr_val); +} + +/// Access attribute value by the attribute's unicode name (no exception thrown if not present) +const JsonChar* Handle_t::attr_value_nothrow(const JsonChar* attr_tag) const { + Attribute a = attr_nothrow(attr_tag); + return a ? attribute_value(a) : 0; +} + +/// Assign new document. Old document is dropped. +DocumentHolder& DocumentHolder::assign(DOC d) { + if (m_doc) { + printout(DEBUG,"DocumentHolder","+++ Release DOM document...."); + delete m_doc; + } + m_doc = d; + return *this; +} + +/// Standard destructor - releases the document +DocumentHolder::~DocumentHolder() { + assign(0); +} + +Attribute Element::getAttr(const JsonChar* name) const { + return m_element ? attribute_node(m_element, name) : 0; +} + +Collection_t::Collection_t(Handle_t element, const char* tag_value) + : m_children(element, tag_value) { + m_node = m_children.reset(); +} + +/// Constructor over XmlElements in a node list +Collection_t::Collection_t(NodeList node_list) + : m_children(node_list) { + m_node = m_children.reset(); +} + +/// Reset the collection object to restart the iteration +Collection_t& Collection_t::reset() { + m_node = m_children.reset(); + return *this; +} + +/// Access the collection size. Avoid this call -- sloooow! +size_t Collection_t::size() const { + return Handle_t(m_children.m_node).numChildren(m_children.m_tag.c_str(), false); +} + +/// Helper function to throw an exception +void Collection_t::throw_loop_exception(const exception& e) const { + if (m_node) { + throw runtime_error(string(e.what()) + "\n" + "DD4hep: Error interpreting XML nodes of type <" + tag() + "/>"); + } + throw runtime_error(string(e.what()) + "\n" + "DD4hep: Error interpreting collections XML nodes."); +} + +void Collection_t::operator++() const { + while (m_node) { + m_node = m_children.next(); + if (m_node && m_node->second.size() > 0 ) + return; + } +} + +void Collection_t::operator--() const { + while (m_node) { + m_node = m_children.previous(); + if (m_node && m_node->second.size() > 0 ) + return; + } +} + +void Collection_t::operator++(int) const { + ++(*this); +} + +void Collection_t::operator--(int) const { + --(*this); +} -- GitLab