Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coding - Improve type checking in IsInstance method and add Info method to Standard_Type #20

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
5 changes: 2 additions & 3 deletions src/BinMDataStd/BinMDataStd_GenericExtStringDriver.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ Handle(TDF_Attribute) BinMDataStd_GenericExtStringDriver::NewEmpty() const
//function : SourceType
//purpose :
//=======================================================================
Handle(Standard_Type)& BinMDataStd_GenericExtStringDriver::SourceType() const
const Handle(Standard_Type)& BinMDataStd_GenericExtStringDriver::SourceType() const
{
static Handle(Standard_Type) aSourceType = Standard_Type::Instance<TDataStd_GenericExtString>();
return aSourceType;
return Standard_Type::Instance<TDataStd_GenericExtString>();
}

//=======================================================================
Expand Down
2 changes: 1 addition & 1 deletion src/BinMDataStd/BinMDataStd_GenericExtStringDriver.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public:

Standard_EXPORT Handle(TDF_Attribute) NewEmpty() const Standard_OVERRIDE;

Standard_EXPORT virtual Handle(Standard_Type)& SourceType() const Standard_OVERRIDE;
Standard_EXPORT virtual const Handle(Standard_Type)& SourceType() const Standard_OVERRIDE;

//! persistent -> transient (retrieve)
Standard_EXPORT Standard_Boolean Paste (const BinObjMgt_Persistent& Source, const Handle(TDF_Attribute)& Target, BinObjMgt_RRelocationTable& RelocTable) const Standard_OVERRIDE;
Expand Down
3 changes: 1 addition & 2 deletions src/Interface/Interface_InterfaceModel.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ static NCollection_DataMap<TCollection_AsciiString, Handle(Standard_Transient)>

static const Handle(Standard_Type)& typerep()
{
static Handle(Standard_Type) tr = STANDARD_TYPE(Interface_ReportEntity);
return tr;
return STANDARD_TYPE(Interface_ReportEntity);
}


Expand Down
5 changes: 3 additions & 2 deletions src/Standard/Standard_Transient.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

const Handle(Standard_Type)& Standard_Transient::get_type_descriptor ()
{
return opencascade::type_instance<Standard_Transient>::get();
static const Handle(Standard_Type) THE_TYPE_INSTANCE = Standard_Type::Register (typeid(Standard_Transient), get_type_name(), sizeof(Standard_Transient), nullptr);
return THE_TYPE_INSTANCE;
}

//
Expand All @@ -34,7 +35,7 @@ const Handle(Standard_Type)& Standard_Transient::DynamicType() const
//
Standard_Boolean Standard_Transient::IsInstance(const Handle(Standard_Type) &AType) const
{
return (AType == DynamicType());
return DynamicType() == AType;
}

//
Expand Down
108 changes: 64 additions & 44 deletions src/Standard/Standard_Type.cxx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (c) 1998-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
// Copyright (c) 1999-2025 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
Expand All @@ -12,96 +12,116 @@
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.


#include <Standard_Type.hxx>
#include <Standard_Mutex.hxx>
#include <Standard_Assert.hxx>
#include <Standard_Mutex.hxx>
#include <Standard_Type.hxx>

#include <unordered_map>

IMPLEMENT_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)

//============================================================================
IMPLEMENT_STANDARD_RTTIEXT(Standard_Type, Standard_Transient)

Standard_Type::Standard_Type (const std::type_info& theInfo,
const char* theName,
Standard_Size theSize,
const Handle(Standard_Type)& theParent) :
myInfo(theInfo),
Standard_Type::Standard_Type(const std::type_info& theInfo,
const char* theName,
Standard_Size theSize,
const Handle(Standard_Type)& theParent)
: myInfo(theInfo),
myName(theName),
mySize(theSize),
mySize(theSize),
myLevel(theParent.IsNull() ? 0 : theParent->myLevel + 1),
myParent(theParent)
{
}

//============================================================================
{}

Standard_Boolean Standard_Type::SubType (const Handle(Standard_Type)& theOther) const
Standard_Boolean Standard_Type::SubType(const Handle(Standard_Type)& theOther) const
{
return ! theOther.IsNull() && (theOther == this || (! myParent.IsNull() && myParent->SubType (theOther)));
if (theOther.IsNull())
{
return false;
}
const Standard_Type* aTypeIter = this;
while (aTypeIter && theOther->myLevel <= aTypeIter->myLevel && theOther->mySize <= aTypeIter->mySize)
{
if (theOther.get() == aTypeIter)
{
return true;
}
aTypeIter = aTypeIter->Parent().get();
}
return false;
}

//============================================================================

Standard_Boolean Standard_Type::SubType (const Standard_CString theName) const
Standard_Boolean Standard_Type::SubType(const Standard_CString theName) const
{
return theName != 0 && (IsEqual (myName, theName) || (! myParent.IsNull() && myParent->SubType (theName)));
const Standard_Type* aTypeIter = this;
do
{
if (IsEqual(theName, aTypeIter->Name()))
{
return true;
}
aTypeIter = aTypeIter->Parent().get();
} while (aTypeIter);
return false;
}

// ------------------------------------------------------------------
// Print (me; s: in out OStream) returns OStream;
// ------------------------------------------------------------------
void Standard_Type::Print (Standard_OStream& AStream) const
void Standard_Type::Print(Standard_OStream& AStream) const
{
AStream << std::hex << (Standard_Address)this << " : " << std::dec << myName ;
AStream << std::hex << (Standard_Address)this << " : " << std::dec << myName;
}

//============================================================================
// Registry of types
//============================================================================

namespace {
namespace
{
// Map of string to type
typedef std::unordered_map<std::type_index, Standard_Type*> registry_type;

// Registry is made static in the function to ensure that it gets
// initialized by the time of first access
registry_type& GetRegistry()
registry_type& GetRegistry()
{
static registry_type theRegistry;
return theRegistry;
}

Standard_Mutex& GetRegistrationMutex()
{
static Standard_Mutex theMutex;
return theMutex;
}

// To initialize theRegistry map as soon as possible to be destroyed the latest
Handle(Standard_Type) theType = STANDARD_TYPE(Standard_Transient);
}

Standard_Type* Standard_Type::Register (const std::type_info& theInfo, const char* theName,
Standard_Size theSize, const Handle(Standard_Type)& theParent)
Standard_Type* Standard_Type::Register(const std::type_info& theInfo,
const char* theName,
Standard_Size theSize,
const Handle(Standard_Type)& theParent)
{
// Access to registry is protected by mutex; it should not happen often because
// instances are cached by Standard_Type::Instance() (one per binary module)
static Standard_Mutex theMutex;
Standard_Mutex::Sentry aSentry (theMutex);

// return existing descriptor if already in the registry
registry_type& aRegistry = GetRegistry();
Standard_Type* aType = 0;
auto anIter = aRegistry.find(theInfo);
Standard_Type* aType = 0;

Standard_Mutex::Sentry aSentry(GetRegistrationMutex());
auto anIter = aRegistry.find(theInfo);
if (anIter != aRegistry.end())
{
return anIter->second;
}

// else create a new descriptor
aType = new Standard_Type (theInfo, theName, theSize, theParent);
aType = new Standard_Type(theInfo, theName, theSize, theParent);

// then add it to registry and return (the reference to the handle stored in the registry)
aRegistry.emplace(theInfo, aType);
return aType;
}

Standard_Type::~Standard_Type ()
Standard_Type::~Standard_Type()
{
// remove descriptor from the registry
registry_type& aRegistry = GetRegistry();
Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry",);
registry_type& aRegistry = GetRegistry();
Standard_Mutex::Sentry aSentry(GetRegistrationMutex());
Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry", );
Comment on lines +121 to +126
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Destructor registry removal syntax error
There is a trailing comma in the Standard_ASSERT call that can cause a syntax error according to static analysis. A minimal fix is to remove that extra comma.

-  Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry", );
+  Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Standard_Type::~Standard_Type()
{
// remove descriptor from the registry
registry_type& aRegistry = GetRegistry();
Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry",);
registry_type& aRegistry = GetRegistry();
Standard_Mutex::Sentry aSentry(GetRegistrationMutex());
Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry", );
Standard_Type::~Standard_Type()
{
// remove descriptor from the registry
registry_type& aRegistry = GetRegistry();
Standard_Mutex::Sentry aSentry(GetRegistrationMutex());
Standard_ASSERT(aRegistry.erase(myInfo) > 0, "Standard_Type::~Standard_Type() cannot find itself in registry");
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 122-122: syntax error

(syntaxError)

}
103 changes: 21 additions & 82 deletions src/Standard/Standard_Type.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,13 @@ namespace opencascade
#define DEFINE_STANDARD_RTTI_INLINE(Class,Base) \
public: \
typedef Base base_type; \
static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \
static const Handle(Standard_Type)& get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
static constexpr const char* get_type_name () { return #Class; } \
static const Handle(Standard_Type)& get_type_descriptor () \
{ \
static const Handle(Standard_Type) THE_TYPE_INSTANCE = Standard_Type::Register (typeid(Class), get_type_name(), \
sizeof(Class), Base::get_type_descriptor()); \
return THE_TYPE_INSTANCE; \
} \
virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE { return get_type_descriptor (); }

//! Helper macro to be included in definition of the classes inheriting
Expand All @@ -104,21 +109,20 @@ public: \
#define DEFINE_STANDARD_RTTIEXT(Class,Base) \
public: \
typedef Base base_type; \
static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \
static constexpr const char* get_type_name () { return #Class; } \
Standard_EXPORT static const Handle(Standard_Type)& get_type_descriptor (); \
Standard_EXPORT virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE;

//! Defines implementation of type descriptor and DynamicType() function
#define IMPLEMENT_STANDARD_RTTIEXT(Class,Base) \
const Handle(Standard_Type)& Class::get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
const Handle(Standard_Type)& Class::get_type_descriptor () \
{ \
static const Handle(Standard_Type) THE_TYPE_INSTANCE = Standard_Type::Register (typeid(Class), get_type_name(), \
sizeof(Class), Base::get_type_descriptor()); \
return THE_TYPE_INSTANCE; \
} \
const Handle(Standard_Type)& Class::DynamicType() const { return STANDARD_TYPE(Class); }

// forward declaration of type_instance class
namespace opencascade {
template <typename T>
class type_instance;
}

//! This class provides legacy interface (type descriptor) to run-time type
//! information (RTTI) for OCCT classes inheriting from Standard_Transient.
//!
Expand All @@ -145,7 +149,6 @@ namespace opencascade {
class Standard_Type : public Standard_Transient
{
public:

//! Returns the system type name of the class (typeinfo.name)
Standard_CString SystemName() const { return myInfo.name(); }

Expand Down Expand Up @@ -177,7 +180,7 @@ public:
template <class T>
static const Handle(Standard_Type)& Instance()
{
return opencascade::type_instance<T>::get();
return T::get_type_descriptor();
}

//! Register a type; returns either new or existing descriptor.
Expand All @@ -193,7 +196,7 @@ public:
Standard_Size theSize, const Handle(Standard_Type)& theParent);

//! Destructor removes the type from the registry
Standard_EXPORT ~Standard_Type ();
Standard_EXPORT ~Standard_Type();

// Define own RTTI
DEFINE_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)
Expand All @@ -205,77 +208,13 @@ private:
Standard_Size theSize, const Handle(Standard_Type)& theParent);

private:
std::type_index myInfo; //!< Object to store system name of the class
Standard_CString myName; //!< Given name of the class
Standard_Size mySize; //!< Size of the class instance, in bytes
Handle(Standard_Type) myParent; //!< Type descriptor of parent class
std::type_index myInfo; //!< Object to store system name of the class
Standard_CString myName; //!< Given name of the class
Standard_Size mySize; //!< Size of the class instance, in bytes
Standard_Size myLevel; //!< Level in the hierarchy
const Handle(Standard_Type)& myParent; //!< Type descriptor of parent class
};

namespace opencascade {

//! Template class providing instantiation of type descriptors as singletons.
//! The descriptors are defined as static variables in function get(), which
//! is essential to ensure that they are initialized in correct sequence.
//!
//! For compilers that do not provide thread-safe initialization of static
//! variables (C++11 feature, N2660), additional global variable is
//! defined for each type to hold its type descriptor. These globals ensure
//! that all types get initialized during the library loading and thus no
//! concurrency occurs when type system is accessed from multiple threads.
template <typename T>
class type_instance
{
static Handle(Standard_Type) myInstance;
public:
static const Handle(Standard_Type)& get ();
};

//! Specialization of type descriptor instance for void; returns null handle
template <>
class type_instance<void>
{
public:
static Handle(Standard_Type) get () { return 0; }
};

// Implementation of static function returning instance of the
// type descriptor
template <typename T>
const Handle(Standard_Type)& type_instance<T>::get ()
{
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
! defined(__clang__) && ! defined(__INTEL_COMPILER))
// ensure that myInstance is instantiated
(void)myInstance;
#endif

// static variable inside function ensures that descriptors
// are initialized in correct sequence
static Handle(Standard_Type) anInstance =
Standard_Type::Register (typeid(T), T::get_type_name(), sizeof(T),
type_instance<typename T::base_type>::get());
return anInstance;
}

// Static class field is defined to ensure initialization of all type
// descriptors at load time of the library on compilers not supporting N2660:
// - VC++ below 14 (VS 2015)
// - GCC below 4.3
// Intel compiler reports itself as GCC on Linux and VC++ on Windows,
// and is claimed to support N2660 on Linux and on Windows "in VS2015 mode".
// CLang should support N2660 since version 2.9, but it is not clear how to
// check its version reliably (on Linux it says it is GCC 4.2).
#if (defined(_MSC_VER) && _MSC_VER < 1900) || \
(defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
! defined(__clang__) && ! defined(__INTEL_COMPILER))

template <typename T>
Handle(Standard_Type) type_instance<T>::myInstance (get());

#endif
}

//! Operator printing type descriptor to stream
inline Standard_OStream& operator << (Standard_OStream& theStream, const Handle(Standard_Type)& theType)
{
Expand Down
2 changes: 1 addition & 1 deletion src/StepVisual/StepVisual_CoordinatesList.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#include <StepVisual_CoordinatesList.hxx>
#include <StepVisual_TessellatedItem.hxx>
IMPLEMENT_STANDARD_RTTIEXT(StepVisual_CoordinatesList,StepGeom_TessellatedItem)
IMPLEMENT_STANDARD_RTTIEXT(StepVisual_CoordinatesList, StepVisual_TessellatedItem)

StepVisual_CoordinatesList::StepVisual_CoordinatesList () {}

Expand Down
2 changes: 1 addition & 1 deletion src/StepVisual/StepVisual_TessellatedGeometricSet.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include <StepVisual_TessellatedGeometricSet.hxx>


IMPLEMENT_STANDARD_RTTIEXT(StepVisual_TessellatedGeometricSet,StepGeom_TessellatedItem)
IMPLEMENT_STANDARD_RTTIEXT(StepVisual_TessellatedGeometricSet,StepVisual_TessellatedItem)


StepVisual_TessellatedGeometricSet::StepVisual_TessellatedGeometricSet () {}
Expand Down
2 changes: 1 addition & 1 deletion src/XCAFDoc/XCAFDoc_NotesTool.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace {

}

IMPLEMENT_DERIVED_ATTRIBUTE(XCAFDoc_NotesTool, XCAFDoc_NoteComment)
IMPLEMENT_DERIVED_ATTRIBUTE(XCAFDoc_NotesTool, TDataStd_GenericEmpty)

enum NotesTool_RootLabels
{
Expand Down
Loading