//////////////////////////////////////////////////////////////////////////////// /** \file \brief \ru Сериализация:. Утилиты чтения и записи потоковых классов. \en Serialization: utilities for reading and writing of stream classes. \~ */ //////////////////////////////////////////////////////////////////////////////// #ifndef __IO_TAPE_H #define __IO_TAPE_H /// \ru Для контроля чтения/записи char* и TCHAR* только через ReadTCHAR/WriteTCHAR() скомпилировать с данным дефайном и увидим все места, где незаконно пишутся/читаются данные через operator << и >>. /// \en Compile with the given preprocessor define for control of reading/writing char* and TCHAR* only via ReadTCHAR/WriteTCHAR(), not via illegally operator << and >>. //#define DISABLE_RWTCHAR #include #include #include #include #include #include #include #include #include #include //---------------------------------------------------------------------------------------- /** \brief \ru Массив для регистрации объектов при чтении/записи. \en Array for object registration while reading/writing. \~ \details \ru Массив для регистрации объектов при чтении/записи. \n \en Array for object registration while reading/writing. \n \~ \ingroup Base_Tools_IO */ //--- class MATH_CLASS TapeRegistrator { public: typedef std::map TapeIndexMap; typedef std::map IndexTapeMap; protected: TapeIndexMap tapeIndexPairs; /// \ru Ассоциативный массив связок [указатель на объект]-[номер в массиве]. \en Map of [object]-[index] pairs. size_t maxCount; /// \ru Максимальное количество зарегистрированных объектов. \en Maximal number of registered objects. IndexTapeMap indexesAndObjs; /// \ru Ассоциативный массив связок [номер в массиве]-[указатель на объект]. \en Map of [index]-[object] pairs. public: /// \ru Конструктор. \en Constructor. TapeRegistrator(); /// \ru Деструктор. \en Destructor. virtual ~TapeRegistrator(); /// \ru Получить количество зарегистрированных объектов. \en Get a number of registered objects. size_t Count() const; /// \ru Зарезервировать место под данное количество элементов. \en Reserve space for a given number of elements. bool Reserve ( size_t n ); /// \ru Найти объект в массиве. \en Find the object in array. size_t FindIt( const TapeBase * e ) const; /// \ru Существует ли объект в массиве. \en Whether the object is in the array. bool IsExist( const TapeBase * e ) const; /// \ru Узнать максимально возможное количество регистрируемых объектов. \en Get the maximal possible number of registered objects. size_t GetMaxCount() const; /// \ru Выдать из массива зарегистрированных объектов указатель по заданному индексу. \en Get the pointer from the registered object array by the given index. TapeBase * operator[]( size_t ind ) const ; ///< \ru Вставить элемент с определенным индексом. \en Insert an element with defined index. void AddAt( const TapeBase * e, size_t ind ); /// \ru Добавить объект в массив. \en Add the object to the array. size_t Add( const TapeBase * e ); /// \ru Выдать указатель на зарегистрированный объект по заданной позиции в кластере. \en Get the pointer of the registered object by the position in the cluster. virtual TapeBase * Get( const ClusterReference & ) const { return nullptr; } // unsupported /// \ru Выдать позицию в кластере по заданному индексу. \en Get position in the cluster by given index. virtual ClusterReference GetClusterRef( size_t ) const { return ClusterReference(); } // unsupported /// \ru Добавить позицию объекта в кластере. \en Add the object position in the cluster. virtual void AddClusterRef( size_t, const ClusterReference & ) {} // unsupported /// \ru Очистить массив зарегистрированных объектов. \en Flush the array of registered objects. virtual void FlushRegistered(); /// \ru Очистить зарегистрированный объект \en Flush the registered object virtual void FlushObj( const TapeBase * ); /// \ru Поменять местами массивы для регистрации void Swap ( TapeRegistrator & swapReg ); protected: /// \ru Очистить зарегистрированный объект \en Flush the registered object void FlushObjInd( size_t ); #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ public: void * operator new ( size_t size ) { return ::Allocate( size, typeid(TapeRegistrator).name() ); } void operator delete ( void * ptr, size_t size ) { ::Free( ptr, size, typeid(TapeRegistrator).name() ); } #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ OBVIOUS_PRIVATE_COPY( TapeRegistrator ) }; //---------------------------------------------------------------------------------------- /** \brief \ru Массив для регистрации объектов с сохранениeм информации о позиции чтения/записи. \en Array for registration of objects with information about reading/writing position. \~ \details \ru Массив для регистрации объектов с сохранениeм информации о позиции чтения/записи. \n \en Array for registration of objects with information about reading/writing position. \n \~ \ingroup Base_Tools_IO */ //--- class MATH_CLASS TapeRegistratorEx : public TapeRegistrator { public: typedef std::map ClusterIndexMap; typedef std::map IndexClusterMap; private: /// \ru Ассоциативный массив [cluster position] -> [object index]. Основное хранилище для значений ClusterReference. /// \en Map: [cluster position] -> [object index]. The primary container for ClusterReference values. ClusterIndexMap refIndex; /// \ru Ассоциативный массив [object index] -> [pointer to cluster position]. Содержит указатели на объекты ClusterReference из массива refIndex. /// \en Map: [object index] -> [pointer to cluster position]. Contains pointers to object ClusterReference from refIndex map. IndexClusterMap objReferences; public: /// \ru Конструктор. \en Constructor. TapeRegistratorEx(); /// \ru Выдать указатель на зарегистрированный объект по заданной позиции в кластере. /// \en Get the pointer of the registered object by the position in the cluster. virtual TapeBase * Get ( const ClusterReference & ref ) const; /// \ru Выдать позицию в кластере по заданному индексу. \en Get position in the cluster by given index. virtual ClusterReference GetClusterRef ( size_t ind ) const; /// \ru Добавить позицию объекта в кластере. \en Add the object position in the cluster. virtual void AddClusterRef( size_t ind, const ClusterReference & ref ); /// \ru Очистить массив зарегистрированных объектов. \en Flush the array of registered objects. virtual void FlushRegistered(); /// \ru Очистить зарегистрированный объект \en Flush the registered object virtual void FlushObj ( const TapeBase * ); OBVIOUS_PRIVATE_COPY( TapeRegistratorEx ) }; //---------------------------------------------------------------------------------------- /** \brief \ru Индикатор прогресса в области видимости для reader. \en Scoped progress indicator for reader. \~ \details \ru Индикатор прогресса в области видимости для чтения модели с помощью reader. Создается дочерний индикатор прогресса для reader. При выходе из области видимости освобождается текущий индикатор прогресса и устанавливается родительский индикатор прогресса. \n \en Scoped progress indicator for reader. A scoped child progress indicator for reader is created. When exiting the scope, the current progress indicator is released and the parent progress indicator is set. \n \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS ScopedReadProgress { SPtr _progress; reader & _reader; public: ScopedReadProgress( reader & in ); ~ScopedReadProgress(); // \ru Доступ к индикатору прогресса. \en Access to progress indicator. ProgressBarWrapper * operator()(); private: ScopedReadProgress(); void operator = ( const ScopedReadProgress & ); }; //---------------------------------------------------------------------------------------- /// \ru Шаблон функции создания нового экземпляра. \en Template of function of a new instance creation. \~ \ingroup Base_Tools_IO //--- typedef TapeBase * ( CALL_DECLARATION * BUILD_FUNC ) ( void ); //---------------------------------------------------------------------------------------- /** \brief \ru Шаблон функции преобразования. \en Template of conversion function. \~ \details \ru Шаблон функции преобразования из указателя на TapeBase к указателю на класс. \n \en Template of function of conversion from a pointer to TapeBase to a pointer to the class. \n \~ \ingroup Base_Tools_IO */ //--- typedef void * ( CALL_DECLARATION * CAST_FUNC ) ( const TapeBase * ); //---------------------------------------------------------------------------------------- /**\ru Шаблон функции чтения экземпляра. \en Template of instance reading function. \~ \ingroup Base_Tools_IO */ //--- typedef void ( CALL_DECLARATION * READ_FUNC ) ( reader & in, void * /*obj*/ ); //---------------------------------------------------------------------------------------- /// \ru Шаблон функции записи экземпляра. \en Template of instance writing function. \~ \ingroup Base_Tools_IO //--- typedef void ( CALL_DECLARATION * WRITE_FUNC ) ( writer & out, void * /*obj*/ ); //---------------------------------------------------------------------------------------- /** \brief \ru Упакованное имя класса. \en Packed class name. \~ \details \ru Упакованное имя одного класса - для набора массива потоковых классов в TapeClass. \n \en Packed name of one class - for array of stream classes in TapeClass. \n \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS ClassDescriptor { protected: uint16 val; ///< \ru Хэш имени класса. \en The class name hash. MbUuid appID_; ///< \ru Дополнительный идентификатор приложения. \en Additional application identifier. private: /// \ru Признак записи appID. \en AppID record flag. static const uint16 rwIdFlag; public: /// \ru Конструктор. \en Constructor. ClassDescriptor(); /// \ru Конструктор по хэшу. \en Constructor by hash. ClassDescriptor( uint16 v ); /// \ru Конструктор по имени. \en Constructor by name. ClassDescriptor( const char * name ); /// \ru Конструктор по хэшу. \en Constructor by hash. ClassDescriptor( uint16 v, const MbUuid & appID ); /// \ru Конструктор по имени. \en Constructor by name. ClassDescriptor( const char * name, const MbUuid & appID ); /// \ru Конструктор по хэшу. \en Constructor by hash. ClassDescriptor( const ClassDescriptor & other ); /// \ru Оператор присваивания. \en An assignment operator. ClassDescriptor & operator = ( const ClassDescriptor & other ); /// \ru Оператор равенства. \en The equality operator. bool operator == ( const ClassDescriptor & other ) const; /// \ru Оператор неравенства. \en The inequality operator. bool operator != ( const ClassDescriptor & other ) const; /// \ru Оператор сравнения. \en Comparison operator. bool operator < ( const ClassDescriptor & other ) const; /// \ru Оператор сравнения. \en Comparison operator. bool operator > ( const ClassDescriptor & other ) const; #ifdef C3D_DEBUG /// \ru Оператор доступа. \en An access operator. operator uint16() const { return val; } #endif /// \ru Оператор записи. \en Write operator. void Write( writer & out ); /// \ru Оператор чтения. \en Read operator. bool Read( reader & in ); }; //---------------------------------------------------------------------------------------- /** \brief \ru "Обертка" для одного потокового класса. \en "Wrapper" for one stream class. \~ \details \ru "Обертка" для одного потокового класса ( не экземпляра! ). Xранит упакованное имя класса и адреса функций, необходимых при чтении/записи. \n \en "Wrapper" for one stream class ( not instance! ). Stores packed class name and addresses of functions necessary while reading/writing. \n \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS TapeClass { protected: ClassDescriptor hashValue; ///< \ru Упакованное имя класса. \en Packed class name. BUILD_FUNC _builder; ///< \ru Функция создания нового экземпляра. \en Functions of a new instance creation. CAST_FUNC _caster; ///< \ru Функция преобразования от TapeBase к указателю на класс. \en Function of conversion from TapeBase to a pointer to a class. READ_FUNC _reader; ///< \ru Функция чтения. \en Read function. WRITE_FUNC _writer; ///< \ru Функция записи. \en Write function. public: /// \ru Конструктор. \en Constructor. /// \ru Конструктор. \en Constructor. TapeClass( const char * name, BUILD_FUNC b, CAST_FUNC c, READ_FUNC r, WRITE_FUNC w ); TapeClass( const char * name, MbUuid appID, BUILD_FUNC b, CAST_FUNC c, READ_FUNC r, WRITE_FUNC w ); /// \ru Деструктор. \en Destructor. virtual ~TapeClass(); /// \ru Получить упакованное имя класса. \en Get the packed class name. ClassDescriptor GetPackedClassName() const; /// \ru Получить упакованное имя класса для записи с учетом версии. \en Get the packed class name for writing subject to the version. virtual ClassDescriptor GetPackedClassNameForWrite( VERSION ) const; friend class TapeManager; friend struct TapeClassContainer; OBVIOUS_PRIVATE_COPY( TapeClass ) }; //---------------------------------------------------------------------------------------- /** \brief \ru Менеджер потоков. \en Stream manager. \~ \details \ru Менеджер потоков чтения и записи. \n \en Reading and writing streams manager. \n \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS TapeManager { private: //static TPointer & StaticTapeManager(); protected : TapeClass * currentClass; ///< \ru Указатель на объект потокового класса. \en A pointer to the object of stream class. protected : /// \ru Конструктор. \en Constructor. TapeManager(); /// \ru Конструктор копирования. \en Copy constructor. TapeManager( const TapeManager & ); public : /// \ru Деструктор. \en Destructor. virtual ~TapeManager() {} public: /// \ru Чтение экземпляра. \en Reading of the instance. bool SpecimenReading ( reader & r, TapeBase & o ) const; /// \ru Запись экземпляра. \en Writing of the instance. bool SpecimenWriting ( writer & w, const TapeBase & o ) const; /// \ru Установить текущим класс по упакованному имени класса. \en Set class as default one by packed class name. bool SetCurrentClassByDescriptor ( const ClassDescriptor & descr ); /// \ru Установить текущим класс по упакованному имени класса. \en Set class as default one by packed class name. bool SetCurrentClassByDescriptor ( const ClassDescriptor & descr, const VersionContainer & ver ); /// \ru Установить текущим класс по имени класса. \en Set class to be current by class name. //bool SetCurrentClassByName ( const char * name ); /// \ru Создать объект потокового класса. \en Create an object of a stream class. TapeBase * BuildObject () const; /// \ru Есть ли функция записи у класса? \en Is there the writing function in the class? bool HasWriter () const; /// \ru Получить упакованное имя класс для записи в версию. \en Get packed class name for writing to the version. ClassDescriptor GetPackedClassNameForWrite ( VERSION version ) const; /// \ru Отпустить менеджер потоков после использования. \en Release the stream manager after using. virtual void FreeTapeManager(); /// \ru Получить ссылку на менеджер потоков. \en Get a reference to the stream manager. static TapeManager & GetTapeManager(); private: TapeManager & operator = ( const TapeManager & ); }; //---------------------------------------------------------------------------------------- /** \brief \ru Массив регистрации потоковых классов. \en Array of stream classes registration. \~ \details \ru Массив регистрации потоковых классов TapeClass. \n \en Array of stream TapeClass classes registration. \n \~ \ingroup Base_Tools_IO */ // --- struct TapeClassContainer { /// \ru Создать массив регистрации потоковых классов. \en Create an array of stream classes registration. static EXPORT_DECLARATION TPointer< SFDPArray > & CALL_DECLARATION StaticTapeClassContainer(); /// \ru Добавить потоковый класс. \en Add a stream class. static bool Add( TapeClass & tapeClass ) { if ( !StaticTapeClassContainer() ) StaticTapeClassContainer() = new SFDPArray( 430, 1, TapeClass_Compare, nullptr ); // \ru не владеет \en doesn't own return StaticTapeClassContainer()->AddExact( tapeClass ); } /// \ru Функция сравнения двух TapeClass для поиска. \en Function of two TapeClass comparison for a search. static int TapeClass_Search( const TapeClass & t1, size_t d ) { return ( ( t1.hashValue == *(ClassDescriptor*)d ) ? 0 : (( t1.hashValue > *(ClassDescriptor*)d ) ? 1 : -1 ) ); } /// \ru Функция сравнения двух TapeClass для сортировки при вставке. \en Function of two TapeClass comparison for sorting while inserting. static int TapeClass_Compare( const TapeClass & t1, const TapeClass & t2 ) { return ( ( t1.hashValue == t2.hashValue ) ? 0 : (( t1.hashValue > t2.hashValue ) ? 1 : -1 ) ); } }; //---------------------------------------------------------------------------------------- /** \brief \ru Поток для чтения и записи. \en Stream for reading and writing. \~ \details \ru Поток для чтения и записи. \n \en Stream for reading and writing. \n \~ \deprecated \ru Класс устарел и будет удален в версии 2023. \en The class is deprecated and will be removed in version 2023. \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS rw : public writer, public reader { public: typedef std::unique_ptr rw_ptr; public: /// \ru Создать читатель/писатель для буфера в памяти. \en Create reader/writer for membuf. static rw_ptr CreateMemWriter( membuf & sb, uint8 om ); /// \ru Конструктор. \en Constructor. rw( iobuf & buf, uint16 om ); virtual ~rw() {} private: /// \ru Конструктор. \en Constructor. rw( iobuf_Seq & sb, bool ownBuf, bool openSys, uint16 om, TapeRegistrator * reg ); OBVIOUS_PRIVATE_COPY( rw ) }; //---------------------------------------------------------------------------------------- /// \ru Функция чтения базового класса. \en Function of reading the base class. \~ \ingroup Base_Tools_IO // --- template inline void ReadBase( reader & in, Base * base ) { Base::Read( in, base ); } //---------------------------------------------------------------------------------------- /// \ru Функция записи базового класса. \en Function of writing the base class. \~ \ingroup Base_Tools_IO // --- template inline void WriteBase( writer & out, const Base * base ) { Base::Write( out, base ); } //---------------------------------------------------------------------------------------- /// \ru Функция чтения виртуального базового класса. \en Function of reading of a virtual base class. \~ \ingroup Base_Tools_IO // --- template void ReadVBase( reader & in, Base * base ) { switch( in.readByte() ) { case tape::otIndexed: break; case tape::otObject : in.registrate( dynamic_cast(base) ); Base::Read( in, base ); break; } } //---------------------------------------------------------------------------------------- /// \ru Функция записи виртуального базового класса. \en Function of writing of a virtual base class. \~ \ingroup Base_Tools_IO // --- template void WriteVBase( writer & out, const Base * base ) { if ( !out.good() ) return; if ( out.exist( dynamic_cast(base) ) ) out.writeByte( tape::otIndexed ); else { out.registrate( dynamic_cast(base) ); out.writeByte( tape::otObject ); Base::Write( out, base ); } } //---------------------------------------------------------------------------------------- // \ru Удаление пробелов и записей перед пробелами. \en Deleting of spaces and records before spaces. \~ // \ingroup Base_Tools_IO // \ru Для совместимости с предыдущими компиляторами по именам возвращаемым typeid(a).name(). // \en For compatibility with the previous compilers by names returned by typeid(a).name(). // \ru Для определения того, что надо делать, скомпилируйте и запустите из консоли код: // \en Compile and run the following code from console to define what is to do: // #include // #include // class CLASS_A { // public: virtual ~CLASS_A() {} // }; // // int main(int argc, char **argv) { // CLASS_A a; // std::cout << typeid(a).name() << '\n'; // return 0; // } // // \ru Выдаваемые значения \en Returned values // MS Visual C++ 6.0 ... 2010: "class CLASS_A" // gcc (Linux): "7CLASS_A" // Embarcadero C++ 7.20 for Win32 "$CLASS_A" // \ru Интересующая нас функция должна выдавать "CLASS_A" \en The desired function must write "CLASS_A" // // \ru Для имени шаблонного класса функция возвращает строку, состоящую из имени класса и имен параметров. // \en For a template class name, the function returns a string consisting of the class name and parameter names. // \ru Например, для имени "class ClassX" функция возвращает "ClassXClassAClassB". // \ru For example, for the name "class ClassX" the function returns "ClassXClassAClassB". // --- MATH_FUNC( const char * ) pureName( const char * name ); //---------------------------------------------------------------------------------------- /// \ru Упаковать строку(имя класса) в uint16. \en Pack the string (class name) into uint16. \~ \ingroup Base_Tools_IO // --- inline uint16 hash( const char * name ) { const uint16 * c = (const uint16 *)name; uint16 h = uint16(strlen(name)); // Mix in the string length. uint16 l = h; uint16 i = uint16(h / sizeof(uint16)); // Could do "<<" here, but less portable. while ( i-- ) h ^= *c++; // XOR in the characters. // If there are any remaining characters, // then XOR in the rest, using a mask: if ( (i = uint16(l % sizeof(uint16))) != 0 ) // SKIP_SA h ^= uint16(*c & 0xff); return h; } //---------------------------------------------------------------------------------------- /** \brief \ru Локальное задание локали. \en Local setting of the locale. \~ \details \ru Поддержка RAII (Resource Acquisition Is Initialization) для задания локали. \n \en Support of RAII (Resource Acquisition Is Initialization) for the setting of the locale. \~ \ingroup Base_Tools_IO */ // --- class MATH_CLASS C3DLocaleSwitcher { static const char * UNSET; std::string _locale; int _category; public: /// \ru Конструктор. При fix == false это просто заглушка. /// \en Constructor. With fix == false, this is just a stub. C3DLocaleSwitcher( const char * loc, bool fix = true, int cat = LC_CTYPE ) : _locale( UNSET ), _category( cat ) { if ( fix ) { _locale = ::setlocale( cat, nullptr ); ::setlocale( cat, loc ); } } /// \ru Деструктор. \en Destructor. ~C3DLocaleSwitcher() { if ( _locale != UNSET ) ::setlocale( _category, _locale.c_str() ); // \ru Вернуть предыдущую локаль. \en Return to the previous locale. } private: C3DLocaleSwitcher(); OBVIOUS_PRIVATE_COPY( C3DLocaleSwitcher ) }; #define FIX_ANSI1251 "ru_RU.CP1251" //---------------------------------------------------------------------------------------- // \ru Чтение CHAR строки из потока. (в кодировке ANSI, с русской локалью) \en Reading of CHAR string from the stream. (in ANSI coding, with Russian locale) // \ru И нулевой указатель и пустая строка возвращаются как нулевой указатель! \en Both null pointer and an empty string are returned as null pointer! // \ru Длина строки не может превышать SYS_MAX_UINT16 - 1 \en The string length cannot exceed SYS_MAX_UINT16 - 1 // \ru Созданную строку кто-то потом должен уничтожить (через delete[]) \en Created string must be deleted by someone then (using delete[]) // --- inline reader & __readChar( reader & ps, char *& s ) { s = nullptr; if ( ps.good() ) { uint16 len = 0; ps.readBytes( &len, sizeof(len) ); // \ru длина строки - uint16 \en string length - uint16 if ( len == 0 || len == SYS_MAX_UINT16 || (len > 0 && ps.eof()) || !ps.good() ) { s = nullptr; } else // good { s = new char[len + 1]; if ( s ) { if ( ps.readBytes(s, len) ) { // \ru прочли сколько нужно - добавить ограничивающий 0 \en have read as much as necessary - the terminating 0 is to be added s[len] = 0; } else { // \ru прочли не все, скорее всего ошибка - очистить строку \en not everything has been read, must be an error - clear the string delete [] s; s = nullptr; } } else ps.setState( io::outOfMemory ); } } return ps; } //---------------------------------------------------------------------------------------- // \ru Чтение WCHAR строки из потока. (в потоке хранится как UTF-16) \en Reading of WCHAR string from the stream. (stored in the stream as UTF-16) // \ru И нулевой указатель и пустая строка возвращаются как нулевой указатель! \en Both null pointer and an empty string are returned as null pointer! // \ru Длина строки не может превышать SYS_MAX_UINT32 - 1 \en The string length cannot exceed SYS_MAX_UINT32 - 1 // \ru Созданную строку кто-то потом должен уничтожить \en Created string should be deleted by someone then // --- inline reader & __readWchar( reader & ps, TCHAR * & s ) { s = nullptr; // \ru на случай, если ничего не прочитаем \en for case if nothing will be read if ( ps.good() ) { uint32 len = 0; if ( ps.readBytes(&len, sizeof(len)) && // \ru длина строки в символах без терминального нуля - uint32 \en the string length in symbols without the termination zero - uint32 len != 0 && len != SYS_MAX_UINT32 && !ps.eof() ) { uint16 * readBuf = new uint16[(size_t)len + 1]; // \ru длина (количество символов) вычитываемой строки с терминальным нулем \en length (number of symbols) of string being read with terminating 0 size_t size = sizeof(uint16) * (size_t)len; // \ru длина (в байтах) вычитываемой строки без терминального нуля \en length (in bytes) of string being read without terminating null if ( ps.readBytes(readBuf, size) ) // \ru прочли сколько нужно - добавить ограничивающий 0 \en have read as much as necessary - the terminating 0 is to be added readBuf[(size_t)len] = 0; else { // \ru прочли не все, скорее всего ошибка - очистить строку \en not everything has been read, must be an error - clear the string delete [] readBuf; readBuf = nullptr; } if ( readBuf ) { // is OK #ifdef _UNICODE // TCHAR == wchar_t #if __SIZEOF_WCHAR_T__ == 2 // sizeof(wchar_t) == sizeof(uint16) s = (TCHAR *)readBuf; // \ru собственно ничего конвертировать не нужно \en nothing to convert #else // sizeof(wchar_t) == sizeof(uint32) s = (TCHAR *)Utf16ToUcs4(readBuf); // \ru Конвертировать UTF-16 в WCHAR \en Convert from UTF-16 to WCHAR delete [] readBuf; #endif #else // _UNICODE #if __SIZEOF_WCHAR_T__ == 2 // sizeof(wchar_t) == sizeof(uint16) s = wcsnewmbs( (const wchar_t*)readBuf ); // \ru Конвертировать WCHAR в CHAR строку. \en Convert WCHAR-string to CHAR-string. #else // sizeof(wchar_t) == sizeof(uint32) uint32* readBuf32 = Utf16ToUcs4(readBuf); // \ru Конвертировать UTF-16 в WCHAR \en Convert from UTF-16 to WCHAR s = wcsnewmbs( (const wchar_t*)readBuf32 ); // \ru Конвертировать WCHAR в CHAR строку. \en Convert WCHAR-string to CHAR-string. delete [] readBuf32; #endif delete [] readBuf; #endif // _UNICODE } } } return ps; } //---------------------------------------------------------------------------------------- // \ru Чтение WCHAR строки из потока. (в потоке хранится как UTF-16) \en Reading of WCHAR string from the stream. (stored in the stream as UTF-16) // \ru И нулевой указатель и пустая строка возвращаются как нулевой указатель! \en Both null pointer and an empty string are returned as null pointer! // \ru Длина строки не может превышать SYS_MAX_UINT32 - 1 \en The string length cannot exceed SYS_MAX_UINT32 - 1 // \ru Созданную строку кто-то потом должен уничтожить \en Created string should be deleted by someone then // --- inline reader & __readWcharT( reader & ps, wchar_t * & s ) { s = nullptr; // \ru на случай, если ничего не прочитаем \en for case if nothing will be read if ( ps.good() ) { uint32 len = 0; if ( ps.readBytes(&len, sizeof(len)) && // \ru длина строки в символах без терминального нуля - uint32 \en the string length in symbols without the termination zero - uint32 len != 0 && len != SYS_MAX_UINT32 && !ps.eof() ) { uint16 * readBuf = new uint16[(size_t)len + 1]; // \ru длина (количество символов) вычитываемой строки с терминальным нулем \en length (number of symbols) of string being read with terminating 0 size_t size = sizeof(uint16) * (size_t)len; // \ru длина (в байтах) вычитываемой строки без терминального нуля \en length (in bytes) of string being read without terminating null if ( ps.readBytes(readBuf, size) ) // \ru прочли сколько нужно - добавить ограничивающий 0 \en have read as much as necessary - the terminating 0 is to be added readBuf[(size_t)len] = 0; else { // \ru прочли не все, скорее всего ошибка - очистить строку \en not everything has been read, must be an error - clear the string delete [] readBuf; readBuf = nullptr; } if ( readBuf ) { // is OK #if __SIZEOF_WCHAR_T__ == 2 // sizeof(wchar_t) == sizeof(uint16) s = (wchar_t *)readBuf; // \ru собственно ничего конвертировать не нужно \en nothing to convert #else // sizeof(wchar_t) == sizeof(uint32) s = (wchar_t *)Utf16ToUcs4(readBuf); // \ru Конвертировать UTF-16 в WCHAR \en Convert from UTF-16 to WCHAR delete [] readBuf; #endif } } } return ps; } #ifdef C3D_WINDOWS //_MSC_VER // \ru Код для поддержки КОМПАС \en Code for KOMPAS support //---------------------------------------------------------------------------------------- /// \ru Чтение CHAR строки из потока. \en Reading of CHAR string from the stream. \~ \ingroup Base_Tools_IO // \ru И нулевой указатель и пустая строка возвращаются как нулевой указатель! \en Both null pointer and an empty string are returned as null pointer! // --- #ifndef DISABLE_RWTCHAR #ifdef _UNICODE inline reader & operator >> ( reader & ps, char *& s ) { return __readChar( ps, s ); } #endif // _UNICODE #endif // DISABLE_RWTCHAR //---------------------------------------------------------------------------------------- /// \ru Запись CHAR строки в поток. \en Writing CHAR string to the stream. \~ \ingroup Base_Tools_IO // --- #ifndef DISABLE_RWTCHAR #ifdef _UNICODE inline writer & operator << ( writer & ps, const char * s ) { return ps.__writeChar( s ); } #endif // _UNICODE #endif // DISABLE_RWTCHAR //---------------------------------------------------------------------------------------- /// \ru Чтение WCHAR строки из потока. \en Reading of WCHAR string from the stream. \~ \ingroup Base_Tools_IO // \ru И нулевой указатель и пустая строка возвращаются как нулевой указатель! \en Both null pointer and an empty string are returned as null pointer! // \ru длина строки не может превышать SYS_MAX_UINT32 - 1 \en length of string can't exceed SYS_MAX_UINT32 - 1 // --- #ifndef DISABLE_RWTCHAR inline reader & operator >> ( reader & ps, TCHAR *& s ) { return __readWchar( ps, s ); } #endif // DISABLE_RWTCHAR //---------------------------------------------------------------------------------------- /// \ru Запись WCHAR строки в поток. \en Writing WCHAR string to the stream. \~ \ingroup Base_Tools_IO // \ru длина строки не может превышать SYS_MAX_UINT32 - 1 \en string length can't exceed SYS_MAX_UINT32 - 1 // --- #ifndef DISABLE_RWTCHAR inline writer & operator << ( writer & ps, const TCHAR * s ) { return ps.__writeWchar( s ); } #endif // DISABLE_RWTCHAR #endif // C3D_WINDOWS #ifdef __MOBILE_VERSION__ #ifdef _UNICODE inline reader & operator >> ( reader & ps, char *& s ){ return __readChar( ps, s );} inline writer & operator << ( writer & ps, const char * s ){ return ps.__writeChar( s );} inline reader & operator >> ( reader & ps, TCHAR *& s ){ return __readWchar( ps, s );} inline writer & operator << ( writer & ps, const TCHAR * s ){ return ps.__writeWchar( s );} #endif // _UNICODE #endif // __MOBILE_VERSION__ //---------------------------------------------------------------------------------------- /// \ru Запись bool в поток. \en Writing bool to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, bool i ) { //unsigned char val = i; uint8 val = i ? 1 : 0; ps.writeByte( val ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение bool в поток. \en Reading of bool to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, bool & i ) { if ( IsVersion16bit( ps.MathVersion() ) ) { unsigned short tmp = 0; ps.readBytes( &tmp, sizeof(unsigned short) ); i = !!tmp; } else i = !!ps.readByte(); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись signed int в поток. \en Writing signed int to the stream. \~ \ingroup Base_Tools_IO // \ru оператор записи для типов: int (не поддерживает int32, long, LONG - для них есть своя реализация) \en write operator for types: int (doesn't support int32, long, LONG - there is a separate implementation for them) // \ru поддерживает запись в 32 и 16-битный формат файла \en supports writing to 32- and 16-bit format of file // --- inline writer & operator << ( writer & ps, signed int i ) { #ifdef C3D_WINDOWS //_MSC_VER if ( IsVersion16bit( ps.MathVersion() ) ) { // \ru чтение из 16-битной версии файла \en reading from 16-bit version of file // \ru ради этого куска чтение/запись int отделено от чтения/записи long \en reading/writing of int is separated from reading/writing of long for the sake of this fragment int16 val = (int16)i; ps.writeBytes( &val, sizeof(val) ); } else { int32 val = (int32)i; ps.writeBytes( &val, sizeof(val) ); } return ps; #else // C3D_WINDOWS if ( IsVersion16bit( ps.MathVersion() ) ) ps.setState( io::fail ); // \ru в Linux-версии 16-битные файлы не поддерживаются \en 16-bit files are not supported in Linux else { int32 val = (int32)i; ps.writeBytes( &val, sizeof(val) ); } return ps; #endif // C3D_WINDOWS } //---------------------------------------------------------------------------------------- /// \ru Запись unsigned int в поток. \en Writing unsigned int to the stream. \~ \ingroup Base_Tools_IO // \ru оператор записи для типов: uint (не поддерживает uint32, ulong - для них есть своя реализация) \en write operator for types: uint (doesn't support uint32, ulong - there is a separate implementation for them) // \ru поддерживает запись в 32 и 16-битный формат файла \en supports writing to 32- and 16-bit format of file // --- inline writer & operator << ( writer & ps, unsigned int i ) { #ifdef C3D_WINDOWS //_MSC_VER if ( IsVersion16bit( ps.MathVersion() ) ) { // \ru чтение из 16-битной версии файла \en reading from 16-bit version of file // \ru ради этого куска чтение/запись int отделено от чтения/записи long \en reading/writing of int is separated from reading/writing of long for the sake of this fragment uint16 val = (uint16)i; ps.writeBytes( &val, sizeof(val) ); } else { uint32 val = i; ps.writeBytes( &val, sizeof(val) ); } return ps; #else // C3D_WINDOWS if ( IsVersion16bit( ps.MathVersion() ) ) ps.setState( io::fail ); // \ru в Linux-версии 16-битные файлы не поддерживаются \en 16-bit files are not supported in Linux else { uint32 val = i; ps.writeBytes( &val, sizeof(val) ); } return ps; #endif // C3D_WINDOWS } //---------------------------------------------------------------------------------------- /// \ru Чтение signed int в поток. \en Reading signed int to the stream. \~ \ingroup Base_Tools_IO // \ru оператор чтения для типов: int (не поддерживает int32, long, LONG - для них есть своя реализация) \en read operator for types: int (doesn't support int32, long, LONG - there is a separate implementation for them) // \ru поддерживает чтение из 32 и 16-битного формата файла \en supports reading from 32- and 16-bit format of file // --- inline reader & operator >> ( reader & ps, signed int & i ) { #ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 if ( IsVersion16bit( ps.MathVersion() ) ) { // \ru чтение из 16-битной версии файла \en reading from 16-bit version of file // \ru ради этого куска чтение/запись int отделено от чтения/записи long \en reading/writing of int is separated from reading/writing of long for the sake of this fragment int16 val = 0; ps.readBytes( &val, sizeof(val) ); i = val; } else { int32 val = 0; ps.readBytes( &val, sizeof(val) ); i = (signed int)val; } return ps; #else // C3D_WINDOWS if ( IsVersion16bit( ps.MathVersion() ) ) ps.setState( io::fail ); // \ru в Linux-версии 16-битные файлы не поддерживаются \en 16-bit files are not supported in Linux else { int32 val = 0; ps.readBytes( &val, sizeof(val) ); i = (signed int)val; } return ps; #endif // C3D_WINDOWS } //---------------------------------------------------------------------------------------- /// \ru Чтение unsigned int в поток. \en Reading unsigned int to the stream. \~ \ingroup Base_Tools_IO // \ru оператор чтения для типов: uint (не поддерживает uint32, ulong - для них есть своя реализация) \en read operator for types: uint (doesn't support uint32, ulong - there is a separate implementation for them) // \ru поддерживает чтение из 32 и 16-битного формата файла \en supports reading from 32- and 16-bit format of file // --- inline reader & operator >> ( reader & ps, unsigned int & i ) { #ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 if ( IsVersion16bit( ps.MathVersion() ) ) { // \ru чтение из 16-битной версии файла \en reading from 16-bit version of file // \ru ради этого куска чтение/запись int отделено от чтения/записи long \en reading/writing of int is separated from reading/writing of long for the sake of this fragment uint16 val = 0; ps.readBytes( &val, sizeof(val) ); i = val; } else { uint32 val = 0; ps.readBytes( &val, sizeof(val) ); i = (unsigned int)val; } return ps; #else // C3D_WINDOWS if ( IsVersion16bit( ps.MathVersion() ) ) ps.setState( io::fail ); // \ru в Linux-версии 16-битные файлы не поддерживаются \en 16-bit files are not supported in Linux else { uint32 val = 0; ps.readBytes( &val, sizeof(val) ); i = (unsigned int)val; } return ps; #endif // C3D_WINDOWS } //---------------------------------------------------------------------------------------- /// \ru Запись int32 в поток. \en Writing int32 to the stream. \~ \ingroup Base_Tools_IO // \ru оператор записи для типов: long, int32, LONG (не поддерживает int - для него есть своя реализация) \en write operator for types: long, int32, LONG (does not support int - there is a separate implementation for it) // \ru данные всегда пишутся в 32-разрядном формате \en data are always written in 32-bit format // --- #ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 // \ru ВНИМАНИЕ!!! В целях совместимости данных для задач скомпилированных под Windows и Linux \en NOTE!!! To provide data compatibility for tasks compiled for Windows and Linux // \ru ЗАПРЕЩАЕТСЯ использовать тип данных long и unsigned long. Используйте int32 и uint32 \en IT IS FORBIDDEN to use long and unsigned long data types. Use int32 and uint32 inline writer & operator << ( writer & ps, int32 l ) { ps.writeBytes( &l, sizeof(l) ); return ps; } #endif // C3D_WINDOWS //---------------------------------------------------------------------------------------- /// \ru Запись uint32 в поток. \en Writing uint32 to the stream. \~ \ingroup Base_Tools_IO // \ru оператор записи для типов: ulong, uint32 (не поддерживает uint - для него есть своя реализация) \en write operator for types: ulong, uint32 (does not support uint - there is a separate implementation for it) // \ru данные всегда пишутся в 32-разрядном формате \en data are always written in 32-bit format // --- #ifdef C3D_WINDOWS // Linux identical int/uint and int32/uint32 // \ru ВНИМАНИЕ!!! В целях совместимости данных для задач скомпилированных под Windows и Linux \en NOTE!!! To provide data compatibility for tasks compiled for Windows and Linux // \ru ЗАПРЕЩАЕТСЯ использовать тип данных long и unsigned long. Используйте int32 и uint32 \en IT IS FORBIDDEN to use long and unsigned long data types. Use int32 and uint32 inline writer & operator << ( writer & ps, uint32 l ) { ps.writeBytes( &l, sizeof(l) ); return ps; } #endif // C3D_WINDOWS //---------------------------------------------------------------------------------------- /// \ru Чтение int32 в поток. \en Reading int32 to the stream. \~ \ingroup Base_Tools_IO // \ru оператор чтения для типов: long, int32, LONG (не поддерживает int - для него есть своя реализация) \en read operator for types: long, int32, LONG (does not support int - there is a separate implementation for it) // \ru данные всегда читаются в 32-разрядном формате \en data are always read in 32-bit format // --- #ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 // \ru ВНИМАНИЕ!!! В целях совместимости данных для задач скомпилированных под Windows и Linux \en NOTE!!! To provide data compatibility for tasks compiled for Windows and Linux // \ru ЗАПРЕЩАЕТСЯ использовать тип данных long и unsigned long. Используйте int32 и uint32 \en IT IS FORBIDDEN to use long and unsigned long data types. Use int32 and uint32 inline reader & operator >> ( reader & ps, int32 & l ) { size_t size = sizeof(int32); if ( !ps.readBytes(&l, size) ) l = 0; return ps; } #endif // C3D_WINDOWS //---------------------------------------------------------------------------------------- /// \ru Чтение uint32 в поток. \en Reading uint32 to the stream. \~ \ingroup Base_Tools_IO // \ru оператор чтения для типов: ulong, uint32 (не поддерживает uint - для него есть своя реализация) \en read operator for types: ulong, uint32 (does not support uint - there is a separate implementation for it) // \ru данные всегда читаются в 32-разрядном формате \en data are always read in 32-bit format // --- #ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 // \ru ВНИМАНИЕ!!! В целях совместимости данных для задач скомпилированных под Windows и Linux \en NOTE!!! To provide data compatibility for tasks compiled for Windows and Linux // \ru ЗАПРЕЩАЕТСЯ использовать тип данных long и unsigned long. Используйте int32 и uint32 \en IT IS FORBIDDEN to use long and unsigned long data types. Use int32 and uint32 inline reader & operator >> ( reader & ps, uint32 & l ) { size_t size = sizeof(uint32); if ( !ps.readBytes(&l, size) ) l = 0; return ps; } #endif // C3D_WINDOWS //---------------------------------------------------------------------------------------- /// \ru Запись int64 в поток. \en Writing int64 to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, int64 val ) { ps.writeInt64( val ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение int64 в поток. \en Reading int64 to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, int64 & val ) { ps.readInt64( val ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение signed char в поток. \en Reading signed char to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, signed char & ch ) { ch = (signed char)ps.readByte(); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение unsigned char в поток. \en Reading unsigned char to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, unsigned char & ch ) { ch = (unsigned char)ps.readByte(); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение char в поток. \en Reading char to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, char & ch ) { ch = (char)ps.readByte(); return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение signed short в поток. \en Reading signed short to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, signed short & sh ) { const size_t size = sizeof(sh); if ( !ps.readBytes(&sh, size) ) sh = 0; return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение unsigned short в поток. \en Reading unsigned short to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, unsigned short & sh ) { const size_t size = sizeof(sh); if ( !ps.readBytes(&sh, size) ) sh = 0; return ps; } #ifndef __ATS_BUILD__ // Нужно для сборки решения Tools\ATS... //---------------------------------------------------------------------------------------- /// \ru Чтение wchar_t в поток. \en Reading wchar_t to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, wchar_t & sh ) { sh = 0; //Обнулить, т.к. размер 4 байта, а читаются только 2 //size_t size = sizeof(sh); size_t size = 2; //В windows sizeof(wchar_t) = 2, в Android sizeof(wchar_t) = 4 if ( !ps.readBytes(&sh, size) ) sh = 0; return ps; } #endif // __ATS_BUILD__ //---------------------------------------------------------------------------------------- /// \ru Чтение float в поток. \en Reading float to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, float & f ) { size_t size = sizeof(f); if ( !ps.readBytes(&f, size) ) f = 0; return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение double в поток. \en Reading double to the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, double & d ) { size_t size = sizeof(d); if ( !ps.readBytes(&d, size) ) d = 0; // \ru Проверка числа на определенность \en Check if the number is defined if ( c3d_isnan(d) ) d = 0; return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение long double из потока. \en Reading long double from the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, long double & l ) { size_t size = sizeof(l); if ( !ps.readBytes(&l, size) ) l = 0; return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение smart-указателя из потока. \en Reading a smart pointer from the stream. \~ \ingroup Base_Tools_IO // --- template inline reader & operator >> ( reader & ps, SPtr<_Class> & sPtr ) { _Class * ptr = nullptr; ps >> ptr; sPtr.assign( ptr ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись smart-указателя в поток. \en Writing a smart pointer to the stream. \~ \ingroup Base_Tools_IO // --- template inline writer & operator << ( writer & ps, const SPtr<_Class> & sPtr ) { ps << sPtr.get(); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись signed char в поток. \en Write signed char to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, signed char ch ) { ps.writeByte( ch ); // \ru байт \en byte return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись unsigned char в поток. \en Write unsigned char to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, unsigned char ch ) { ps.writeByte( ch ); // \ru байт \en byte return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись char в поток. \en Write char to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, char ch ) { ps.writeByte( ch ); // \ru байт \en byte return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись signed short в поток. \en Write signed short to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, signed short sh ) { ps.writeBytes( &sh, sizeof(sh) ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись unsigned short в поток. \en Write unsigned short to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, unsigned short sh ) { ps.writeBytes( &sh, sizeof(sh) ); return ps; } #ifndef __ATS_BUILD__ // Нужно для сборки решения Tools\ATS... //---------------------------------------------------------------------------------------- /// \ru Запись wchar_t в поток. \en Write wchar_t to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, wchar_t sh ) { size_t size = 2; //В windows sizeof(wchar_t) = 2, в Android sizeof(wchar_t) = 4 ps.writeBytes( &sh, size ); return ps; } #endif // __ATS_BUILD__ //---------------------------------------------------------------------------------------- /// \ru Запись float в поток. \en Write float to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, float f ) { ps.writeBytes( &f, sizeof(f) ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись double в поток. \en Write double to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, const double & d ) { ps.writeBytes( &d, sizeof(d) ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись long double в поток. \en Write long double to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, const long double & l ) { ps.writeBytes( &l, sizeof(l) ); return ps; } //---------------------------------------------------------------------------------------- /// \ru Записать TCHAR строку в поток. \en Write TCHAR string to the stream. \~ \ingroup Base_Tools_IO // --- inline void WriteTCHAR( writer & out, const TCHAR * ts, bool directSingleByte = false ) { if ( directSingleByte || out.MathVersion() < UNICODE_VERSION ) { // \ru пишем WCHAR* как CHAR* \en write WCHAR* as CHAR* char * s = _tcsNstr( ts ); // \ru создаем ANSI из TCHAR (если TCHAR == char, то просто дублируем) \en create ANSI from TCHAR (if TCHAR == char, then simply duplicate) out.__writeChar( s ); // \ru пишем строку в формате ANSI \en write string in ANSI format delete [] s; } else { // \ru пишем WCHAR* \en write WCHAR* out.__writeWchar( ts ); } } //---------------------------------------------------------------------------------------- /// \ru Прочитать TCHAR строку из потока. \en Read TCHAR string from the stream. \~ \ingroup Base_Tools_IO //--- inline void ReadTCHAR( reader & in, TCHAR *& ts, bool directSingleByte = false ) { if ( directSingleByte || in.MathVersion() < UNICODE_VERSION ) { #ifndef C3D_WINDOWS C3DLocaleSwitcher lh( FIX_ANSI1251, in.MathVersion() < UNICODE_VERSION ); #endif // \ru читаем WCHAR* из CHAR* \en read WCHAR* from CHAR* char * s = nullptr; __readChar( in, s ); // \ru читаем строку в формате ANSI \en read string in ANSI format ts = _strNtcs( s ); // \ru создаем TCHAR из ANSI (если TCHAR == char, то просто дублируем) \en create TCHAR from ANSI (if TCHAR == char, then simply duplicate) delete [] s; } else { // \ru читаем WCHAR* \en read WCHAR* __readWchar( in, ts ); } } //---------------------------------------------------------------------------------------- /// \ru Записать wchar_t строку в поток. \en Write wchar_t string to the stream. \~ \ingroup Base_Tools_IO // --- inline void WriteWcharT( writer & out, const wchar_t * ts ) { out.__writeWcharT( ts ); } //---------------------------------------------------------------------------------------- /// \ru Прочитать TCHAR строку из потока. \en Read TCHAR string from the stream. \~ \ingroup Base_Tools_IO //--- inline void ReadWcharT( reader& in, wchar_t *& ts ) { __readWcharT( in, ts ); } //---------------------------------------------------------------------------------------- /// \ru Запись size_t в зависимости от версии потока. \en Write size_t subject to the stream version. \~ \ingroup Base_Tools_IO // --- inline void WriteCOUNT( writer & out, size_t count ) { if ( IsVersion64bit( out.MathVersion() ) ) { uint64 count64 = count; if ( out.MathVersion() >= 0x0F001001L ) { if ( count64 == SYS_MAX_T ) count64 = SYS_MAX_UINT64; } out.writeUInt64( count64 ); } else { // \ru OV_x64 проверить переполнение при записи 64-битных данных в 32-битный поток \en OV_x64 check for overflow while writing 64-bit data to 32-bit stream if ( HiUint32( count ) != 0 ) out.setState( io::underflow64to32 ); uint32 _count = (uint32)LoUint32(count); out << _count; } } //---------------------------------------------------------------------------------------- /// \ru Запись ptrdiff_t в зависимости от версии потока. \en Writing ptrdiff_t subject to the stream version. \~ \ingroup Base_Tools_IO // --- inline void WriteINT_T( writer & out, ptrdiff_t count ) { if ( IsVersion64bit( out.MathVersion() ) ) { out.writeInt64( count ); } else { // \ru OV_x64 проверить переполнение при записи 64-битных данных в 32-битный поток \en OV_x64 check for overflow while writing 64-bit data to 32-bit stream if ( (int64)count > (int64)SYS_MAX_INT32 || (int64)count < (int64)SYS_MIN_INT32 ) out.setState( io::underflow64to32 ); int32 _count = (int32)LoUint32(count); out << _count; } } //---------------------------------------------------------------------------------------- /// \ru Чтение size_t в зависимости от версии потока. \en Reading size_t subject to the stream version. \~ \ingroup Base_Tools_IO // // \ru Т.к. операторы чтения/записи для uint и uint32 разные нужно \en Since reading/writing operators are different for uint and uint32, // \ru уметь читать оба, в зависимости от места где вызывается. \en there should be capability for reading both of them subject to the place where it is called. // \ru Решено запись не менять, т.к. в 16 битовую задачу не записываем. \en Decided not to modify writing since we do not write to 16-bit task. // --- inline size_t ReadCOUNT ( reader & in, bool uint_val = true ) { size_t count = 0; if ( IsVersion64bit( in.MathVersion() ) ) { uint64 _count = 0; in.readUInt64( _count ); if ( in.MathVersion() >= 0x0F001001L ) { if ( _count == SYS_MAX_UINT64 ) _count = SYS_MAX_T; } else { // \Mapping\a_17356\17356_Телега.c3d PRECONDITION( _count != SYS_MAX_UINT32 ); // неоднозначность интерпретации значения // Primery_Set/Models_8/_58720. if ( _count == SYS_MAX_UINT32 || _count == SYS_MAX_UINT64 ) _count = SYS_MAX_T; } count = (size_t)_count; // \ru OV_x64 проверить переполнение при чтении 64-битных данных в 32-битной задаче \en OV_x64 check for overflow while reading 64-bit data in 32-bit task if ( HiUint32(count) != HiUint32(_count) ) in.setState( io::underflow64to32 ); } else { // \ru оператор чтения в uint (в отличии от uint32) поддерживает чтение 16-битных версий файла \en operator of reading to uint (in contrast to uint32) supports reading 16-bit versions of file if ( uint_val ) { uint _count = 0; in >> _count; count = (size_t)_count; } else { uint32 _count = 0; in >> _count; count = (size_t)_count; } if ( count == SYS_MAX_UINT32 ) count = SYS_MAX_T; } return count; } //---------------------------------------------------------------------------------------- /// \ru Чтение ptrdiff_t в зависимости от версии потока. \en Reading ptrdiff_t subject to the stream version. \~ \ingroup Base_Tools_IO // // \ru Т.к. операторы чтения/записи для uint и uint32 разные нужно \en Since reading/writing operators are different for uint and uint32, // \ru уметь читать оба, в зависимости от места где вызывается. \en there should be capability for reading both of them subject to the place where it is called. // \ru Решено запись не менять, т.к. в 16 битовую задачу не записываем. \en Decided not to modify writing since we do not write to 16-bit task. // --- // \ru САА K13 31.8.2010 Исправление BUG 52091 \en CAA K13 31.8.2010 Fix for BUG 52091 // \ru 77 вызовов и из них только 2 с false!!! - поэтому по умолчанию для всех \en 77 calls and only 2 of them with false!!! - so it is default for all inline ptrdiff_t ReadINT_T( reader & in, bool uint_val = true ) { ptrdiff_t count = 0; if ( IsVersion64bit( in.MathVersion() ) ) { int64 _count = 0; in.readInt64( _count ); count = (ptrdiff_t)_count; // \ru OV_x64 проверить переполнение при чтении 64-битных данных в 32-битной задаче \en OV_x64 check for overflow while reading 64-bit data in 32-bit task if ( HiInt32(count) != HiInt32(_count) ) in.setState( io::underflow64to32 ); } else { // \ru оператор чтения в uint (в отличии от uint32) поддерживает чтение 16-битных версий файла \en operator of reading to uint (in contrast to uint32) supports reading 16-bit versions of file if ( uint_val ) { int _count = 0; in >> _count; count = (ptrdiff_t)_count; } else { int32 _count = 0; in >> _count; count = (ptrdiff_t)_count; } } return count; } //---------------------------------------------------------------------------------------- /// \ru Запись size_t в память в зависимости от версии потока. \en Writing size_t to the memory subject to the stream version. \~ \ingroup Base_Tools_IO // --- inline void WriteCOUNT( void * out, VERSION version, size_t count ) { if ( IsVersion64bit(version) ) { const uint64 count64 = (uint64)count; ::memcpy( out, &count64, sizeof(count64) ); } else { // \ru OV_x64 проверить переполнение при записи 64-битных данных в 32-битный поток \en OV_x64 check for overflow while writing 64-bit data to 32-bit stream //OV_x64 if ( count > (int64)_I32_MAX || count < (int64)_I32_MIN ) //OV_x64 out.setState( io::underflow64to32 ); PRECONDITION( count <= (size_t)SYS_MAX_UINT32/*_UI32_MAX*/ ); const uint32 count32 = (uint32)LoUint32(count); ::memcpy( out, &count32, sizeof(count32) ); } } //---------------------------------------------------------------------------------------- /// \ru Запись ptrdiff_t в память в зависимости от версии потока. \en Writing ptrdiff_t to the memory subject to the stream version. \~ \ingroup Base_Tools_IO // --- inline void WriteCOUNT( void * out, VERSION version, ptrdiff_t count ) { if ( IsVersion64bit(version) ) { const int64 count64 = (int64)count; ::memcpy( out, &count64, sizeof(count64) ); } else { // \ru OV_x64 проверить переполнение при записи 64-битных данных в 32-битный поток \en OV_x64 check for overflow while writing 64-bit data to 32-bit stream //OV_x64 if ( count > (int64)_I32_MAX || count < (int64)_I32_MIN ) //OV_x64 out.setState( io::underflow64to32 ); PRECONDITION( count <= (ptrdiff_t)SYS_MAX_INT32/*_I32_MAX*/ && count >= (ptrdiff_t)SYS_MIN_INT32/*_I32_MIN*/ ); const int32 count32 = (int32)LoUint32(count); ::memcpy( out, &count32, sizeof(count32) ); } } //---------------------------------------------------------------------------------------- /// \ru Чтение size_t в память в зависимости от версии потока. \en Reading of size_t to the memory subject to the stream version. \~ \ingroup Base_Tools_IO // --- inline size_t ReadCOUNT ( void * in, VERSION version ) { size_t count = 0; if ( IsVersion64bit(version) ) { uint64 count64 = 0; ::memcpy( &count64, in, sizeof(count64) ); PRECONDITION( count64 <= SYS_MAX_T/*SIZE_MAX*/ ); count = (size_t)count64; // \ru OV_x64 проверить переполнение при чтении 64-битных данных в 32-битной задаче \en OV_x64 check for overflow while reading 64-bit data in 32-bit task //OV_x64 if ( HiUint32( count ) != HiUint32( _count ) ) //OV_x64 in.setState( io::underflow64to32 ); } else { uint32 count32 = 0; ::memcpy( &count32, in, sizeof(count32) ); PRECONDITION( sizeof(count32) <= sizeof(count)); // Cannot readCOUNT because sizof(uint32) > sizeof(size_t) count = /*AR (size_t)*/count32; //-V101 } return count; } //---------------------------------------------------------------------------------------- /** \brief \ru Получить упакованное имя класса по значению хэша записанному в поток. \en Get the packed class name from the hash value written to the stream. \~ \details \ru Получить упакованное имя класса по значению хэша записанному в поток. \n \en Get the packed class name from the hash value written to the stream. \n \~ \param[in] classDescr - \ru Обертка хэша. \en Hash value wrapper. \~ \param[in] ver - \ru Версия потока в котором записан хэш. \en The version of the stream in which the hash is written. \~ \result \ru Возвращает упакованное имя класса. \en Returns the packed class name. \~ \ingroup Base_Tools_IO */ // --- MATH_FUNC (ClassDescriptor) GetPackedClassName( const ClassDescriptor & classDescr, const VersionContainer & ver ); //---------------------------------------------------------------------------------------- /** \brief \ru Добавить новое соответствие значения хэша записанного в поток упакованному имени класса. \en Add a new mapping of the hash value written to the stream to the packed class name. \~ \details \ru Добавить новое соответствие значения хэша записанного в поток упакованному имени класса. \n \en Add a new mapping of the hash value written to the stream to the packed class name. \n \~ \param[in] newClassName - \ru Новое имя класса. \en New class name. \~ \param[in] oldClassName - \ru Старое имя класса. \en Old class name. \~ \param[in] appIndex - \ru Индекс приложения, которому принадлежит класс. \en The index of the application that the class belongs to. \~ \param[in] lowVersion - \ru Нижняя граница версии. \en Version lower bound. \~ \param[in] highVersion - \ru Верхняя граница версии. \en Version upper bound. \~ \ingroup Base_Tools_IO */ // --- MATH_FUNC (void) AddPackedClassNameForVersion( const ClassDescriptor & newClassName, const ClassDescriptor & oldClassName, uint appIndex, VERSION lowVersion, VERSION highVersion ); //---------------------------------------------------------------------------------------- /** \brief \ru Диагностика коллизий имени нового класса с зарегистрированными классами. \en Diagnostics of collisions of new class name with registered classes. \~ \details \ru Диагностика коллизий имени нового класса с зарегистрированными классами. \n \en Diagnostics of collisions of new class name with registered classes. \n \~ \param[in] className - \ru Имя класса. \en The class name. \~ \param[in] appID - \ru Идентификатор приложения. \en The application id. \~ \return \ru Признак уникальности класса с заданным именем при регистрации с указанным идентификатором приложения. \en Whether the class with the specified name is unique if registered with specified application id. \~ \ingroup Base_Tools_IO */ // --- MATH_FUNC( bool ) IsValidStreamClassName( const char * className, const MbUuid & appID ); #ifndef SIMPLENAME_AS_CLASS //---------------------------------------------------------------------------------------- /// \ru Запись простого имени. \en Writing of a simple name. \~ \ingroup Base_Tools_IO // --- inline void WriteSimpleName( writer & out, const SimpleName & s ) { out << s; } //---------------------------------------------------------------------------------------- /// \ru Чтение простого имени. \en Reading of a simple name. \~ \ingroup Base_Tools_IO // --- inline SimpleName ReadSimpleName( reader & in ) { SimpleName s = 0; in >> s; return s; } #else // SIMPLENAME_AS_CLASS //---------------------------------------------------------------------------------------- /// \ru Запись простого имени. \en Writing of a simple name. \~ \ingroup Base_Tools_IO // --- inline void WriteSimpleName( writer & out, const SimpleName & s ) { size_t sn = s; WriteCOUNT( out, sn ); } //---------------------------------------------------------------------------------------- /// \ru Чтение простого имени. \en Reading of a simple name. \~ \ingroup Base_Tools_IO // --- inline SimpleName ReadSimpleName( reader & in ) { size_t sn = ReadCOUNT( in ); return SimpleName(sn); } #endif // SIMPLENAME_AS_CLASS namespace c3d // namespace C3D { //---------------------------------------------------------------------------------------- /// \ru Оператор записи хэша. \en Operator of writing hash. \~ \ingroup Base_Tools_IO //--- inline writer & operator << ( writer & out, const StrHash & strHash ) { // \ru Нельзя допускать хеш с неопределенным типом и с определенным значением \en Hash with undefined type and with specified value cannot be allowed PRECONDITION( !(IsGoodSimpleName(strHash.m_val) && strHash.m_type == c3d::StrHash::htp_undef) ); WriteSimpleName( out, strHash.m_val ); if ( out.MathVersion() >= 0x0A001005L ) out << strHash.m_type; return out; } //---------------------------------------------------------------------------------------- /// \ru Оператор чтения хэша. \en Operator of hash reading. \~ \ingroup Base_Tools_IO //--- inline reader & operator >> ( reader & in, c3d::StrHash & strHash ) { strHash.m_val = ReadSimpleName( in ); if ( in.MathVersion() >= UNICODE_VERSION ) if ( in.MathVersion() >= 0x0A001005L /*\ru введена запись типа хеша \en record of hash type is set */) in >> strHash.m_type; else strHash.m_type = c3d::StrHash::htp_wchar; // \ru !!! Переходный период, могут быть разные \en !!! Period of transition, may be different else strHash.m_type = c3d::StrHash::htp_char; // \ru Нельзя допускать хеш с неопределенным типом и с определенным значением \en Hash with undefined type and with specified value cannot be allowed PRECONDITION( !(IsGoodSimpleName(strHash.m_val) && strHash.m_type == c3d::StrHash::htp_undef) ); return in; } } // namespace C3D //---------------------------------------------------------------------------------------- /// \ru Запись строки в поток. \en Writing a string to the stream. \~ \ingroup Base_Tools_IO //--- inline writer & operator << ( writer & ps, const std::string & s ) { if ( ps.MathVersion() < UNICODE_VERSION ) { // \ru пишем WCHAR* как CHAR* \en write WCHAR* as CHAR* ps.__writeChar( s.c_str() ); // \ru пишем строку в формате ANSI \en write string in ANSI format } else { wchar_t* buf = mbsnewwcs( s.c_str() ); WriteWcharT( ps, buf ); delete[] buf; } return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение строки из потока. \en Reading a string from the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, std::string & s ) { if ( ps.MathVersion() < UNICODE_VERSION ) { #ifndef C3D_WINDOWS C3DLocaleSwitcher lh( FIX_ANSI1251 ); #endif char * str( nullptr ); __readChar( ps, str ); // \ru читаем строку в формате ANSI \en read string in ANSI format if ( str ) s = str; else s.clear(); delete [] str; } else { wchar_t * p (nullptr); ReadWcharT( ps, p ); // \ru в зависимости от версии потока \en subject to the stream version if ( p ) { char* str = wcsnewmbs(p); if ( str ) s = str; else s.clear(); delete[] str; } else s.clear(); delete [] p; } return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись строки в поток. \en Writing a string to the stream. \~ \ingroup Base_Tools_IO // --- inline writer & operator << ( writer & ps, const std::wstring & s ) { if ( ps.MathVersion() < UNICODE_VERSION ) { // \ru пишем WCHAR* как CHAR* \en write WCHAR* as CHAR* char * str = wcsnewmbs( s.c_str() ); // \ru создаем ANSI из TCHAR (если TCHAR == char, то просто дублируем) \en create ANSI from TCHAR (if TCHAR == char, then simply duplicate) ps.__writeChar( str ); // \ru пишем строку в формате ANSI \en write string in ANSI format delete [] str; } else WriteWcharT( ps, s.c_str() ); // \ru в зависимости от версии потока \en subject to the stream version return ps; } //---------------------------------------------------------------------------------------- /// \ru Чтение строки из потока. \en Reading a string from the stream. \~ \ingroup Base_Tools_IO // --- inline reader & operator >> ( reader & ps, std::wstring & s ) { if ( ps.MathVersion() < UNICODE_VERSION ) { #ifndef C3D_WINDOWS C3DLocaleSwitcher lh( FIX_ANSI1251 ); #endif char * str( nullptr ); __readChar( ps, str ); // \ru читаем строку в формате ANSI \en read string in ANSI format wchar_t* p = mbsnewwcs( str ); if ( p ) s = p; else s.clear(); delete [] p; delete [] str; } else { wchar_t * p = nullptr; ReadWcharT( ps, p ); // \ru в зависимости от версии потока \en subject to the stream version if ( p ) s = p; else s.clear(); delete [] p; } return ps; } //---------------------------------------------------------------------------------------- /// \ru Запись строки в поток. \en Writing a string to the stream. \~ \ingroup Base_Tools_IO //--- inline writer & operator << ( writer & ps, const std::wstring * s ) { WriteWcharT( ps, (s ? s->c_str() : nullptr) ); // \ru в зависимости от версии потока \en subject to the stream version return ps; } //---------------------------------------------------------------------------------------- /// \ru Прочитать кластер. \en Read the cluster. \~ \ingroup Base_Tools_IO // --- inline void ReadCluster( reader & in, uint16 clusterSize, Cluster & cl ) { // \ru очистить поле указателя, т.к. в AllocMem есть проверка на 0 \en clear the pointer field since there is a check for 0 in AllocMem cl.SetClusterOffset( 0 ); // \ru распределяем кластер стандартной длины ... \en allocate a cluster of a standard length ... cl.AllocMem( clusterSize ); uint16 length = 0; in >> length; PRECONDITION( length <= clusterSize ); cl.m_l = length; // \ru ...а читаем - сколько было занято \en ...but read as much as has been occupied in.readBytes( (uint8*)cl.m_f, length ); } //---------------------------------------------------------------------------------------- /// \ru Записать кластер, параметр clusterSize используется для проверки корректности длины кластера. /// \en Write the cluster, the clusterSize parameter is used to checking the cluster length. // \~ \ingroup Base_Tools_IO // --- #ifdef C3D_DEBUG inline void WriteCluster( writer & out, const Cluster & cl, uint16 clusterSize ) #else inline void WriteCluster( writer & out, const Cluster & cl, uint16 /*clusterSize*/ ) #endif { uint16 len = cl.m_l; PRECONDITION( len <= clusterSize ); out << len; out.writeBytes( (const uint8*)cl.m_f, len ); } //---------------------------------------------------------------------------------------- /// \ru Записать информацию о кластере. \en Write the information about the cluster. \~ \ingroup Base_Tools_IO // --- inline size_t WriteClusterInfo( void * out, VERSION version, const Cluster & obj ) { WriteCOUNT( out, version, obj.m_f ); uint16 len = obj.m_l; ::memcpy( (uint8*)out + LenCOUNT(version), &len, sizeof( len ) ); return Cluster::SizeOf( version ); } //---------------------------------------------------------------------------------------- /// \ru Прочитать информацию о кластере. \en Read the information about the cluster. \~ \ingroup Base_Tools_IO // --- inline size_t ReadClusterInfo( void * in, VERSION version, Cluster & obj ) { size_t off = ReadCOUNT( in, version ); uint16 len = 0; ::memcpy( &len, (uint8*)in + LenCOUNT(version), sizeof( len ) ); obj.AllocFile( off, len ); // \ru запомнить смещение в файле и кол-во байт \en memorize the shift in file and the number of bytes return Cluster::SizeOf( version ); } //------------------------------------------------------------------------------ // \ru Записать содержимое кластера. Возвращает размер данных кластера или -1, если длина кластера больше заявленной. // \en Write the cluster's contents. Return size of cluster's data or -1, if the cluster length is greater than the defined one. // --- inline size_t WriteClusterBody( void * out, VERSION version, const Cluster & obj, uint16 clusterSize ) { uint8 * m = (uint8 *)out; // \ru кол-во заполненных байт в кластере \en the number of filled bytes in the cluster uint16 l = obj._len(); PRECONDITION( l <= clusterSize ); *(uint16*)m = l; m += sizeof(uint16); if ( l > clusterSize ) return (size_t)-1; if ( l ) { memcpy( m, obj._ptr(), l ); // \ru теперь данные кластера \en the cluster data now // не используется далее m += l; } return getMemLen( obj, version ) ; } //------------------------------------------------------------------------------ // \ru Прочитать содержимое кластера. Возвращает размер данных кластера или -1, если длина кластера больше заявленной. // \en Read the cluster's contents. Return size of cluster's data or -1, if the cluster length is greater than the defined one. // --- inline size_t ReadClusterBody( void * in, VERSION version, Cluster & obj, uint16 clusterSize ) { uint8 * m = (uint8 *)in; // \ru прочитать кол-во заполненных байт кластера и заполнить соответствующее поле в нем \en read the number of filled bytes in the cluster and fill its corresponding field uint16 l = *(uint16*)m; PRECONDITION( l <= clusterSize ); obj.SetClusterLength( l ); m += sizeof(uint16); if ( l > clusterSize ) return (size_t)-1; if ( l ) { memcpy( obj._getMemPointer(), m, l ); // \ru теперь данные кластера \en the cluster data now // не используется далее m += l; } return getMemLen( obj, version ); } //------------------------------------------------------------------------------ /** \brief \ru Стартовать try-catch регион для I/O операций. \en Start try-catch region for I/O operations. \~ \ingroup Base_Tools */ //--- #define C3D_IO_CATCH_START \ try { //------------------------------------------------------------------------------ /** \brief \ru Завершить try-catch регион для I/O операций (аргумент iostrm - поток чтения или записи). \en Complete try-catch region for I/O operations (argument iostrm - reading or writing stream). \~ \ingroup Base_Tools */ //--- #define C3D_IO_CATCH_END(iostrm) \ } \ catch ( const std::bad_alloc & ) { \ iostrm.setState( io::outOfMemory ); \ } \ catch ( ... ) { \ iostrm.setState( io::fail ); \ } //------------------------------------------------------------------------------ // \ru Реализация функций записи по неконстантной ссылке/указателю (объявленных в KNOWN_OBJECTS_RW_REF_OPERATORS_BASE, KNOWN_OBJECTS_RW_PTR_OPERATORS_BASE) // для объектов, для которых при записи и чтении точно известен тип. // \en Implementation of writing functions by non-constant reference/pointer (declared in KNOWN_OBJECTS_RW_REF_OPERATORS_BASE, KNOWN_OBJECTS_RW_PTR_OPERATORS_BASE) // for objects which type is exactly known while reading and writing. //--- #define IMP_KNOWN_OBJECTS_RW_REF_OPERATORS(Class) \ writer & CALL_DECLARATION operator << ( writer & out, Class & ref ) { return operator << ( out, (const Class &)ref ); } #define IMP_KNOWN_OBJECTS_RW_PTR_OPERATORS(Class) \ writer & CALL_DECLARATION operator << ( writer & out, Class * ptr ) { return operator << ( out, (const Class *)ptr ); } //------------------------------------------------------------------------------ // \ru Реализация функций записи по неконстантной ссылке/указателю (объявленных в KNOWN_OBJECTS_RW_REF_OPERATORS_EX_BASE, KNOWN_OBJECTS_RW_PTR_OPERATORS_EX_BASE) // для объектов, для которых при записи и чтении точно известен тип. // \en Implementation of writing functions by non-constant reference/pointer (declared in KNOWN_OBJECTS_RW_REF_OPERATORS_EX_BASE, KNOWN_OBJECTS_RW_PTR_OPERATORS_EX_BASE) // for objects which type is exactly known while reading and writing. //--- #define IMP_KNOWN_OBJECTS_RW_REF_OPERATORS_EX(Class, DLLFUNC) \ DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, Class & ref ) { return operator << ( out, (const Class &)ref ); } #define IMP_KNOWN_OBJECTS_RW_PTR_OPERATORS_EX(Class, DLLFUNC) \ DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, Class * ptr ) { return operator << ( out, (const Class *)ptr ); } //---------------------------------------------------------------------------------------- /** \brief \ru Реализация дружественных операторов чтения и записи указателей и ссылок, объявленных в макросе DECLARE_PERSISTENT_OPS_BASE. \en Implementation of friend operators of reading and writing of pointers and references declared in DECLARE_PERSISTENT_OPS_BASE macro. \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_OPS_BASE( Class, DLLFUNC ) \ DLLFUNC reader & CALL_DECLARATION operator >> ( reader & in, Class & ref ) { \ in.readObject( dynamic_cast(&ref) ); \ return in; \ } \ DLLFUNC reader & CALL_DECLARATION operator >> ( reader & in, Class *& ptr ) { \ ptr = dynamic_cast( in.readObjectPointer() ); \ return in; \ } \ DLLFUNC reader & CALL_DECLARATION operator >> ( reader & in, const Class *& ptr ) \ { \ ptr = dynamic_cast( in.readObjectPointer() ); \ return in; \ } \ DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, const Class & ref ) { \ out.writeObject( dynamic_cast(&ref) ); \ return out; \ } \ DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, const Class * ptr ) { \ out.writeObjectPointer( dynamic_cast(ptr) ); \ return out; \ } \ DLLFUNC writer & CALL_DECLARATION operator << ( writer & out, Class & ref ) { \ out.writeObject( dynamic_cast(&ref) ); \ return out; \ } \ DLLFUNC writer & CALL_DECLARATION operator << ( writer& out, Class * ptr ) { \ out.writeObjectPointer( dynamic_cast(ptr) ); \ return out; \ } //------------------------------------------------------------------------------ /// \ru Функции получения дескриптора (хэш + APP UID) класса. \~ \ingroup Base_Tools_IO /// \ru Реализация макроса DECLARE_CLASS_DESC_FUNC. \en Implementation of DECLARE_CLASS_DESC_FUNC marco. // --- #define IMP_CLASS_DESC_FUNC( AppID, Class ) \ ClassDescriptor Class::GetClassDescriptor( const VersionContainer & v) const \ { return ClassDescriptor( GetPureName(v), AppID ); } //---------------------------------------------------------------------------------------- /** \brief \ru Конструирование нового экземпляра класса. \en Construction of a new instance of the class. \~ \details \ru Конструирование нового экземпляра класса. \n Определяются функция конструирования нового экземпляра класса, функция преобразования от указателя на TapeBase к указателю на класс и класс (не экземпляр!) добавляется в массив потоковых путем создания переменной r ## Class типа TapeClass (а в конструкторе TapeClass производится добавление в массив потоковых классов). Символ ## - это указание препроцессору о необходимости "склейки" текущего идентификатора с последующим. \en Construction of a new instance of the class. \n Definition of functions of construction a new instance of the class, function of conversion from a pointer to TapeBase to a pointer to the class and addition of the class (not an instance) to the array of stream classes by creating variable r ## Class of type TapeClass (and in constructor of TapeClass addition to array of stream classes is performed). Symbol ## is a directive for preprocessor about the necessity of "gluing" of the current identifier with the next one. \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_REGISTRATION( AppID, Class ) \ TapeBase * CALL_DECLARATION make ## _ ## Class () { \ return new Class(tapeInit); \ } \ void * CALL_DECLARATION cast ## _ ## Class ( const TapeBase * obj ) { \ return dynamic_cast(const_cast(obj) ); \ } \ \ TapeClass r ## Class( \ typeid(Class).name(), \ AppID, \ (BUILD_FUNC) make ## _ ## Class, \ (CAST_FUNC ) cast ## _ ## Class, \ (READ_FUNC ) Class::Read, \ (WRITE_FUNC) Class::Write \ ) //------------------------------------------------------------------------------ // \ru Как записать переименованный класс в старую версию (с) Столяров А.Г. \en How to write the renamed class to the old version (c) Stolyarov A.G. /* #define IMP_PERSISTENT_REGISTRATION_OLDCLASS( Class, OldClass ) \ TapeBase * CALL_DECLARATION make ## _ ## Class () { \ return dynamic_cast( new Class(tapeInit) ); \ } \ void * CALL_DECLARATION cast ## _ ## Class ( const TapeBase * obj ) { \ return dynamic_cast(const_cast(obj) ); \ } \ TapeClass r ## Class( \ typeid(Class).name(), \ typeid(OldClass).name(), \ (BUILD_FUNC) make ## _ ## Class, \ (CAST_FUNC ) cast ## _ ## Class, \ (READ_FUNC ) Class::Read, \ (WRITE_FUNC) Class::Write \ ) #define IMP_PERSISTENT_OLDCLASS( Class, OldClass ) \ IMP_PERSISTENT_REGISTRATION_OLDCLASS( Class, OldClass ); \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) IMP_PERSISTENT_OLDCLASS( Class, OldClass ); class TapeClassForNewObjects : public TapeClass { protected : ClassDescriptor hashValueOld; // \ru упакованное имя класса для старой версии файла \en packed class name for the old version of file public : TapeClassForNewObjects( const char * name, const char * oldName, BUILD_FUNC b, CAST_FUNC c, READ_FUNC r, WRITE_FUNC w ); virtual ~TapeClassForNewObjects(); virtual ClassDescriptor GetPackedClassNameForWrite( long version ) const; OBVIOUS_PRIVATE_COPY(TapeClassForNewObjects); }; TapeClassForNewObjects::TapeClassForNewObjects( const char * name, const char * oldName, BUILD_FUNC b, CAST_FUNC c, READ_FUNC r, WRITE_FUNC w ) : TapeClass( name, b, c, r, w ) , hashValueOld( ::hash(::pureName( oldName ) ) ) { } ClassDescriptor TapeClassForNewObjects::GetPackedClassNameForWrite( long version ) const { uint16 res = version > CHANGE_VERSION ? TapeClass::GetPackedClassName() : uint16(hashValueOld); return res; } */ #ifdef __DEBUG_MEMORY_ALLOCATE_FREE_ //-------------------------------------------------------------------------------------- /// \ru Реализация функций new, delete и операторов доступа (объявленных в DECLARE_NEW_DELETE_CLASS). /// \en Implementation of functions new, delete and access operators (declared in DECLARE_NEW_DELETE_CLASS). /// \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) //-------------------------------------------------------------------------------------- /// \ru Реализация операторов new и delete, обеспечивающих последовательное обращение /// к функциям выделения/освобождения памяти из разных потоков (объявленных в DECLARE_NEW_DELETE_CLASS_EX). /// \en Implementation of new and delete operators which provide sequential access /// to the allocation/deallocation functions from different threads (declared in DECLARE_NEW_DELETE_CLASS_EX). \~ /// \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) \ void * Class::operator new( size_t size ) { \ return ::Allocate( size, typeid(Class).name() ); } \ void Class::operator delete ( void *ptr, size_t size ) { \ ::Free( ptr, size, typeid(Class).name() ); } \ \ void * Class::operator new[] ( size_t size ) { \ return ::AllocateArray( size, typeid(Class[]).name()); } \ void Class::operator delete[] ( void *ptr ) { \ ::FreeArray( ptr, typeid(Class[]).name() ); } #else // __DEBUG_MEMORY_ALLOCATE_FREE_ //-------------------------------------------------------------------------------------- /// \ru Реализация функций new, delete и операторов доступа (объявленных в DECLARE_NEW_DELETE_CLASS). /// \en Implementation of functions new, delete and access operators (declared в DECLARE_NEW_DELETE_CLASS). /// \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) #if defined(__OVERLOAD_MEMORY_ALLOCATE_FREE_) && !defined(C3D_DEBUG) //-------------------------------------------------------------------------------------- /// \ru Реализация операторов new и delete, обеспечивающая последовательное обращение /// к функциям выделения/освобождения памяти из разных потоков (объявленных в DECLARE_NEW_DELETE_CLASS_EX). /// Перегружаются все стандартные операторы new и delete. /// \en Implementation of new and delete operators which provides sequential access /// to the allocation/deallocation functions from different threads (declared in DECLARE_NEW_DELETE_CLASS_EX). /// All standard new and delete operators are overloaded. \~ /// \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) \ void* Class::operator new( size_t size ) { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new( size ); } \ void Class::operator delete( void *ptr ) { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete( ptr ); } \ \ void* Class::operator new( size_t size, void *ptr ) { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new( size, ptr ); } \ void Class::operator delete( void *ptr, void *ptr2 ) { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete( ptr, ptr2 ); } \ \ void* Class::operator new[]( size_t size ) { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new[]( size ); } \ void Class::operator delete[]( void *ptr ) { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete[]( ptr ); } \ \ void* Class::operator new []( size_t size, void *ptr ) { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new[]( size, ptr ); } \ void Class::operator delete []( void *ptr, void *ptr2 ) { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete[]( ptr, ptr2 ); } \ \ void* Class::operator new( size_t size, const std::nothrow_t &nt ) throw() { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new( size, nt ); } \ void Class::operator delete( void *ptr, const std::nothrow_t &nt ) throw() { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete( ptr, nt ); } \ \ void* Class::operator new []( size_t size, const std::nothrow_t &nt ) throw() { \ SET_MEMORY_SCOPED_LOCK; \ return ::operator new[]( size, nt ); } \ void Class::operator delete []( void *ptr, const std::nothrow_t &nt ) throw() { \ SET_MEMORY_SCOPED_LOCK; \ ::operator delete[]( ptr, nt ); } #else // __OVERLOAD_MEMORY_ALLOCATE_FREE_ //-------------------------------------------------------------------------------------- /// \ru Реализация операторов new и delete, обеспечивающая последовательное обращение /// к функциям выделения/освобождения памяти из разных потоков (объявленных в DECLARE_NEW_DELETE_CLASS_EX). /// \en Implementation of new and delete operators which provides sequential access /// to the allocation/deallocation functions from different threads (declared in DECLARE_NEW_DELETE_CLASS_EX). \~ /// \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) #endif // __OVERLOAD_MEMORY_ALLOCATE_FREE_ #endif // __DEBUG_MEMORY_ALLOCATE_FREE_ //------------------------------------------------------------------------------ /** \brief \ru Реализация объявления DECLARE_PERSISTENT_CLASS_BASE. \en Implementation of DECLARE_PERSISTENT_CLASS_BASE declaration. \~ \details \ru Реализация объявления DECLARE_PERSISTENT_CLASS_BASE. Описывает необходимые действия для поточного класса. Устанавливается в любой .cpp файл. Class должен наследовать от TapeBase. Должны быть реализованы функции чтения Read и записи Write. \n \en Implementation of DECLARE_PERSISTENT_CLASS_BASE declaration. Describes the necessary operations for a stream class. It is set into any .cpp file. Class must be inherited from TapeBase. Function Read of reading and function Write of writing should be implemented. \n \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS_OPS( AppID, Class, DLLFUNC ) \ IMP_PERSISTENT_REGISTRATION( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ); \ IMP_PERSISTENT_OPS_BASE( Class, DLLFUNC ); \ IMP_CLASS_DESC_FUNC( AppID, Class ) //------------------------------------------------------------------------------ /** \brief \ru Реализация объявления DECLARE_PERSISTENT_CLASS_BASE для абстрактного поточного класса. \en Implementation of DECLARE_PERSISTENT_CLASS_BASE declaration for an abstract stream class. \~ \details \ru Реализация объявления DECLARE_PERSISTENT_CLASS_BASE для абстрактного поточного класса. Описывает необходимые действия для поточного класса. Устанавливается в любой .cpp файл. Class должен наследовать от TapeBase. Должны быть реализованы функции чтения Read и записи Write. \n \en Implementation of DECLARE_PERSISTENT_CLASS_BASE declaration for an abstract stream class. Describes the necessary operations for a stream class. It is set into any .cpp file. Class must be inherited from TapeBase. Function Read of reading and function Write of writing should be implemented. \n \~ \ingroup Base_Tools_IO */ // --- #define IMP_A_PERSISTENT_CLASS_OPS( AppID, Class, DLLFUNC ) \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ); \ IMP_PERSISTENT_OPS_BASE( Class, DLLFUNC ); \ IMP_CLASS_DESC_FUNC( AppID, Class ) //------------------------------------------------------------------------------ /** \brief \ru Реализация объявления DECLARE_PERSISTENT_CLASS_NEW_DEL_BASE. \en Implementation of DECLARE_PERSISTENT_CLASS_NEW_DEL_BASE declaration. \~ \details \ru Реализация объявления DECLARE_PERSISTENT_CLASS_NEW_DEL_BASE. Описывает необходимые действия для поточного класса. Устанавливается в любой .cpp файл. Class должен наследовать от TapeBase. Должны быть реализованы функции чтения Read и записи Write. \n \en Implementation of DECLARE_PERSISTENT_CLASS_NEW_DEL_BASE declaration. Describes the necessary operations for a stream class. It is set into any .cpp file. Class must be inherited from TapeBase. Function Read of reading and function Write of writing should be implemented. \n \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS_NEW_DEL_OPS( AppID, Class, DLLFUNC ) \ IMP_PERSISTENT_CLASS_OPS( AppID, Class, DLLFUNC ); \ IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ); //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции для абстрактного поточного класса, \en Describes the necessary operations for the abstract stream class // \ru не наследующего ни от кого кроме TapeBase, и у которого \en which is not inherited from any class except TapeBase and which // \ru нет своих полей данных для записи в поток \en has no its own data fields for writing to stream // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется (!!!) отсутствие (!!!) функций \en 2. The following functions must be (!!!) absent (!!!) // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // --- #define IMP_A_PERSISTENT_CLASS_WD( AppID, Class ) \ void Class::Read( reader &, Class * ) {} \ void Class::Write( writer &, const Class * ) {} \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) \ IMP_CLASS_DESC_FUNC( AppID, Class ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции для абстрактного поточного класса с проверкой главной версии потока (версии математического ядра), // \en Describes the necessary operations for the abstract stream class with check of the main stream version (the mathenatical kernel version), // \ru не наследующего ни от кого кроме TapeBase, и у которого \en which is not inherited from any class except TapeBase and which // \ru нет своих полей данных для записи в поток. \en has no its own data fields for writing to stream. // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется (!!!) отсутствие (!!!) функций \en 2. The following functions must be (!!!) absent (!!!) // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // --- #define IMP_A_PERSISTENT_MATH_CLASS_WD( AppID, Class ) \ void Class::Read( reader &, Class * ) {} \ void Class::Write( writer & out, const Class * ) \ { if ( out.MathVersion() < wrv_FirstRelease ) out.setState( io::cantWriteObject ); } \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) \ IMP_CLASS_DESC_FUNC( AppID, Class ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции для абстрактного \en Describes the necessary operations for abstract // \ru поточного класса \en stream class // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется наличие функций \en 2. There must be the following functions // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // --- #define IMP_A_PERSISTENT_CLASS( AppID, Class ) \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) \ IMP_CLASS_DESC_FUNC( AppID, Class ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции абстрактного поточного класса, \en Describes the necessary operations for the abstract stream class // \ru наследующего от другого такого же, и у которого \en inherited from another class which is the same and which // \ru нет своих полей данных для записи в поток \en has no its own data fields for writing to stream // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется (!!!) отсутствие (!!!) функций \en 2. The following functions must be (!!!) absent (!!!) // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // \ru эти функции генерируются автоматически \en these functions are generated automatically // --- #define IMP_A_PERSISTENT_CLASS_FROM_BASE( AppID, Class, Base ) \ void Class::Read( reader & in, Class * obj ) { \ Base::Read( in, obj ); \ } \ void Class::Write( writer & out, const Class * obj ) { \ Base::Write( out, obj ); \ } \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) \ IMP_CLASS_DESC_FUNC( AppID, Class ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции поточного класса, \en Describes the necessary operations of the stream class // \ru наследующего от другого такого же, и у которого \en inherited from another class which is the same and which // \ru нет своих полей данных для записи в поток \en has no its own data fields for writing to stream // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется (!!!) отсутствие (!!!) функций \en 2. The following functions must be (!!!) absent (!!!) // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // \ru эти функции генерируются автоматически \en these functions are generated automatically // --- #define IMP_PERSISTENT_CLASS_FROM_BASE( AppID, Class, Base ) \ IMP_PERSISTENT_REGISTRATION( AppID, Class ); \ IMP_A_PERSISTENT_CLASS_FROM_BASE( AppID, Class, Base ) //------------------------------------------------------------------------------ /** \brief \ru Аналог макроса IMP_PERSISTENT_CLASS_FROM_BASE с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков. \en Analog of IMP_PERSISTENT_CLASS_FROM_BASE macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads. \~ \details \ru Аналог макроса IMP_PERSISTENT_CLASS_FROM_BASE с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков (включается переменной __OVERLOAD_MEMORY_ALLOCATE_FREE_). \en Analog of IMP_PERSISTENT_CLASS_FROM_BASE macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads (enabled by defining __OVERLOAD_MEMORY_ALLOCATE_FREE_). \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS_FROM_BASE_NEW_DEL( AppID, Class, Base ) \ IMP_PERSISTENT_CLASS_FROM_BASE( AppID, Class, Base ) \ IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые операции для поточного класса, \en Describes the necessary operations for the stream class // \ru не наследующего ни от кого кроме TapeBase, и у которого \en which is not inherited from any class except TapeBase and which // \ru нет своих полей данных для записи в поток \en has no its own data fields for writing to stream // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется (!!!) отсутствие (!!!) функций \en 2. The following functions must be (!!!) absent (!!!) // - void Class::Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // --- #define IMP_PERSISTENT_CLASS_WD( AppID, Class ) \ IMP_PERSISTENT_REGISTRATION( AppID, Class ); \ void Class::Read( reader &, Class * ) {} \ void Class::Write( writer &, const Class * ) {} \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) \ IMP_CLASS_DESC_FUNC( AppID, Class ) //---------------------------------------------------------------------------------------- /** \brief \ru Аналог макроса IMP_PERSISTENT_CLASS_WD с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков. \en Analog of IMP_PERSISTENT_CLASS_WD macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads. \~ \details \ru Аналог макроса IMP_PERSISTENT_CLASS_WD с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков (включается переменной __OVERLOAD_MEMORY_ALLOCATE_FREE_). \en Analog of IMP_PERSISTENT_CLASS_WD macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads (enabled by defining __OVERLOAD_MEMORY_ALLOCATE_FREE_). \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS_WD_NEW_DEL( AppID, Class ) \ IMP_PERSISTENT_CLASS_WD( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) //------------------------------------------------------------------------------ /** \brief \ru Реализация объявления DECLARE_PERSISTENT_CLASS. \en Implementation of DECLARE_PERSISTENT_CLASS declaration. \~ \details \ru Реализация объявления DECLARE_PERSISTENT_CLASS. Описывает необходимые действия для поточного класса. Устанавливается в любой .cpp файл. Class должен наследовать от TapeBase. Должны быть реализованы функции чтения Read и записи Write. \n \en Implementation of DECLARE_PERSISTENT_CLASS declaration. Describes the necessary operations for a stream class. It is set into any .cpp file. Class must be inherited from TapeBase. Function Read of reading and function Write of writing should be implemented. \n \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS( AppID, Class ) \ IMP_PERSISTENT_REGISTRATION( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ); \ IMP_CLASS_DESC_FUNC( AppID, Class ) /** \brief \ru Аналог макроса IMP_PERSISTENT_CLASS с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков. \en Analog of IMP_PERSISTENT_CLASS macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads. \~ \details \ru Аналог макроса IMP_PERSISTENT_CLASS с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков (включается переменной __OVERLOAD_MEMORY_ALLOCATE_FREE_). \en Analog of IMP_PERSISTENT_CLASS macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads (enabled by defining __OVERLOAD_MEMORY_ALLOCATE_FREE_). \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_CLASS_NEW_DEL( AppID, Class ) \ IMP_PERSISTENT_CLASS( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ); //---------------------------------------------------------------------------------------- /// \ru Конструирование нового экземпляра класса для класса без записи. \en Construction of a new instance of the class for a class without writing. \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_RO_REGISTRATION( AppID, Class ) \ TapeBase * CALL_DECLARATION make ## _ ## Class () { \ return new Class(tapeInit); \ } \ void * CALL_DECLARATION cast ## _ ## Class ( const TapeBase * obj ) { \ return dynamic_cast(const_cast(obj) ); \ } \ TapeClass r ## Class( \ typeid(Class).name(), \ AppID, \ (BUILD_FUNC) make ## _ ## Class, \ (CAST_FUNC ) cast ## _ ## Class, \ (READ_FUNC ) Class::Read, \ (WRITE_FUNC) 0 \ ) //---------------------------------------------------------------------------------------- // \ru Описывает необходимые действия для поточного класса без записи \en Describes the necessary operations for a stream class without writing. // \ru Устанавливается в любой .cpp файл \en It is set to any .cpp file // \ru Примечание : \en Note: // \ru 1. Class должен наследовать от TapeBase \en 1. Class must be inherited from TapeBase // \ru 2. Требуется наличие функций \en 2. There must be the following functions // - void Class:Read( reader& in, Class* obj ); // - void Class::Write( writer& out, const Class* obj ); // \ru где Class - имя класса \en where Class is a class name // --- #define IMP_PERSISTENT_RO_CLASS( AppID, Class ) \ IMP_PERSISTENT_RO_REGISTRATION( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS( Class ) //------------------------------------------------------------------------------ /** \brief \ru Аналог макроса IMP_PERSISTENT_RO_CLASS с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков. \en Analog of IMP_PERSISTENT_RO_CLASS macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads. \~ \details \ru Аналог макроса IMP_PERSISTENT_RO_CLASS с возможностью перегрузки операторов new/delete, обеспечивающий последовательное обращение к функциям выделения/освобождения памяти из разных потоков (включается переменной __OVERLOAD_MEMORY_ALLOCATE_FREE_). \en Analog of IMP_PERSISTENT_RO_CLASS macro with support of new/delete operators overloading which provides sequential access to the allocation/deallocation functions from different threads (enabled by defining __OVERLOAD_MEMORY_ALLOCATE_FREE_). \~ \ingroup Base_Tools_IO */ // --- #define IMP_PERSISTENT_RO_CLASS_NEW_DEL( AppID, Class ) \ IMP_PERSISTENT_RO_CLASS( AppID, Class ); \ IMP_PERSISTENT_NEW_DELETE_CLASS_EX( Class ) /** \brief \ru Объявление операторов чтения и записи указателей и ссылок. \en Declaration of operators of reading and writing of pointers and references. \~ \deprecated \ingroup Base_Tools_IO */ // --- #define DECLARE_PERSISTENT_OPS_B( Class ) \ friend inline reader & CALL_DECLARATION operator >> ( reader & in, Class & ref ); \ friend inline reader & CALL_DECLARATION operator >> ( reader & in, Class *& ptr ); \ friend inline reader & CALL_DECLARATION operator >> ( reader & in, const Class *& ptr ); \ friend inline writer & CALL_DECLARATION operator << ( writer & out, const Class & ref ); \ friend inline writer & CALL_DECLARATION operator << ( writer & out, const Class * ptr ); \ friend inline writer & CALL_DECLARATION operator << ( writer & out, Class & ref ); \ friend inline writer & CALL_DECLARATION operator << ( writer& out, Class * ptr ); //---------------------------------------------------------------------------------------- /** \brief \ru Операторы чтения указателей и ссылок для класса без записи. \en Operators of reading pointers and references for a class without writing. \~ \deprecated \ingroup Base_Tools_IO */ // --- #define DECLARE_PERSISTENT_RO_OPS( Class ) \ friend inline reader & CALL_DECLARATION operator >> ( reader & in, Class & ref ) { \ in.readObject( dynamic_cast(&ref) ); \ return in; \ } \ friend inline reader & CALL_DECLARATION operator >> ( reader & in, Class *& ptr ) { \ ptr = dynamic_cast( in.readObjectPointer() ); \ return in; \ } //---------------------------------------------------------------------------------------- /// \ru Функции чтения для класса без записи. \en Function of reading for class without writing. \~ \ingroup Base_Tools_IO /// \deprecated // --- #define DECLARE_PERSISTENT_RO_FUNCS( Class ) \ public: \ static void Read( reader & in, Class * obj ) //---------------------------------------------------------------------------------------- /// \ru Конструктор для потокового класса. \en Constructor for a stream class. \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_CTOR( Class ) \ Class::Class( TapeInit ) {} //---------------------------------------------------------------------------------------- /// \ru Конструктор для класса с одной потоковой базой. \en Constructor for a class with one stream base. \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_CTOR1( Class, Base ) \ Class::Class( TapeInit ) : Base( tapeInit ) {} //---------------------------------------------------------------------------------------- /// \ru Конструктор для класса с двумя потоковыми базами. \en Constructor for a class with two stream bases. \~ \ingroup Base_Tools_IO // --- #define IMP_PERSISTENT_CTOR2( Class, Base1, Base2 ) \ Class::Class( TapeInit ) : Base1( tapeInit ), Base2( tapeInit ) {} #endif // __IO_TAPE_H