| 1 | // Copyright (c) 2019 OPEN CASCADE SAS |
| 2 | // |
| 3 | // This file is part of Open CASCADE Technology software library. |
| 4 | // |
| 5 | // This library is free software; you can redistribute it and/or modify it under |
| 6 | // the terms of the GNU Lesser General Public License version 2.1 as published |
| 7 | // by the Free Software Foundation, with special exception defined in the file |
| 8 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
| 9 | // distribution for complete text of the license and disclaimer of any warranty. |
| 10 | // |
| 11 | // Alternatively, this file may be used under the terms of Open CASCADE |
| 12 | // commercial license or contractual agreement. |
| 13 | |
| 14 | #ifndef _Standard_Dump_HeaderFile |
| 15 | #define _Standard_Dump_HeaderFile |
| 16 | |
| 17 | #include <NCollection_IndexedDataMap.hxx> |
| 18 | #include <NCollection_List.hxx> |
| 19 | #include <Standard_SStream.hxx> |
| 20 | #include <TCollection_AsciiString.hxx> |
| 21 | |
| 22 | //! The file contains interface to prepare dump output for OCCT objects. Format of the dump is JSON. |
| 23 | //! To prepare this output, implement method DumpJson in the object and use macro functions from this file. |
| 24 | //! Macros have one parameter for both, key and the value. It is a field of the current class. Macro has internal analyzer that |
| 25 | //! uses the variable name to generate key. If the parameter has prefix symbols "&", "*" and "my", it is cut. |
| 26 | //! |
| 27 | //! - OCCT_DUMP_FIELD_VALUE_NUMERICAL. Use it for fields of numerical C++ types, like int, float, double. It creates a pair "key", "value", |
| 28 | //! - OCCT_DUMP_FIELD_VALUE_STRING. Use it for char* type. It creates a pair "key", "value", |
| 29 | //! - OCCT_DUMP_FIELD_VALUE_POINTER. Use it for pointer fields. It creates a pair "key", "value", where the value is the pointer address, |
| 30 | //! - OCCT_DUMP_FIELD_VALUES_DUMPED. Use it for fields that has own Dump implementation. It expects the pointer to the class instance. |
| 31 | //! It creates "key": { result of dump of the field } |
| 32 | //! - OCCT_DUMP_FIELD_VALUES_NUMERICAL. Use it for unlimited list of fields of C++ double type. |
| 33 | //! It creates massive of values [value_1, value_2, ...] |
| 34 | //! - OCCT_DUMP_FIELD_VALUES_STRING. Use it for unlimited list of fields of TCollection_AsciiString types. |
| 35 | //! It creates massive of values ["value_1", "value_2", ...] |
| 36 | //! - OCCT_DUMP_BASE_CLASS. Use if Dump implementation of the class is virtual, to perform ClassName::Dump() of the parent class, |
| 37 | //! expected parameter is the parent class name. |
| 38 | //! It creates "key": { result of dump of the field } |
| 39 | //! - OCCT_DUMP_VECTOR_CLASS. Use it as a single row in some object dump to have one row in output. |
| 40 | //! It's possible to use it without necessity of OCCT_DUMP_CLASS_BEGIN call. |
| 41 | //! It creates massive of values [value_1, value_2, ...] |
| 42 | //! |
| 43 | //! The Dump result prepared by these macros is an output stream, it is not arranged with spaces and line feed. |
| 44 | //! To have output in a more readable way, use ConvertToAlignedString method for obtained stream. |
| 45 | |
| 46 | //! Converts the class type into a string value |
| 47 | #define OCCT_CLASS_NAME(theClass) #theClass |
| 48 | |
| 49 | //! @def OCCT_DUMP_CLASS_BEGIN |
| 50 | //! Creates an instance of Sentry to cover the current Dump implementation with keys of start and end. |
| 51 | //! This row should be inserted before other macros. The end key will be added by the sentry remove, |
| 52 | //! (exit of the method). |
| 53 | #define OCCT_DUMP_CLASS_BEGIN(theOStream, theField) \ |
| 54 | { \ |
| 55 | const char* className = OCCT_CLASS_NAME(theField); \ |
| 56 | OCCT_DUMP_FIELD_VALUE_STRING (theOStream, className) \ |
| 57 | } |
| 58 | |
| 59 | //! @def OCCT_DUMP_TRANSIENT_CLASS_BEGIN |
| 60 | //! Creates an instance of Sentry to cover the current Dump implementation with keys of start and end. |
| 61 | //! This row should be inserted before other macros. The end key will be added by the sentry remove, |
| 62 | //! (exit of the method). |
| 63 | #define OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream) \ |
| 64 | { \ |
| 65 | const char* className = get_type_name(); \ |
| 66 | OCCT_DUMP_FIELD_VALUE_STRING (theOStream, className) \ |
| 67 | } |
| 68 | |
| 69 | //! @def OCCT_DUMP_FIELD_VALUE_NUMERICAL |
| 70 | //! Append into output value: "Name": Field |
| 71 | #define OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, theField) \ |
| 72 | { \ |
| 73 | TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \ |
| 74 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 75 | theOStream << "\"" << aName << "\": " << theField; \ |
| 76 | } |
| 77 | |
| 78 | //! @def OCCT_DUMP_FIELD_VALUE_STRING |
| 79 | //! Append into output value: "Name": "Field" |
| 80 | #define OCCT_DUMP_FIELD_VALUE_STRING(theOStream, theField) \ |
| 81 | { \ |
| 82 | TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \ |
| 83 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 84 | theOStream << "\"" << aName << "\": \"" << theField << "\""; \ |
| 85 | } |
| 86 | |
| 87 | //! @def OCCT_DUMP_FIELD_VALUE_POINTER |
| 88 | //! Append into output value: "Name": "address of the pointer" |
| 89 | #define OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, theField) \ |
| 90 | { \ |
| 91 | TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \ |
| 92 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 93 | theOStream << "\"" << aName << "\": \"" << Standard_Dump::GetPointerInfo (theField) << "\""; \ |
| 94 | } |
| 95 | |
| 96 | //! @def OCCT_DUMP_FIELD_VALUE_STRING |
| 97 | //! Append into output value: "Name": "Field" |
| 98 | #define OCCT_DUMP_FIELD_VALUE_GUID(theOStream, theField) \ |
| 99 | { \ |
| 100 | TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \ |
| 101 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 102 | char aStr[Standard_GUID_SIZE_ALLOC]; \ |
| 103 | theField.ToCString (aStr); \ |
| 104 | theOStream << "\"" << aName << "\": \"" << aStr << "\""; \ |
| 105 | } |
| 106 | |
| 107 | //! @def OCCT_DUMP_FIELD_VALUES_DUMPED |
| 108 | //! Append into output value: "Name": { field dumped values } |
| 109 | //! It computes Dump of the fields. The expected field is a pointer. |
| 110 | //! Use this macro for fields of the dumped class which has own Dump implementation. |
| 111 | //! The macros is recursive. Recursion is stopped when the depth value becomes equal to zero. |
| 112 | //! Depth = -1 is the default value, dump here is unlimited. |
| 113 | #define OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, theField) \ |
| 114 | { \ |
| 115 | if (theDepth != 0 && (void*)(theField) != NULL) \ |
| 116 | { \ |
| 117 | Standard_SStream aFieldStream; \ |
| 118 | (theField)->DumpJson (aFieldStream, theDepth - 1); \ |
| 119 | TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \ |
| 120 | Standard_Dump::DumpKeyToClass (theOStream, aName, Standard_Dump::Text (aFieldStream)); \ |
| 121 | } \ |
| 122 | } |
| 123 | |
| 124 | //! @def OCCT_DUMP_FIELD_VALUES_NUMERICAL |
| 125 | //! Append real values into output values in an order: [value_1, value_2, ...] |
| 126 | //! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump. |
| 127 | #define OCCT_DUMP_FIELD_VALUES_NUMERICAL(theOStream, theName, theCount, ...) \ |
| 128 | { \ |
| 129 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 130 | theOStream << "\"" << theName << "\": ["; \ |
| 131 | Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\ |
| 132 | theOStream << "]"; \ |
| 133 | } |
| 134 | |
| 135 | //! @def OCCT_DUMP_FIELD_VALUES_STRING |
| 136 | //! Append real values into output values in an order: ["value_1", "value_2", ...] |
| 137 | //! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump. |
| 138 | #define OCCT_DUMP_FIELD_VALUES_STRING(theOStream, theName, theCount, ...) \ |
| 139 | { \ |
| 140 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 141 | theOStream << "\"" << theName << "\": ["; \ |
| 142 | Standard_Dump::DumpCharacterValues (theOStream, theCount, __VA_ARGS__);\ |
| 143 | theOStream << "]"; \ |
| 144 | } |
| 145 | |
| 146 | //! @def OCCT_DUMP_BASE_CLASS |
| 147 | //! Append into output value: "Name": { field dumped values } |
| 148 | //! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump. |
| 149 | //! Use this macro for parent of the current class. |
| 150 | //! The macros is recursive. Recursive is stoped when the depth value becomes equal to zero. |
| 151 | //! Depth = -1 is the default value, dump here is unlimited. |
| 152 | #define OCCT_DUMP_BASE_CLASS(theOStream, theDepth, theField) \ |
| 153 | { \ |
| 154 | if (theDepth != 0) \ |
| 155 | { \ |
| 156 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 157 | theField::DumpJson (theOStream, theDepth - 1); \ |
| 158 | } \ |
| 159 | } |
| 160 | |
| 161 | //! @def OCCT_DUMP_VECTOR_CLASS |
| 162 | //! Append vector values into output value: "Name": [value_1, value_2, ...] |
| 163 | //! This macro is intended to have only one row for dumped object in Json. |
| 164 | //! It's possible to use it without necessity of OCCT_DUMP_CLASS_BEGIN call, but pay attention that it should be only one row in the object dump. |
| 165 | #define OCCT_DUMP_VECTOR_CLASS(theOStream, theName, theCount, ...) \ |
| 166 | { \ |
| 167 | Standard_Dump::AddValuesSeparator (theOStream); \ |
| 168 | theOStream << "\"" << theName << "\": ["; \ |
| 169 | Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\ |
| 170 | theOStream << "]"; \ |
| 171 | } |
| 172 | |
| 173 | //! Kind of key in Json string |
| 174 | enum Standard_JsonKey |
| 175 | { |
| 176 | Standard_JsonKey_None, //!< no key |
| 177 | Standard_JsonKey_OpenChild, //!< "{" |
| 178 | Standard_JsonKey_CloseChild, //!< "}" |
| 179 | Standard_JsonKey_OpenContainer, //!< "[" |
| 180 | Standard_JsonKey_CloseContainer, //!< "]" |
| 181 | Standard_JsonKey_Quote, //!< "\"" |
| 182 | Standard_JsonKey_SeparatorKeyToValue, //!< ": " |
| 183 | Standard_JsonKey_SeparatorValueToValue //!< ", " |
| 184 | }; |
| 185 | |
| 186 | //! Type for storing a dump value with the stream position |
| 187 | struct Standard_DumpValue |
| 188 | { |
| 189 | Standard_DumpValue() : myStartPosition (0) {} |
| 190 | Standard_DumpValue (const TCollection_AsciiString& theValue, const Standard_Integer theStartPos) |
| 191 | : myValue (theValue), myStartPosition (theStartPos) {} |
| 192 | |
| 193 | TCollection_AsciiString myValue; //!< current string value |
| 194 | Standard_Integer myStartPosition; //!< position of the value first char in the whole stream |
| 195 | }; |
| 196 | |
| 197 | //! This interface has some tool methods for stream (in JSON format) processing. |
| 198 | class Standard_Dump |
| 199 | { |
| 200 | public: |
| 201 | //! Converts stream value to string value. The result is original stream value. |
| 202 | //! @param theStream source value |
| 203 | //! @return text presentation |
| 204 | Standard_EXPORT static TCollection_AsciiString Text (const Standard_SStream& theStream); |
| 205 | |
| 206 | //! Converts stream value to string value. Improves the text presentation with the following cases: |
| 207 | //! - for '{' append after '\n' and indent to the next value, increment current indent value |
| 208 | //! - for '}' append '\n' and current indent before it, decrement indent value |
| 209 | //! - for ',' append after '\n' and indent to the next value. If the current symbol is in massive container [], do nothing |
| 210 | //! @param theStream source value |
| 211 | //! @param theIndent count of ' ' symbols to apply hierarchical indent of the text values |
| 212 | //! @return text presentation |
| 213 | Standard_EXPORT static TCollection_AsciiString FormatJson (const Standard_SStream& theStream, const Standard_Integer theIndent = 3); |
| 214 | |
| 215 | //! Converts stream into map of values. Values are not empty if the stream contains at least two values. |
| 216 | //! |
| 217 | //! The one level stream example: <class_name>key_1\value_1\key_2\value_2</class_name> |
| 218 | //! In output: theStreamKey equals class_name, theValues contains key_1, value_1, key_2, and value_2. |
| 219 | //! |
| 220 | //! Two level stream example: <class_name>key_1\value_1\key_2\value_2\key_3<subclass_name>subclass_key_1\subclass_value1</subclass_name></class_name> |
| 221 | //! In output: theStreamKey equals class_name, theValues contains key_1, value_1, key_2, and value_2, key_3 and |
| 222 | //! <subclass_name>subclass_key_1\subclass_value1</subclass_name>. |
| 223 | //! The last value might be processed later using the same method. |
| 224 | //! |
| 225 | //! @param theStream stream value |
| 226 | //! @param theKeyToValues [out] container of split values |
| 227 | Standard_EXPORT static Standard_Boolean SplitJson (const TCollection_AsciiString& theStreamStr, |
| 228 | NCollection_IndexedDataMap<TCollection_AsciiString, Standard_DumpValue>& theKeyToValues); |
| 229 | |
| 230 | //! Returns container of indices in values, that has hierarchical value |
| 231 | Standard_EXPORT static NCollection_List<Standard_Integer> HierarchicalValueIndices ( |
| 232 | const NCollection_IndexedDataMap<TCollection_AsciiString, TCollection_AsciiString>& theValues); |
| 233 | |
| 234 | //! Returns true if the value has bracket key |
| 235 | Standard_EXPORT static Standard_Boolean HasChildKey (const TCollection_AsciiString& theSourceValue); |
| 236 | |
| 237 | //! Returns key value for enum type |
| 238 | Standard_EXPORT static Standard_CString JsonKeyToString (const Standard_JsonKey theKey); |
| 239 | |
| 240 | //! Returns length value for enum type |
| 241 | Standard_EXPORT static Standard_Integer JsonKeyLength (const Standard_JsonKey theKey); |
| 242 | |
| 243 | //! @param theStream source value |
| 244 | static Standard_EXPORT void AddValuesSeparator (Standard_OStream& theOStream); |
| 245 | |
| 246 | //! Returns default prefix added for each pointer info string if short presentation of pointer used |
| 247 | static TCollection_AsciiString GetPointerPrefix() { return "0x"; } |
| 248 | |
| 249 | //! Convert handle pointer to address of the pointer. If the handle is NULL, the result is an empty string. |
| 250 | //! @param thePointer a pointer |
| 251 | //! @param isShortInfo if true, all '0' symbols in the beginning of the pointer are skipped |
| 252 | //! @return the string value |
| 253 | Standard_EXPORT static TCollection_AsciiString GetPointerInfo (const Handle(Standard_Transient)& thePointer, |
| 254 | const bool isShortInfo = true); |
| 255 | |
| 256 | //! Convert pointer to address of the pointer. If the handle is NULL, the result is an empty string. |
| 257 | //! @param thePointer a pointer |
| 258 | //! @param isShortInfo if true, all '0' symbols in the beginning of the pointer are skipped |
| 259 | //! @return the string value |
| 260 | Standard_EXPORT static TCollection_AsciiString GetPointerInfo (const void* thePointer, |
| 261 | const bool isShortInfo = true); |
| 262 | |
| 263 | //! Append into output value: "Name": { Field } |
| 264 | //! @param theOStream [out] stream to be fill with values |
| 265 | //! @param theKey a source value |
| 266 | //! @param theField stream value |
| 267 | Standard_EXPORT static void DumpKeyToClass (Standard_OStream& theOStream, |
| 268 | const TCollection_AsciiString& theKey, |
| 269 | const TCollection_AsciiString& theField); |
| 270 | |
| 271 | //! Unite values in one value using template: "value_1", "value_2", ..., "value_n" |
| 272 | //! @param theOStream [out] stream to be fill with values |
| 273 | //! @param theCount numer of values |
| 274 | Standard_EXPORT static void DumpCharacterValues (Standard_OStream& theOStream, int theCount, ...); |
| 275 | |
| 276 | //! Unite values in one value using template: value_1, value_2, ..., value_n |
| 277 | //! @param theOStream [out] stream to be fill with values |
| 278 | //! @param theCount numer of values |
| 279 | Standard_EXPORT static void DumpRealValues (Standard_OStream& theOStream, int theCount, ...); |
| 280 | |
| 281 | //! Convert field name into dump text value, removes "&" and "my" prefixes |
| 282 | //! An example, for field myValue, theName is Value, for &myCLass, the name is Class |
| 283 | //! @param theField a source value |
| 284 | //! @param theName [out] an updated name |
| 285 | Standard_EXPORT static TCollection_AsciiString DumpFieldToName (const TCollection_AsciiString& theField); |
| 286 | |
| 287 | private: |
| 288 | //! Extracts from the string value a pair (key, value), add it into output container, update index value |
| 289 | //! Example: |
| 290 | //! stream string starting the index position contains: ..."key": <value>... |
| 291 | //! a pair key, value will be added into theValues |
| 292 | //! at beginning theIndex is the position of the quota before <key>, after the index is the next position after the value |
| 293 | //! splitDumped(aString) gives theSplitValue = "abc", theTailValue = "defg", theKey = "key" |
| 294 | Standard_EXPORT static Standard_Boolean splitKeyToValue (const TCollection_AsciiString& theStreamStr, |
| 295 | Standard_Integer theStartIndex, |
| 296 | Standard_Integer& theNextIndex, |
| 297 | NCollection_IndexedDataMap<TCollection_AsciiString, Standard_DumpValue>& theValues); |
| 298 | |
| 299 | |
| 300 | //! Returns key of json in the index position. Incement the index position to the next symbol in the row |
| 301 | Standard_EXPORT static Standard_Boolean jsonKey (const TCollection_AsciiString& theStreamStr, |
| 302 | Standard_Integer theStartIndex, |
| 303 | Standard_Integer& theNextIndex, |
| 304 | Standard_JsonKey& theKey); |
| 305 | |
| 306 | //! Find position in the source string of the symbol close after the start position. |
| 307 | //! Ignore combination <symbol open> ... <symbol close> between the close symbol. |
| 308 | //! Example, for case ... { ... { ... } ...} ... } it returns the position of the forth brace |
| 309 | Standard_EXPORT static Standard_Integer nextClosePosition (const TCollection_AsciiString& theSourceValue, |
| 310 | const Standard_Integer theStartPosition, |
| 311 | const Standard_JsonKey theCloseKey, |
| 312 | const Standard_JsonKey theOpenKey); |
| 313 | |
| 314 | }; |
| 315 | |
| 316 | #endif // _Standard_Dump_HeaderFile |