2c1e989cbbadb9ce96c4eda8252e1924b21f4047
[occt.git] / src / Standard / Standard_Dump.hxx
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 //!@file
23 //! The file contains interface to prepare dump output for OCCT objects. Format of the dump is JSON.
24 //!
25 //! To prepare this output, implement method DumpJson in the object and use macro functions from this file.
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 //!
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.
33 //!     It creates "key": { result of dump of the field }
34 //! - OCCT_DUMP_FIELD_VALUES_NUMERICAL. Use it for unlimited list of fields of C++ double type.
35 //!     It creates massive of values [value_1, value_2, ...]
36 //! - OCCT_DUMP_FIELD_VALUES_STRING. Use it for unlimited list of fields of TCollection_AsciiString types.
37 //!     It creates massive of values ["value_1", "value_2", ...]
38 //! - OCCT_DUMP_BASE_CLASS. Use if Dump implementation of the class is virtual, to perform ClassName::Dump() of the parent class,
39 //!     expected parameter is the parent class name.
40 //!     It creates "key": { result of dump of the field }
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.
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
49 #define OCCT_CLASS_NAME(theClass) #theClass
50
51 //! @def OCCT_DUMP_CLASS_BEGIN
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).
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 }
70
71 //! @def OCCT_DUMP_FIELD_VALUE_NUMERICAL
72 //! Append into output value: "Name": Field
73 #define OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, theField) \
74 { \
75   TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \
76   Standard_Dump::AddValuesSeparator (theOStream); \
77   theOStream << "\"" << aName << "\": " << theField; \
78 }
79
80 //! @def OCCT_DUMP_FIELD_VALUE_STRING
81 //! Append into output value: "Name": "Field"
82 #define OCCT_DUMP_FIELD_VALUE_STRING(theOStream, theField) \
83 { \
84   TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \
85   Standard_Dump::AddValuesSeparator (theOStream); \
86   theOStream << "\"" << aName << "\": \"" << theField << "\""; \
87 }
88
89 //! @def OCCT_DUMP_FIELD_VALUE_POINTER
90 //! Append into output value: "Name": "address of the pointer"
91 #define OCCT_DUMP_FIELD_VALUE_POINTER(theOStream, theField) \
92 { \
93   TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \
94   Standard_Dump::AddValuesSeparator (theOStream); \
95   theOStream << "\"" << aName << "\": \"" << Standard_Dump::GetPointerInfo (theField) << "\""; \
96 }
97
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
109 //! @def OCCT_DUMP_FIELD_VALUES_DUMPED
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.
115 #define OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, theField) \
116 { \
117   if (theDepth != 0 && (void*)(theField) != NULL) \
118   { \
119     Standard_SStream aFieldStream; \
120     (theField)->DumpJson (aFieldStream, theDepth - 1); \
121     TCollection_AsciiString aName = Standard_Dump::DumpFieldToName (#theField); \
122     Standard_Dump::DumpKeyToClass (theOStream, aName, Standard_Dump::Text (aFieldStream)); \
123   } \
124 }
125
126 //! @def OCCT_DUMP_FIELD_VALUES_NUMERICAL
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.
129 #define OCCT_DUMP_FIELD_VALUES_NUMERICAL(theOStream, theName, theCount, ...) \
130 { \
131   Standard_Dump::AddValuesSeparator (theOStream); \
132   theOStream << "\"" << theName << "\": ["; \
133   Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\
134   theOStream << "]"; \
135 }
136
137 //! @def OCCT_DUMP_FIELD_VALUES_STRING
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.
140 #define OCCT_DUMP_FIELD_VALUES_STRING(theOStream, theName, theCount, ...) \
141 { \
142   Standard_Dump::AddValuesSeparator (theOStream); \
143   theOStream << "\"" << theName << "\": ["; \
144   Standard_Dump::DumpCharacterValues (theOStream, theCount, __VA_ARGS__);\
145   theOStream << "]"; \
146 }
147
148 //! @def OCCT_DUMP_BASE_CLASS
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.
154 #define OCCT_DUMP_BASE_CLASS(theOStream, theDepth, theField) \
155 { \
156   if (theDepth != 0) \
157   { \
158     Standard_Dump::AddValuesSeparator (theOStream); \
159     theField::DumpJson (theOStream, theDepth - 1); \
160   } \
161 }
162
163 //! @def OCCT_DUMP_VECTOR_CLASS
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.
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, ...) \
168 { \
169   Standard_Dump::AddValuesSeparator (theOStream); \
170   theOStream << "\"" << theName << "\": ["; \
171   Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\
172   theOStream << "]"; \
173 }
174
175 //! Kind of key in Json string
176 enum Standard_JsonKey
177 {
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 };
187
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) {}
194
195   TCollection_AsciiString myValue; //!< current string value
196   Standard_Integer myStartPosition; //!< position of the value first char in the whole stream
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
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
245   //! @param theOStream source value
246   static Standard_EXPORT void AddValuesSeparator (Standard_OStream& theOStream);
247
248   //! Returns default prefix added for each pointer info string if short presentation of pointer used
249   static TCollection_AsciiString GetPointerPrefix() { return "0x"; }
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,
270                                               const TCollection_AsciiString& theKey,
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 
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
315 };
316
317 #endif // _Standard_Dump_HeaderFile