File indexing completed on 2024-04-28 07:39:47

0001 /*
0002     SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /** \file object.h
0008  *  \brief Object, MetaObject and MetaProperty classes
0009  */
0010 
0011 #ifndef STEPCORE_OBJECT_H
0012 #define STEPCORE_OBJECT_H
0013 
0014 #include <QBitArray>
0015 #include <QString>
0016 #include <QVariant>
0017 
0018 #include <Eigen/Core> // for EIGEN_MAKE_ALIGNED_OPERATOR_NEW
0019 
0020 #include "util.h"
0021 
0022 namespace StepCore {
0023 
0024 class MetaObject;
0025 class MetaProperty;
0026 
0027 #define STEPCORE_OBJECT_NA(_className) \
0028     private: \
0029         typedef _className _thisType; \
0030         static const StepCore::MetaObject   _metaObject; \
0031         static const StepCore::MetaObject*  _superClasses[]; \
0032         static const StepCore::MetaProperty _classProperties[]; \
0033     public: \
0034         static  const StepCore::MetaObject* staticMetaObject() { return &_metaObject; } \
0035         virtual const StepCore::MetaObject* metaObject() const { return &_metaObject; } \
0036     private:
0037 
0038 #define STEPCORE_OBJECT(_className) \
0039     public: \
0040         EIGEN_MAKE_ALIGNED_OPERATOR_NEW \
0041     STEPCORE_OBJECT_NA(_className)
0042 
0043 /** \ingroup reflections
0044  *  \brief Root of the StepCore classes hierarchy
0045  */
0046 class Object
0047 {
0048     STEPCORE_OBJECT(Object)
0049 
0050 public:
0051     explicit Object(const QString& name = QString()): _name(name) {}
0052     virtual ~Object() {}
0053 
0054     /** Returns name of the object */
0055     const QString& name() const { return _name; }
0056     /** Set name of the object */
0057     void setName(const QString& name) { _name = name; }
0058 
0059 protected:
0060     QString _name;
0061 };
0062 
0063 /** \ingroup reflections
0064  *  \brief Meta-information about property
0065  */
0066 class MetaProperty
0067 {
0068 public:
0069     enum {
0070         READABLE = 1, ///< Property is readable
0071         WRITABLE = 2, ///< Property is writable
0072         STORED = 4,   ///< Property should be stored in file
0073         DYNAMIC = 32, ///< Variable changes during simulation or changes of other properties
0074         SIDEEFFECTS = 64 ///< Changing this property has side-effects
0075                          ///  (changes in other dynamic or non-dynamic properties)
0076                          ///  @note Do not set this together with STORED
0077     };
0078 
0079 public:
0080     MetaProperty():
0081         _name(QLatin1String("")), _units(QString()), _description(QLatin1String("")),
0082         _flags(0), _userTypeId(0), _readVariant(nullptr), _writeVariant(nullptr),
0083         _readString(nullptr), _writeString(nullptr), _initialized(false) {}
0084 
0085     /*MetaProperty(const MetaProperty& p):
0086         _name(p._name), _units(p._units), _flags(p.flags), _userTypeId(p._userTypeId),
0087         _readVariant(p._readVariant), _writeVariant(p._writeVariant),
0088         _readString(p._readString), _writeString(p._writeString) {}*/
0089         
0090     MetaProperty(const QString& name, const QString& units,
0091                  const QString& description, int flags, int userType,
0092                  QVariant (*const readVariant)(const Object*),
0093                  bool (*const writeVariant)(Object* obj, const QVariant& v),
0094                  QString (*const readString)(const Object* obj),
0095                  bool (*const writeString)(Object* obj, const QString& v))
0096         : _name(name), _units(units), _description(description),
0097           _flags(flags), _userTypeId(userType),
0098           _readVariant(readVariant), _writeVariant(writeVariant),
0099           _readString(readString), _writeString(writeString), _initialized(false) {}
0100 
0101     /** Returns property name */
0102     const QString& name() const { return _name; }
0103     /** Returns property units (if appropriate) */
0104     const QString& units() const { return _units; }
0105     /** Returns property description */
0106     const QString& description() const { return _description; }
0107     /** Returns property flags */
0108     int flags() const { return _flags; }
0109 
0110     /** Returns translated property name */
0111     const QString& nameTr() const { tryInit(); return _nameTr; }
0112     /** Returns translated property units (if appropriate) */
0113     const QString& unitsTr() const { tryInit(); return _unitsTr; }
0114     /** Returns translated property description */
0115     const QString& descriptionTr() const { tryInit(); return _descriptionTr; }
0116 
0117     /** Returns property userType (see QMetaProperty) */
0118     int userTypeId() const { return _userTypeId; }
0119     /** Read property as QVariant */
0120     QVariant readVariant(const Object* obj) const { return _readVariant(obj); }
0121     /** Write property as QVariant. \return true on success */
0122     bool writeVariant(Object* obj, const QVariant& v) const { return _writeVariant(obj, v); }
0123 
0124     /** Read property as string */
0125     QString readString(const Object* obj) const { return _readString(obj); }
0126     /** Write property as string. \return true on success */
0127     bool writeString(Object* obj, const QString& s) const { return _writeString(obj, s); }
0128 
0129     /** Returns true if this property is readable */
0130     bool isReadable() const { return _flags & READABLE; }
0131     /** Returns true if this property is writable */
0132     bool isWritable() const { return _flags & WRITABLE; }
0133     /** Returns true if this property should be stored */
0134     bool isStored() const { return _flags & STORED; }
0135     /** Returns true if this property is dynamic (changes during simulation) */
0136     bool isDynamic() const { return _flags & DYNAMIC; }
0137     /** Returns true if this property has side-effects
0138      *  (changes in other dynamic or non-dynamic properties) */
0139     bool hasSideEffects() const { return _flags & SIDEEFFECTS; }
0140 
0141 public:
0142     const QString _name;
0143     const QString _units;
0144     const QString _description;
0145     const int _flags;
0146     const int _userTypeId;
0147     QVariant (*const _readVariant)(const Object* obj);
0148     bool (*const _writeVariant)(Object* obj, const QVariant& v);
0149     QString (*const _readString)(const Object* obj);
0150     bool (*const _writeString)(Object* obj, const QString& v);
0151 
0152     mutable bool _initialized;
0153     mutable QString _nameTr;
0154     mutable QString _unitsTr;
0155     mutable QString _descriptionTr;
0156 
0157 public:
0158     void init() const;
0159     void tryInit() const { if(!_initialized) init(); }
0160 };
0161 
0162 /** \ingroup reflections
0163  *  \brief Meta-information about class
0164  */
0165 class MetaObject
0166 {
0167 public:
0168     enum {
0169         ABSTRACT = 1 ///< Class is abstract
0170     };
0171 
0172 public:
0173     /** Returns class name */
0174     const QString& className() const { return _className; }
0175     /** Returns class description */
0176     const QString& description() const { return _description; }
0177 
0178     /** Returns translated class name */
0179     const QString& classNameTr() const { tryInit(); return _classNameTr; }
0180     /** Returns translated class description */
0181     const QString& descriptionTr() const { tryInit(); return _descriptionTr; } 
0182 
0183     /** Returns class id */
0184     int classId() const { tryInit(); return _classId; }
0185 
0186     /** Returns true if class is abstract */
0187     bool isAbstract() const { return _flags & ABSTRACT; }
0188     /** Creates new object of this class */
0189     Object* newObject() const { return _newObject(); }
0190     /** Creates a copy of given object */
0191     Object* cloneObject(const Object& obj) const { return _cloneObject(obj); }
0192 
0193     /** Returns number of direct bases */
0194     int superClassCount() const { return _superClassCount; }
0195     /** Returns direct base */
0196     const MetaObject* superClass(int n) const { return _superClasses[n]; }
0197     /** Returns true if this class inherits class described by obj */
0198     bool inherits(const MetaObject* obj) const;
0199     /** Returns true if this class inherits class T */
0200     template<class T> bool inherits() const { return inherits(T::staticMetaObject()); }
0201     /** Returns true if this class inherits class T */
0202     template<class T> bool inherits(T*) const { return inherits(T::staticMetaObject()); }
0203     /** Returns true if this class inherits class named name
0204      *  \note Due to technical reason this is much slower then
0205      *        inherits(const MetaObject*) function */
0206     bool inherits(const char* name) const;
0207 
0208     /** Returns number of non-inherited properties */
0209     int classPropertyCount() const { return _classPropertyCount; }
0210     /** Returns non-inherited property */
0211     const MetaProperty* classProperty(int n) const { return &_classProperties[n]; }
0212 
0213     /** Returns property count */
0214     int propertyCount() const { tryInit(); return _allPropertyCount; }
0215     /** Returns property by index */
0216     const MetaProperty* property(int n) const { tryInit(); return _allProperties[n]; }
0217     /** Returns property by name */
0218     const MetaProperty* property(const QString& name) const;
0219 
0220 public:
0221     void init() const;
0222     void tryInit() const { if(!_initialized) init(); }
0223     void copyProperties(const MetaProperty** dest) const;
0224 
0225     const QString     _className;
0226     const QString     _description;
0227     const int         _flags;
0228     Object* (*const _newObject)();
0229     Object* (*const _cloneObject)(const Object&);
0230 
0231     const MetaObject**  const _superClasses;
0232     const int                 _superClassCount;
0233     const MetaProperty* const _classProperties;
0234     const int                 _classPropertyCount;
0235 
0236     mutable bool                 _initialized;
0237     mutable const MetaProperty** _allProperties;
0238     mutable int                  _allPropertyCount;
0239 
0240     mutable int _classId;
0241     mutable QBitArray _allSuperClassIds;
0242 
0243     mutable QString     _classNameTr;
0244     mutable QString     _descriptionTr;
0245 
0246     static int  s_classIdCount;
0247 };
0248 
0249 /** Casts between pointers to Object */
0250 template<class _Dst, class _Src> // XXX: implement it better
0251 _Dst stepcore_cast(_Src src) {
0252     if(!src || !src->metaObject()->template inherits(_Dst())) return NULL;
0253     return static_cast<_Dst>(src);
0254 }
0255 
0256 /* Helper functions TODO: namespace of class ? */
0257 
0258 template<typename T> inline QString typeToString(const T& v) {
0259     return QVariant::fromValue(v).toString();
0260 }
0261 
0262 template<typename T> inline T stringToType(const QString& s, bool* ok) {
0263     QVariant v(s); *ok = v.convert((QVariant::Type) qMetaTypeId<T>());
0264     return v.value<T>();
0265 }
0266 
0267 template<typename T> inline QVariant typeToVariant(const T& v) {
0268     return QVariant::fromValue(v);
0269 }
0270 
0271 template<typename T> inline T variantToType(const QVariant& v, bool* ok) {
0272     if(v.userType() == qMetaTypeId<T>()) { *ok = true; return v.value<T>(); }
0273     QVariant vc(v); *ok = vc.convert((QVariant::Type)qMetaTypeId<T>());
0274     return vc.value<T>();
0275 }
0276 
0277 template<class C, typename T>
0278 struct MetaPropertyHelper {
0279 
0280     /* read */
0281     template<T (C::*_read)() const> static QVariant read(const Object* obj) {
0282         return typeToVariant<T>((dynamic_cast<const C*>(obj)->*_read)());
0283     }
0284     template<const T& (C::*_read)() const> static QVariant read(const Object* obj) {
0285         return typeToVariant<T>((dynamic_cast<const C*>(obj)->*_read)());
0286     }
0287 
0288     /* write */
0289     template<void (C::*_write)(T)> static bool write(Object* obj, const QVariant& v) {
0290         bool ok; T tv = variantToType<T>(v, &ok); if(!ok) return false;
0291         (dynamic_cast<C*>(obj)->*_write)(tv); return true;
0292     }
0293     template<void (C::*_write)(const T&)> static bool write(Object* obj, const QVariant& v) {
0294         bool ok; T tv = variantToType<T>(v, &ok); if(!ok) return false;
0295         (dynamic_cast<C*>(obj)->*_write)(tv); return true;
0296     }
0297     template<bool (C::*_write)(T)> static bool write(Object* obj, const QVariant& v) {
0298         bool ok; T tv = variantToType<T>(v, &ok); if(!ok) return false;
0299         return (dynamic_cast<C*>(obj)->*_write)(tv);
0300     }
0301     template<bool (C::*_write)(const T&)> static bool write(Object* obj, const QVariant& v) {
0302         bool ok; T tv = variantToType<T>(v, &ok); if(!ok) return false;
0303         return (dynamic_cast<C*>(obj)->*_write)(tv);
0304     }
0305 
0306     /* readString */
0307     template<T (C::*_read)() const> static QString readString(const Object* obj) {
0308         return typeToString<T>((dynamic_cast<const C*>(obj)->*_read)());
0309     }
0310     template<const T& (C::*_read)() const> static QString readString(const Object* obj) {
0311         return typeToString<T>((dynamic_cast<const C*>(obj)->*_read)());
0312     }
0313 
0314     /* writeString */
0315     template<void (C::*_write)(T)> static bool writeString(Object* obj, const QString& s) {
0316         bool ok; T tv = stringToType<T>(s, &ok); if(!ok) return false;
0317         (dynamic_cast<C*>(obj)->*_write)(tv); return true;
0318     }
0319     template<void (C::*_write)(const T&)> static bool writeString(Object* obj, const QString& s) {
0320         bool ok; T tv = stringToType<T>(s, &ok); if(!ok) return false;
0321         (dynamic_cast<C*>(obj)->*_write)(tv); return true;
0322     }
0323     template<bool (C::*_write)(T)> static bool writeString(Object* obj, const QString& s) {
0324         bool ok; T tv = stringToType<T>(s, &ok); if(!ok) return false;
0325         return (dynamic_cast<C*>(obj)->*_write)(tv);
0326     }
0327     template<bool (C::*_write)(const T&)> static bool writeString(Object* obj, const QString& s) {
0328         bool ok; T tv = stringToType<T>(s, &ok); if(!ok) return false;
0329         return (dynamic_cast<C*>(obj)->*_write)(tv);
0330     }
0331 
0332     static QVariant readNull(const Object* obj) { Q_UNUSED(obj) return QVariant(); }
0333     static QString readStringNull(const Object* obj) { Q_UNUSED(obj) return QString(); }
0334     static bool writeNull(Object* obj, const QVariant& v) { Q_UNUSED(obj) Q_UNUSED(v) return false; }
0335     static bool writeStringNull(Object* obj, const QString& s) { Q_UNUSED(obj) Q_UNUSED(s) return false; }
0336 };
0337 
0338 template<typename Class, int N>
0339 struct MetaObjectHelper {
0340     static Object* newObjectHelper() { return new Class(); }
0341     static Object* cloneObjectHelper(const Object& obj) {
0342         return new Class(static_cast<const Class&>(obj));
0343     }
0344 };
0345 
0346 template<class Class>
0347 struct MetaObjectHelper<Class, MetaObject::ABSTRACT> {
0348     static Object* newObjectHelper() { return nullptr; }
0349     static Object* cloneObjectHelper(const Object& obj) { Q_UNUSED(obj) return nullptr; }
0350 };
0351 
0352 #define STEPCORE_FROM_UTF8(str) QString::fromUtf8(str)
0353 
0354 #define STEPCORE_UNITS_NULL QString()
0355 #define STEPCORE_UNITS_1 QString("")
0356 
0357 #define _STEPCORE_PROPERTY_NULL StepCore::MetaProperty()
0358 
0359 #define STEPCORE_META_OBJECT(_className, _classNameNoop, _description, _flags, __superClasses, __properties) \
0360     const StepCore::MetaProperty _className::_classProperties[] = { _STEPCORE_PROPERTY_NULL, __properties }; \
0361     const StepCore::MetaObject*  _className::_superClasses[] = { nullptr, __superClasses }; \
0362     const StepCore::MetaObject   _className::_metaObject = { \
0363         QString(STEPCORE_STRINGIFY(_className)), QString(_description), _flags, \
0364         StepCore::MetaObjectHelper<_className, _flags & StepCore::MetaObject::ABSTRACT>::newObjectHelper, \
0365         StepCore::MetaObjectHelper<_className, _flags & StepCore::MetaObject::ABSTRACT>::cloneObjectHelper, \
0366         _superClasses+1, sizeof(_superClasses)/sizeof(*_superClasses)-1, \
0367         _classProperties+1, sizeof(_classProperties)/sizeof(*_classProperties)-1, false, nullptr, 0, 0, QBitArray(), "", "" };
0368     
0369 #define STEPCORE_SUPER_CLASS(_className) _className::staticMetaObject(),
0370 
0371 #define STEPCORE_PROPERTY_RF(_type, _name, _nameNoop, _units, _description, _flags, _read) \
0372     StepCore::MetaProperty( STEPCORE_STRINGIFY(_name), _units, _description, \
0373       StepCore::MetaProperty::READABLE | _flags, qMetaTypeId<_type>(), \
0374       StepCore::MetaPropertyHelper<_thisType, _type>::read<&_thisType::_read>, \
0375       StepCore::MetaPropertyHelper<_thisType, _type>::writeNull, \
0376       StepCore::MetaPropertyHelper<_thisType, _type>::readString<&_thisType::_read>, \
0377       StepCore::MetaPropertyHelper<_thisType, _type>::writeStringNull ),
0378 
0379 #define STEPCORE_PROPERTY_RWF(_type, _name, _nameNoop, _units, _description, _flags, _read, _write) \
0380     StepCore::MetaProperty( STEPCORE_STRINGIFY(_name), _units, _description, \
0381       StepCore::MetaProperty::READABLE | StepCore::MetaProperty::WRITABLE | _flags, \
0382       qMetaTypeId<_type>(), \
0383       StepCore::MetaPropertyHelper<_thisType, _type>::read<&_thisType::_read>, \
0384       StepCore::MetaPropertyHelper<_thisType, _type>::write<&_thisType::_write>, \
0385       StepCore::MetaPropertyHelper<_thisType, _type>::readString<&_thisType::_read>, \
0386       StepCore::MetaPropertyHelper<_thisType, _type>::writeString<&_thisType::_write> ),
0387 
0388 #define STEPCORE_PROPERTY_R(_type, _name, _nameNoop, _units, _description, _read) \
0389     STEPCORE_PROPERTY_RF(_type, _name, _nameNoop, _units, _description, 0, _read)
0390 
0391 #define STEPCORE_PROPERTY_RW(_type, _name, _nameNoop, _units, _description, _read, _write) \
0392     STEPCORE_PROPERTY_RWF(_type, _name, _nameNoop, _units, _description, \
0393         StepCore::MetaProperty::STORED, _read, _write)
0394 
0395 #define STEPCORE_PROPERTY_R_D(_type, _name, _nameNoop, _units, _description, _read) \
0396     STEPCORE_PROPERTY_RF(_type, _name, _nameNoop, _units, _description, StepCore::MetaProperty::DYNAMIC, _read)
0397 
0398 #define STEPCORE_PROPERTY_RW_D(_type, _name, _nameNoop, _units, _description, _read, _write) \
0399     STEPCORE_PROPERTY_RWF(_type, _name, _nameNoop, _units, _description, \
0400         StepCore::MetaProperty::STORED | StepCore::MetaProperty::DYNAMIC, _read, _write)
0401 
0402 } // namespace StepCore
0403 
0404 #endif
0405