1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0030949: Foundation Classes - Dump improvement for OCCT classes

1. new file Standard_Dump to prepare and parse Dump in JSON format for OCCT objects
2. some presentations cover the proposed dump functionality.
3. 'bounding', 'vaspects' has '-dumpJson' field to see the DumpJson result
4. Bnd_Box constructor with min/max points is implemented to use Dump of this class in Dump BVH_Box
5. Limitation (some classes of Graphic3d, Prs3d has not full filling for DumpJson)
This commit is contained in:
nds
2019-09-19 15:13:42 +03:00
committed by bugmaster
parent c42ef16585
commit 0904aa6395
83 changed files with 1420 additions and 4 deletions

View File

@@ -24,6 +24,8 @@ Standard_DimensionError.hxx
Standard_DimensionMismatch.hxx
Standard_DivideByZero.hxx
Standard_DomainError.hxx
Standard_Dump.cxx
Standard_Dump.hxx
Standard_ErrorHandler.cxx
Standard_ErrorHandler.hxx
Standard_ExtCharacter.hxx

View File

@@ -0,0 +1,224 @@
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Standard_Dump.hxx>
#include <stdarg.h>
// =======================================================================
// function : Constructor
// purpose :
// =======================================================================
Standard_DumpSentry::Standard_DumpSentry (Standard_OStream& theOStream, const char* theClassName)
: myOStream (&theOStream)
{
(*myOStream) << "\"" << theClassName << "\": {";
}
// =======================================================================
// function : Destructor
// purpose :
// =======================================================================
Standard_DumpSentry::~Standard_DumpSentry()
{
(*myOStream) << "}";
}
// =======================================================================
// function : EndsWith
// purpose :
// =======================================================================
Standard_Boolean Standard_Dump::EndsWith (const Standard_OStream& theOStream,
const TCollection_AsciiString& theEndString)
{
Standard_SStream aStream;
aStream << theOStream.rdbuf();
TCollection_AsciiString aStreamStr = Standard_Dump::Text (aStream);
return aStreamStr.EndsWith (theEndString);
}
//=======================================================================
//function : DumpKeyToClass
//purpose :
//=======================================================================
void Standard_Dump::DumpKeyToClass (Standard_OStream& theOStream,
const char* theKey,
const TCollection_AsciiString& theField)
{
if (!Standard_Dump::EndsWith (theOStream, "{"))
theOStream << ", ";
theOStream << "\"" << theKey << "\": {" << theField << "}";
}
//=======================================================================
//function : DumpCharacterValues
//purpose :
//=======================================================================
void Standard_Dump::DumpCharacterValues (Standard_OStream& theOStream, int theCount, ...)
{
va_list vl;
va_start(vl, theCount);
for(int i = 0; i < theCount; ++i)
{
if (i > 0)
theOStream << ", ";
theOStream << "\"" << va_arg(vl, char*) << "\"";
}
va_end(vl);
}
//=======================================================================
//function : DumpRealValues
//purpose :
//=======================================================================
void Standard_Dump::DumpRealValues (Standard_OStream& theOStream, int theCount, ...)
{
va_list vl;
va_start(vl, theCount);
for(int i = 0; i < theCount; ++i)
{
if (i > 0)
theOStream << ", ";
theOStream << va_arg(vl, Standard_Real);
}
va_end(vl);
}
// =======================================================================
// function : GetPointerInfo
// purpose :
// =======================================================================
TCollection_AsciiString Standard_Dump::GetPointerInfo (const Handle(Standard_Transient)& thePointer,
const bool isShortInfo)
{
if (thePointer.IsNull())
return TCollection_AsciiString();
return GetPointerInfo (thePointer.get(), isShortInfo);
}
// =======================================================================
// function : GetPointerInfo
// purpose :
// =======================================================================
TCollection_AsciiString Standard_Dump::GetPointerInfo (const void* thePointer, const bool isShortInfo)
{
std::ostringstream aPtrStr;
aPtrStr << thePointer;
if (!isShortInfo)
return aPtrStr.str().c_str();
TCollection_AsciiString anInfoPtr (aPtrStr.str().c_str());
for (int aSymbolId = 1; aSymbolId < anInfoPtr.Length(); aSymbolId++)
{
if (anInfoPtr.Value(aSymbolId) != '0')
{
anInfoPtr = anInfoPtr.SubString (aSymbolId, anInfoPtr.Length());
anInfoPtr.Prepend (GetPointerPrefix());
return anInfoPtr;
}
}
return aPtrStr.str().c_str();
}
// =======================================================================
// DumpFieldToName
// =======================================================================
void Standard_Dump::DumpFieldToName (const char* theField, const char*& theName)
{
theName = theField;
if (theName[0] == '&')
{
theName = theName + 1;
}
if (::LowerCase (theName[0]) == 'm' && theName[1] == 'y')
{
theName = theName + 2;
}
}
// =======================================================================
// Text
// =======================================================================
TCollection_AsciiString Standard_Dump::Text (const Standard_SStream& theStream)
{
return TCollection_AsciiString (theStream.str().c_str());
}
// =======================================================================
// FormatJson
// =======================================================================
TCollection_AsciiString Standard_Dump::FormatJson (const Standard_SStream& theStream,
const Standard_Integer theIndent)
{
TCollection_AsciiString aStreamStr = Text (theStream);
TCollection_AsciiString anIndentStr;
for (Standard_Integer anIndentId = 0; anIndentId < theIndent; anIndentId++)
anIndentStr.AssignCat (' ');
TCollection_AsciiString aText;
Standard_Integer anIndentCount = 0;
Standard_Boolean isMassiveValues = Standard_False;
for (Standard_Integer anIndex = 1; anIndex < aStreamStr.Length(); anIndex++)
{
Standard_Character aSymbol = aStreamStr.Value (anIndex);
if (aSymbol == '{')
{
anIndentCount++;
aText += aSymbol;
aText += '\n';
for (int anIndent = 0; anIndent < anIndentCount; anIndent++)
aText += anIndentStr;
}
else if (aSymbol == '}')
{
anIndentCount--;
aText += '\n';
for (int anIndent = 0; anIndent < anIndentCount; anIndent++)
aText += anIndentStr;
aText += aSymbol;
}
else if (aSymbol == '[')
{
isMassiveValues = Standard_True;
aText += aSymbol;
}
else if (aSymbol == ']')
{
isMassiveValues = Standard_False;
aText += aSymbol;
}
else if (aSymbol == ',')
{
if (!isMassiveValues)
{
aText += aSymbol;
aText += '\n';
for (int anIndent = 0; anIndent < anIndentCount; anIndent++)
aText += anIndentStr;
if (anIndex + 1 < aStreamStr.Length() && aStreamStr.Value (anIndex + 1) == ' ')
anIndex++; // skip empty value after comma
}
else
aText += aSymbol;
}
else
aText += aSymbol;
}
return aText;
}

View File

@@ -0,0 +1,245 @@
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _Standard_Dump_HeaderFile
#define _Standard_Dump_HeaderFile
#include <Standard_SStream.hxx>
#include <TCollection_AsciiString.hxx>
class Standard_DumpSentry;
//! The file contains interface to prepare dump output for OCCT objects. Format of the dump is JSON.
//! To prepare this output, implement method Dump in the object and use macro functions from this file.
//! Macros have one parameter for both, key and the value. It is a field of the current class. Macro has internal analyzer that
//! uses the variable name to generate key. If the parameter has prefix symbols "&", "*" and "my", it is cut.
//!
//! - DUMP_FIELD_VALUE_NUMERICAL. Use it for fields of numerical C++ types, like int, float, double. It creates a pair "key", "value",
//! - DUMP_FIELD_VALUE_STRING. Use it for char* type. It creates a pair "key", "value",
//! - DUMP_FIELD_VALUE_POINTER. Use it for pointer fields. It creates a pair "key", "value", where the value is the pointer address,
//! - DUMP_FIELD_VALUES_DUMPED. Use it for fields that has own Dump implementation. It expects the pointer to the class instance.
//! It creates "key": { result of dump of the field }
//! - DUMP_FIELD_VALUES_NUMERICAL. Use it for unlimited list of fields of C++ double type.
//! It creates massive of values [value_1, value_2, ...]
//! - DUMP_FIELD_VALUES_STRING. Use it for unlimited list of fields of TCollection_AsciiString types.
//! It creates massive of values ["value_1", "value_2", ...]
//! - DUMP_FIELD_VALUES_BY_KIND. Use if Dump implementation of the class is virtual, to perform ClassName::Dump() of the parent class,
//! expected parameter is the parent class name.
//! It creates "key": { result of dump of the field }
//! - DUMP_VECTOR_CLASS. Use it as a single row in some object dump to have one row in output.
//! It's possible to use it without necessity of DUMP_CLASS_BEGIN call.
//! It creates massive of values [value_1, value_2, ...]
//!
//! The Dump result prepared by these macros is an output stream, it is not arranged with spaces and line feed.
//! To have output in a more readable way, use ConvertToAlignedString method for obtained stream.
//! Converts the class type into a string value
#define CLASS_NAME(theClass) #theClass
//! @def DUMP_CLASS_BEGIN
//! Creates an instance of Sentry to cover the current Dump implementation with keys of start and end.
//! This row should be inserted before other macros. The end key will be added by the sentry remove,
//! (exit of the method).
#define DUMP_CLASS_BEGIN(theOStream, theName) \
Standard_DumpSentry aSentry (theOStream, CLASS_NAME(theName)); \
//! @def DUMP_FIELD_VALUE_NUMERICAL
//! Append into output value: "Name": Field
#define DUMP_FIELD_VALUE_NUMERICAL(theOStream, theField) \
{ \
const char* aName = NULL; \
Standard_Dump::DumpFieldToName (#theField, aName); \
if (!Standard_Dump::EndsWith (theOStream, "{")) \
theOStream << ", "; \
theOStream << "\"" << aName << "\": " << theField; \
}
//! @def DUMP_FIELD_VALUE_STRING
//! Append into output value: "Name": "Field"
#define DUMP_FIELD_VALUE_STRING(theOStream, theField) \
{ \
const char* aName = NULL; \
Standard_Dump::DumpFieldToName (#theField, aName); \
if (!Standard_Dump::EndsWith (theOStream, "{")) \
theOStream << ", "; \
theOStream << "\"" << aName << "\": \"" << theField << "\""; \
}
//! @def DUMP_FIELD_VALUE_POINTER
//! Append into output value: "Name": "address of the pointer"
#define DUMP_FIELD_VALUE_POINTER(theOStream, theField) \
{ \
const char* aName = NULL; \
Standard_Dump::DumpFieldToName (#theField, aName); \
if (!Standard_Dump::EndsWith (theOStream, "{")) \
theOStream << ", "; \
theOStream << "\"" << aName << "\": \"" << Standard_Dump::GetPointerInfo (theField) << "\""; \
}
//! @def DUMP_FIELD_VALUES_DUMPED
//! Append into output value: "Name": { field dumped values }
//! It computes Dump of the fields. The expected field is a pointer.
//! Use this macro for fields of the dumped class which has own Dump implementation.
//! The macros is recursive. Recursion is stopped when the depth value becomes equal to zero.
//! Depth = -1 is the default value, dump here is unlimited.
#define DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, theField) \
{ \
if (theDepth != 0) \
{ \
Standard_SStream aFieldStream; \
if ((theField) != NULL) \
(theField)->DumpJson (aFieldStream, theDepth - 1); \
const char* aName = NULL; \
Standard_Dump::DumpFieldToName (#theField, aName); \
Standard_Dump::DumpKeyToClass (theOStream, aName, Standard_Dump::Text (aFieldStream)); \
} \
}
//! @def DUMP_FIELD_VALUES_NUMERICAL
//! Append real values into output values in an order: [value_1, value_2, ...]
//! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump.
#define DUMP_FIELD_VALUES_NUMERICAL(theOStream, theName, theCount, ...) \
{ \
if (!Standard_Dump::EndsWith (theOStream, "{")) \
theOStream << ", "; \
theOStream << "\"" << theName << "\": ["; \
Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\
theOStream << "]"; \
}
//! @def DUMP_FIELD_VALUES_STRING
//! Append real values into output values in an order: ["value_1", "value_2", ...]
//! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump.
#define DUMP_FIELD_VALUES_STRING(theOStream, theName, theCount, ...) \
{ \
if (!Standard_Dump::EndsWith (theOStream, "{")) \
theOStream << ", "; \
theOStream << "\"" << theName << "\": ["; \
Standard_Dump::DumpCharacterValues (theOStream, theCount, __VA_ARGS__);\
theOStream << "]"; \
}
//! @def DUMP_FIELD_VALUES_BY_KIND
//! Append into output value: "Name": { field dumped values }
//! It computes Dump of the parent. The expected field is a parent class name to call ClassName::Dump.
//! Use this macro for parent of the current class.
//! The macros is recursive. Recursive is stoped when the depth value becomes equal to zero.
//! Depth = -1 is the default value, dump here is unlimited.
#define DUMP_FIELD_VALUES_BY_KIND(theOStream, theDepth, theField) \
{ \
if (theDepth != 0) \
{ \
Standard_SStream aFieldStream; \
theField::DumpJson (aFieldStream, theDepth - 1); \
const char* aName = NULL; \
Standard_Dump::DumpFieldToName (#theField, aName); \
Standard_Dump::DumpKeyToClass (theOStream, aName, Standard_Dump::Text (aFieldStream)); \
} \
}
//! @def DUMP_VECTOR_CLASS
//! Append vector values into output value: "Name": [value_1, value_2, ...]
//! This macro is intended to have only one row for dumped object in Json.
//! It's possible to use it without necessity of DUMP_CLASS_BEGIN call, but pay attention that it should be only one row in the object dump.
#define DUMP_VECTOR_CLASS(theOStream, theName, theCount, ...) \
{ \
theOStream << "\"" << CLASS_NAME(theName) << "\": ["; \
Standard_Dump::DumpRealValues (theOStream, theCount, __VA_ARGS__);\
theOStream << "]"; \
}
//! @brief Simple sentry class providing convenient interface to dump.
//! Appends start and last rows in dump with class name key.
//! An example of the using: for ClassName, the result is: "ClassName" { ... }
//! Create instance of that class in the first row of Dump.
class Standard_DumpSentry
{
public:
//! Constructor - add parameters of start class name definition in the stream
Standard_EXPORT Standard_DumpSentry (Standard_OStream& theOStream, const char* theClassName);
//! Destructor - add parameters of stop class name definition in the stream
Standard_EXPORT ~Standard_DumpSentry();
private:
Standard_OStream* myOStream; //!< modified stream
};
//! This interface has some tool methods for stream (in JSON format) processing.
class Standard_Dump
{
public:
//! Converts stream value to string value. The result is original stream value.
//! @param theStream source value
//! @return text presentation
Standard_EXPORT static TCollection_AsciiString Text (const Standard_SStream& theStream);
//! Converts stream value to string value. Improves the text presentation with the following cases:
//! - for '{' append after '\n' and indent to the next value, increment current indent value
//! - for '}' append '\n' and current indent before it, decrement indent value
//! - for ',' append after '\n' and indent to the next value. If the current symbol is in massive container [], do nothing
//! @param theStream source value
//! @param theIndent count of ' ' symbols to apply hierarchical indent of the text values
//! @return text presentation
Standard_EXPORT static TCollection_AsciiString FormatJson (const Standard_SStream& theStream, const Standard_Integer theIndent = 3);
//! Determines whether the end of this stream matches the specified string.
//! @param theStream source value
//! @param theEndString text value to find
//! @return true if matches
static Standard_EXPORT Standard_Boolean EndsWith (const Standard_OStream& theOStream,
const TCollection_AsciiString& theEndString);
//! Returns default prefix added for each pointer info string if short presentation of pointer used
Standard_EXPORT static TCollection_AsciiString GetPointerPrefix() { return "0x"; }
//! Convert handle pointer to address of the pointer. If the handle is NULL, the result is an empty string.
//! @param thePointer a pointer
//! @param isShortInfo if true, all '0' symbols in the beginning of the pointer are skipped
//! @return the string value
Standard_EXPORT static TCollection_AsciiString GetPointerInfo (const Handle(Standard_Transient)& thePointer,
const bool isShortInfo = true);
//! Convert pointer to address of the pointer. If the handle is NULL, the result is an empty string.
//! @param thePointer a pointer
//! @param isShortInfo if true, all '0' symbols in the beginning of the pointer are skipped
//! @return the string value
Standard_EXPORT static TCollection_AsciiString GetPointerInfo (const void* thePointer,
const bool isShortInfo = true);
//! Append into output value: "Name": { Field }
//! @param theOStream [out] stream to be fill with values
//! @param theKey a source value
//! @param theField stream value
Standard_EXPORT static void DumpKeyToClass (Standard_OStream& theOStream,
const char* theKey,
const TCollection_AsciiString& theField);
//! Unite values in one value using template: "value_1", "value_2", ..., "value_n"
//! @param theOStream [out] stream to be fill with values
//! @param theCount numer of values
Standard_EXPORT static void DumpCharacterValues (Standard_OStream& theOStream, int theCount, ...);
//! Unite values in one value using template: value_1, value_2, ..., value_n
//! @param theOStream [out] stream to be fill with values
//! @param theCount numer of values
Standard_EXPORT static void DumpRealValues (Standard_OStream& theOStream, int theCount, ...);
//! Convert field name into dump text value, removes "&" and "my" prefixes
//! An example, for field myValue, theName is Value, for &myCLass, the name is Class
//! @param theField a source value
//! @param theName [out] an updated name
Standard_EXPORT static void DumpFieldToName (const char* theField, const char*& theName);
};
#endif // _Standard_Dump_HeaderFile