//-< CLASS.H >-------------------------------------------------------*--------* // GOODS Version 1.0 (c) 1997 GARRET * ? * // (Generic Object Oriented Database System) * /\| * // * / \ * // Created: 7-Jan-97 K.A. Knizhnik * / [] \ * // Last update: 31-May-97 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Runtime type information: class and fileds descriptors //-------------------------------------------------------------------*--------* #ifndef __CLASS_H__ #define __CLASS_H__ #include "wstring.h" #include "goodsdlx.h" BEGIN_GOODS_NAMESPACE class object_reference; class metaobject; class raw_binary_t { public: char const* get_data() const { return data; } size_t get_size() const { return size; } operator char*() { return data; } char& operator [](int i) { assert((unsigned)i < size); return data[i]; } raw_binary_t() { data = NULL; size = 0; } raw_binary_t(char* ptr, size_t len) { if (len > 0) { data = new char[len]; memcpy(data, ptr, len); size = len; } else { data = NULL; size = 0; } } raw_binary_t& operator = (raw_binary_t const& src) { if ((size = src.size) > 0) { data = new char[size]; memcpy(data, src.data, size); } else { data = NULL; } } ~raw_binary_t() { delete[] data; } private: friend class field_descriptor; char* data; size_t size; }; class GOODS_DLL_EXPORT field_descriptor : public l2elem { friend class class_descriptor; protected: field_descriptor* components; // components of field const char* name; // name of field struct field_characteristics { field_type type; // type of field (defined in protocol.h) int size; // size of field int n_items; // length of array int offs; // offset to field }; field_characteristics loc; // characteristics of local object field // in volatile memory field_characteristics dbs; // characteristics of object files // in database int n_refs; // number of references in field // (this field is used only for database objects) // // Unpack field from database format to internal representation // static void unpack(field_descriptor* field, obj_storage* storage, char* dst, char* &src_refs, char* &src_bins); // // Pack field to database format from internal representation // (this method also builds persistent closure of all referenced objects) // static void pack(field_descriptor* field, char* &dst_refs, char* &dst_bins, char* src, hnd_t parent_hnd, field_descriptor* varying, int varying_length); // // Calculated packed size of string components // static size_t calculate_strings_size(field_descriptor* field, char* src_obj, size_t size); // // Destroy references from varying part of object. 'src' pointes // to the second element of varying part and 'len' specify // number of element in varying part minus one // void destroy_references(char* src, int len); virtual ~field_descriptor(); public: inline friend field_descriptor& describe_field(int1) { return *(field_descriptor*)fld_signed_integer; } inline friend field_descriptor& describe_field(int2) { return *(field_descriptor*)fld_signed_integer; } inline friend field_descriptor& describe_field(int4) { return *(field_descriptor*)fld_signed_integer; } inline friend field_descriptor& describe_field(int8) { return *(field_descriptor*)fld_signed_integer; } inline friend field_descriptor& describe_field(nat1) { return *(field_descriptor*)fld_unsigned_integer; } inline friend field_descriptor& describe_field(nat2) { return *(field_descriptor*)fld_unsigned_integer; } inline friend field_descriptor& describe_field(nat4) { return *(field_descriptor*)fld_unsigned_integer; } inline friend field_descriptor& describe_field(nat8) { return *(field_descriptor*)fld_unsigned_integer; } inline friend field_descriptor& describe_field(double) { return *(field_descriptor*)fld_real; } inline friend field_descriptor& describe_field(object_reference const&) { return *(field_descriptor*)fld_reference; } inline friend field_descriptor& describe_field(wstring_t const&) { return *(field_descriptor*)fld_string; } inline friend field_descriptor& describe_field(raw_binary_t const&) { return *(field_descriptor*)fld_raw_binary; } field_descriptor& operator,(field_descriptor& next_field) { next_field.link_after(prev); return *this; } // // Construct field descriptor using parameters of field obtained by // one of the macros below // field_descriptor(const char* name, int size, int n_items, int offset, field_descriptor* componentns); // // Construct field descriptor for performing mapping between fields // when class format is changed // field_descriptor(field_descriptor const* new_field, dbs_field_descriptor const* old_field); }; #define NO_FIELDS (*(field_descriptor*)0) #define FIELD(x) \ (*NEW field_descriptor(#x, sizeof(x), 1, (char*)&(x) - (char*)this, \ &GOODS_NAMESPACE::describe_field(x))) #define ARRAY(x) \ (*NEW field_descriptor(#x, sizeof(*x), itemsof(x), (char*)(x) - (char*)this, \ &GOODS_NAMESPACE::describe_field(*x))) #define MATRIX(x) \ (*NEW field_descriptor(#x, sizeof(*x), itemsof(x), (char*)(x) - (char*)this, \ NEW field_descriptor("", sizeof(**x), itemsof(*x), 0, \ &GOODS_NAMESPACE::describe_field(**x)))) #define VARYING(x) \ (assert(sizeof(x) == sizeof(*x)), \ *NEW field_descriptor(#x, sizeof(*x), 0, (char*)(x) - (char*)this, \ &GOODS_NAMESPACE::describe_field(*x))) // // Application class descriptor. It contains information about // name, type, size and offset of all class fields in memory and // in database. This class also contains reference to database class // descriptor. To perform convertion of instances of modified classes special // class descriptor is created which is used only for loading object. // #define DESCRIPTOR_HASH_TABLE_SIZE 1041 class GOODS_DLL_EXPORT class_descriptor { friend class object_handle; friend class object; friend class obj_storage; public: const char* const name; const ctid_t ctid; class_descriptor* const base_class; typedef object* (*constructor_t)(hnd_t hnd, class_descriptor& cls, size_t varying_size); const constructor_t constructor; metaobject* mop; // metaobject be default for this class object instances class_descriptor* derived_classes;// list of derived classes for thus class class_descriptor* next_derived; // next derived class for base class void* class_data; // can be used to refer class specific data enum class_attributes { cls_no_attr = 0, cls_aligned = 1 // instance should be aligned to nearest power of 2 }; int class_attr; // mask of class attributes static class_descriptor* find(const char* name); boolean is_superclass_for(hnd_t hnd) const; // // Class object is no more used by storage // void dealloc() { if (new_cpid != 0) { // class was created only for conversion of loaded objects delete this; } } inline size_t unpacked_size(size_t packed_size) const { return packed_varying_size ? fixed_size + (packed_size-packed_fixed_size) / packed_varying_size * varying_size : fixed_size; } inline size_t packed_size(char* obj, size_t unpacked_size) const { return packed_fixed_size + (has_strings ? calculate_strings_size(obj) : 0) + (varying_size ? (unpacked_size-fixed_size) / varying_size * packed_varying_size : 0); } // // Constructor is usually called by REGISTER or REGISTER_EX macro // class_descriptor(const char* name, // class name size_t size, // size of fized part of class instance metaobject* mop, // metaobject constructor_t cons, // constructor of class instance class_descriptor* base, // base class int class_attr = cls_no_attr); virtual ~class_descriptor(); protected: size_t packed_fixed_size; size_t packed_varying_size; size_t n_fixed_references; size_t n_varying_references; size_t fixed_size; size_t varying_size; boolean has_strings; object* obj; // // This fields are used only in convertion class descriptor // cpid_t const new_cpid; class_descriptor* const new_class; // class descriptor assigned to // created object dbs_class_descriptor* dbs_desc; static ctid_t last_ctid; static class_descriptor* hash_table[DESCRIPTOR_HASH_TABLE_SIZE]; class_descriptor* next; // collision chain field_descriptor* fields; // list of all fields in class field_descriptor* varying; // pointer to varying field (if any) static unsigned hash_function(const char* name); boolean initialized() { return dbs_desc != NULL; } // // Calculate class and it's components attributes: // packed size, offset, number of references. Returns number of fields. // int calculate_attributes(field_descriptor* field, size_t& size, size_t& n_refs, size_t& names_size); // // Build database class descriptor for this class // static int build_dbs_class_descriptor(dbs_class_descriptor* dbs_desc, int field_no, field_descriptor* field, size_t& name_offs); // // Calculate total packed size of all strings in the object // size_t calculate_strings_size(char* obj) const; // // Convert object from database format to internal format // void unpack(dbs_object_header* obj, hnd_t hnd); // // Convert object from internal format to database representation // void pack(dbs_object_header* obj, hnd_t hnd); // // Include into chain of modified objects all transient // objects referenced by object with 'hnd' indentifier // void make_persistent_closure(hnd_t hnd); // // Destroy object references in varying part of object // void destroy_varying_part_references(object* obj) const; // // Create fields tree for mapping fields of old version of the class // to new version of the class // field_descriptor* create_field_mapping(dbs_class_descriptor* old_desc, field_descriptor* new_field, int old_field_no, int n_dbs_fileds, size_t& ref_offs, size_t& bin_offs); // // Create class descriptor for modified class (in comparence // with database class 'old_desc' with the same name). This class is used // only for loading object from database, then object 'cpid' // will be changed to 'new_cpid' and object will be contolled // by 'new_desc' descriptor of new version of class. // class_descriptor(cpid_t new_cpid, class_descriptor* new_desc, dbs_class_descriptor* old_desc); // // Collect information about class components. This method is // really part of contructor and is separated only to avoid // problem with order of invokation of constructors of static objects. // void build_components_info(); }; #if GOODS_RUNTIME_TYPE_CHECKING #if defined(__GNUC__) && __GNUC_MINOR__ <= 95 #define METACLASS_DECLARATIONS(CLASS, BASE_CLASS) \ static class_descriptor self_class; \ static object* constructor(hnd_t hnd, class_descriptor& desc, \ size_t varying_size); \ CLASS(hnd_t hnd, class_descriptor& desc, size_t varying_size) \ : BASE_CLASS(hnd, desc, varying_size) {} \ virtual field_descriptor& describe_components() #else #define METACLASS_DECLARATIONS(CLASS, BASE_CLASS) \ static class_descriptor self_class; \ friend class_descriptor& classof(CLASS const*); \ static object* constructor(hnd_t hnd, class_descriptor& desc, \ size_t varying_size); \ CLASS(hnd_t hnd, class_descriptor& desc, size_t varying_size) \ : BASE_CLASS(hnd, desc, varying_size) {} \ virtual field_descriptor& describe_components() #endif #if defined(__BORLANDC__) #define REGISTER_TEMPLATE(CLASS, BASE, MOP) \ BEGIN_GOODS_NAMESPACE \ class_descriptor& classof(CLASS const*) \ { return CLASS::self_class; } \ END_GOODS_NAMESPACE \ template<> \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ template<> \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class) #else #define REGISTER_TEMPLATE(cls, bas, mop) REGISTER(cls, bas, mop) #endif #define REGISTER(CLASS, BASE, MOP) \ BEGIN_GOODS_NAMESPACE \ class_descriptor& classof(CLASS const*) \ { return CLASS::self_class; } \ END_GOODS_NAMESPACE \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class) #define REGISTER_EX(CLASS, BASE, MOP, ATTR) \ class_descriptor& classof(CLASS const*) \ { return CLASS::self_class; } \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class, \ ATTR) #else #define METACLASS_DECLARATIONS(CLASS, BASE_CLASS) \ static class_descriptor self_class; \ static object* constructor(hnd_t hnd, class_descriptor& desc, \ size_t varying_size); \ CLASS(hnd_t hnd, class_descriptor& desc, size_t varying_size) \ : BASE_CLASS(hnd, desc, varying_size) {} \ virtual field_descriptor& describe_components() #if defined(__BORLANDC__) #define REGISTER_TEMPLATE(CLASS, BASE, MOP) \ template<> \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ template<> \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class) #else #define REGISTER_TEMPLATE(cls, bas, mop) REGISTER(cls, bas, mop) #endif #define REGISTER(CLASS, BASE, MOP) \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class) #define REGISTER_EX(CLASS, BASE, MOP, ATTR) \ object* CLASS::constructor(hnd_t hnd, \ class_descriptor& desc, size_t var_len) \ { return new (desc, var_len) CLASS(hnd, desc, var_len); } \ class_descriptor CLASS::self_class(#CLASS, \ sizeof(CLASS), \ &MOP, \ CLASS::constructor, \ &BASE::self_class, \ ATTR) #endif END_GOODS_NAMESPACE #endif