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